{"id":21048277,"url":"https://github.com/angelbarrera92/do-k8s-challenge","last_synced_at":"2025-10-11T04:08:02.952Z","repository":{"id":144305459,"uuid":"441838221","full_name":"angelbarrera92/do-k8s-challenge","owner":"angelbarrera92","description":"Angel Barrera @ Digital Ocean Kubernetes Challenge","archived":false,"fork":false,"pushed_at":"2022-01-10T08:19:47.000Z","size":3312,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-11T04:08:01.280Z","etag":null,"topics":["kubernetes","registry","s3","spaces","tunnels"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/angelbarrera92.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-26T07:55:07.000Z","updated_at":"2023-03-05T06:32:18.000Z","dependencies_parsed_at":"2024-08-24T07:30:38.976Z","dependency_job_id":null,"html_url":"https://github.com/angelbarrera92/do-k8s-challenge","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/angelbarrera92/do-k8s-challenge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angelbarrera92%2Fdo-k8s-challenge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angelbarrera92%2Fdo-k8s-challenge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angelbarrera92%2Fdo-k8s-challenge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angelbarrera92%2Fdo-k8s-challenge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/angelbarrera92","download_url":"https://codeload.github.com/angelbarrera92/do-k8s-challenge/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angelbarrera92%2Fdo-k8s-challenge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279006257,"owners_count":26084060,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kubernetes","registry","s3","spaces","tunnels"],"created_at":"2024-11-19T14:42:56.881Z","updated_at":"2025-10-11T04:08:02.936Z","avatar_url":"https://github.com/angelbarrera92.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Digital Ocean Kubernetes Challenge\n\n## Goal\n\nDeploy a Kubernetes Cluster on Digital Ocean, deploy a Docker Registry using Digital Ocean Object storage as storage backend,\nthen expose it without using a Load Balancer; using a subproject borned from this challenge: [k8s-tunnel-controller](https://github.com/angelbarrera92/k8s-tunnel-controller/)\n\n## Hands on!\n\n### Create a Kubernetes Cluster\n\nNavigate to your [Digital Ocean account](https://cloud.digitalocean.com).\n\n![Login](images/DO-login.png)\n\nThen, navigate to the [Kubernetes page](https://cloud.digitalocean.com/kubernetes).):\n\n![Kubernetes](images/DO-K8S.png)\n\nAnd create a new cluster making sure to select:\n- At least two node in the default node pool.\n- The basic node plan.\n\n![Kubernetes Configuration](images/DO-K8S-config.png)\n\n**NOTE:** *(It will cost around 20$ per month)*\n\nWait a few minutes to be able to access the cluster. It can take up to five minutes to be ready.\n\n![Kubernetes Cluster](images/DO-cluster.png)\n\nThen, download the Kube config file, and save it in your home directory: `~/.kube/config`.\n\n```bash\n$ mv ~/Downloads/k8s-1-21-5-do-0-ams3-1640502039921-kubeconfig.yaml ~/.kube/config\n```\n\nCheck the cluster status:\n\n```bash\n$ kubectl get nodes\nNAME                   STATUS   ROLES    AGE     VERSION\npool-pzl0cpssp-u63sf   Ready    \u003cnone\u003e   5m27s   v1.21.5\npool-pzl0cpssp-u63sq   Ready    \u003cnone\u003e   5m27s   v1.21.5\n```\n\n### Create the required bucket and credentials\n\nIn order to provide distributed and fault tolerant storage, Digital Ocean provides a service called Spaces *(S3 compatible)*.\nThe registry will use Spaces to store the container images.\n\nNavigate to the Spaces page:\n\n![Spaces](images/DO-spaces.png)\n\nThen, create a new bucket:\n\n![Spaces Bucket](images/DO-space-config.png)\n\nIt is important to select the same region as the cluster, it will increase the performance/latency of the storage.\n\nFinally, create a set of API keys for the bucket navigating to the API page:\n\n![DO API](images/DO-keys.png)\n\nThen create a new key:\n\n![DO API Key](images/DO-space-keys.png)\n\n**NOTE:** *Credentials in the screenshot are not longer valid, just for your information.*\n\n### Deploy the K8S-tunnel-controller\n\n[K8S-tunnel-controller](https://github.com/angelbarrera92/k8s-tunnel-controller) is a subproject borned from this challenge.\nIt allows to expose a Kubernetes internal service to internet with automatic TLS, custom DNS, and\nwithout exposing any node of the cluster to internet.\n\nIn order to deploy it, the easiest way is to use the `kubectl` command with the following URL.\n\n```bash\n$ kubectl apply -f https://raw.githubusercontent.com/angelbarrera92/k8s-tunnel-controller/v0.1.0/deployments/kubernetes/manifests/deploy.yaml\nserviceaccount/tunnels-k8s-tunnel-controller created\nclusterrole.rbac.authorization.k8s.io/tunnels-k8s-tunnel-controller created\nclusterrolebinding.rbac.authorization.k8s.io/tunnels-k8s-tunnel-controller created\nservice/tunnels-k8s-tunnel-controller created\ndeployment.apps/tunnels-k8s-tunnel-controller created\npod/tunnels-k8s-tunnel-controller-test-connection created\n```\n\nAfter a while, you will see the following output:\n\n```bash\n$ kubectl get pods\nNAME                                             READY   STATUS    RESTARTS   AGE\ntunnels-k8s-tunnel-controller-846f94c6c9-s7s2r   1/1     Running   0          3m46s\ntunnels-k8s-tunnel-controller-test-connection    0/1     Error     0          3m46s\n```\n\n\u003e Don't worry about the `test-connection` pod, it will be automatically deleted after a while.\n\n### Prepare the registry configuration\n\nCreate a configuration file for the registry from [this template](config-template.yml)\n```yaml\n---\nversion: 0.1\nlog:\n  level: debug\n  formatter: text\n  fields:\n    service: registry\nloglevel: debug\nstorage:\n  redirect:\n    disable: true\n  s3:\n    accesskey: \u003cYOUR_ACCESS_KEY\u003e\n    secretkey: \u003cYOUR_SECRET_KEY\u003e\n    region: \u003cYOUR_REGION\u003e\n    regionendpoint: \u003cYOUR_REGION_ENDPOINT\u003e\n    bucket: \u003cYOUR_BUCKET\u003e\nhttp:\n  addr: :5000\n  # cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1\n  secret: \u003cRANDOM_SECRET_GOES_HERE\u003e\n  headers:\n    X-Content-Type-Options: [nosniff]\n  http2:\n    disabled: false\n  host: https://\u003cYOUR_TUNNEL\u003e.tunnels.o.barrera.dev\nauth:\n  htpasswd:\n    realm: basic-realm\n    path: /auth/htpasswd\n```\n\nIt contains the following configuration:\n\n- `YOUR_ACCESS_KEY`: The access key for the bucket.\n- `YOUR_SECRET_KEY`: The secret key for the bucket.\n- `YOUR_REGION`: The region of the bucket.\n- `YOUR_REGION_ENDPOINT`: The region endpoint of the bucket.\n- `YOUR_BUCKET`: The bucket name.\n- `RANDOM_SECRET_GOES_HERE`: A random secret to be used for the endpoint.\n  - Feel free to use `cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1` command to generate it.\n- `YOUR_TUNNEL`: The name of the tunnel.\n\nThen, create a secret for the registry. It will be used to authenticate the registry.\nThe secret will be created with the following command:\n\n```bash\n$ kubectl create namespace registry\nnamespace/registry created\n$ kubectl create secret generic -n registry registry-auth --from-literal=username=\u003cREGISTRY_USERNAME\u003e --from-literal=password=\u003cREGISTRY_PASSWORD\u003e --dry-run -o yaml | kubectl apply -f -\nW1226 10:18:23.382124   70151 helpers.go:557] --dry-run is deprecated and can be replaced with --dry-run=client.\nsecret/registry-auth created\n```\n\nIt contains the following configuration:\n\n- `REGISTRY_USERNAME`: The username for the registry.\n- `REGISTRY_PASSWORD`: The password for the registry.\n\n\nOnce you have in place all the configuration, you can deploy the registry.\n\n### Deploy the registry\n\n```bash\n$ kubectl create secret generic registry -n registry --from-file=config.yml=config.yml --dry-run -o yaml | kubectl apply -f -\nW1226 09:04:15.766940  166192 helpers.go:557] --dry-run is deprecated and can be replaced with --dry-run=client.\nsecret/registry created\n$ kubectl apply -f registry.yaml\ndaemonset.apps/registry created\nservice/registry created\n$ kubectl get pods -n registry\nNAME             READY   STATUS    RESTARTS   AGE\nregistry-d4mkj   1/1     Running   0          5s\nregistry-lt68f   1/1     Running   0          5s\n```\n\n### Expose the registry\n\nThen annotate your registry service to expose it to the internet using the `\u003cYOUR_TUNNEL\u003e` name. In this case: `registry-do-challeng`.\n\n```bash\n$ kubectl annotate service registry -n registry k8s-tunnel-controller/tunnel=registry-do-challenge\nservice/registry annotated\n$ kubectl get pods -n registry\nNAME                         READY   STATUS    RESTARTS   AGE\nregistry-5000-tunnel-vylzl   1/1     Running   0          5s\nregistry-d4mkj               1/1     Running   0          2m10s\nregistry-lt68f               1/1     Running   0          2m10s\n```\n\nCheck tunnel logs:\n\n```bash\n$ kubectl logs registry-5000-tunnel-vylzl -n registry\n2021/12/26 08:46:19 config server_addr: tunnels.o.barrera.dev:5223\ntls_crt: /certs/client.crt\ntls_key: /certs/client.key\nroot_ca: \"\"\nbackoff:\n  interval: 500ms\n  multiplier: 1.5\n  max_interval: 1m0s\n  max_time: 15m0s\ntunnels:\n  registry:\n    proto: http\n    addr: http://registry:5000\n    host: registry-do-challenge.tunnels.o.barrera.dev\n\n2021/12/26 08:46:19 level 1 action start\n2021/12/26 08:46:19 level 1 action dial network tcp addr tunnels.o.barrera.dev:5223\n2021/12/26 08:46:19 level 1 action handshake addr 129.159.204.185:5223\n```\n\n**Note:** Ensure the `tunnels.registry.host` value shown above is the same as the `http.host` value in the `config.yml` file. Otherwise, the registry will not work.\n\n### Test the registry\n\nLet's test the registry. First, download a container image from [Docker Hub](https://hub.docker.com/).\n\n```bash\n$ docker pull registry:2\n2: Pulling from library/registry\n79e9f2f55bf5: Pull complete\n0d96da54f60b: Pull complete\n5b27040df4a2: Pull complete\ne2ead8259a04: Pull complete\n3790aef225b9: Pull complete\nDigest: sha256:169211e20e2f2d5d115674681eb79d21a217b296b43374b8e39f97fcf866b375\nStatus: Downloaded newer image for registry:2\ndocker.io/library/registry:2\n```\n\nThen, tag the image with your tunnel hostname. In this case: `registry-do-challenge.tunnels.o.barrera.dev`:\n\n```bash\n$ docker tag registry:2 registry-do-challenge.tunnels.o.barrera.dev/registry:2\n```\n\nThen, login to the registry.\n\n```bash\n$ docker login registry-do-challenge.tunnels.o.barrera.dev -u \u003cREGISTRY_USERNAME\u003e -p \u003cREGISTRY_PASSWORD\u003e\nWARNING! Using --password via the CLI is insecure. Use --password-stdin.\nWARNING! Your password will be stored unencrypted in /home/angel/.docker/config.json.\nConfigure a credential helper to remove this warning. See\nhttps://docs.docker.com/engine/reference/commandline/login/#credentials-store\n\nLogin Succeeded\n```\n\nFinally push the image to the registry.\n\n```bash\n$ docker push registry-do-challenge.tunnels.o.barrera.dev/registry:2\nThe push refers to repository [registry-do-challenge.tunnels.o.barrera.dev/registry]\naeccf26589a7: Pushed\nf640be0d5aad: Pushed\naa4330046b37: Pushed\nad10b481abe7: Pushed\n69715584ec78: Pushed\n2: digest: sha256:36cb5b157911061fb610d8884dc09e0b0300a767a350563cbfd88b4b85324ce4 size: 1363\n```\n\n## Important notes\n\n**Clean up the environment** following this guide in reverse order.\n\n- Delete the Space Keys\n- Delete the Space bucket\n- Delete the Kubernetes Cluster\n\nThis registry deployment if not ready to be used in the enterprises/production environment.\nTake in mind the authentication method **is not secure and should be used only for testing purposes.**\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangelbarrera92%2Fdo-k8s-challenge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fangelbarrera92%2Fdo-k8s-challenge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangelbarrera92%2Fdo-k8s-challenge/lists"}