{"id":15064685,"url":"https://github.com/hangrybear666/10-devops-bootcamp__kubernetes","last_synced_at":"2026-01-02T08:15:48.518Z","repository":{"id":254553579,"uuid":"846889887","full_name":"hangrybear666/10-devops-bootcamp__kubernetes","owner":"hangrybear666","description":"K8s manifests, Helmcharts and kubectl scripts for Deployments, StatefulSets, ConfigMaps, Secrets, PVCs, Services, Ingress to deploy web-app/db stacks \u0026 microservices on Linode Managed K8s Engine.","archived":false,"fork":false,"pushed_at":"2024-10-07T21:01:47.000Z","size":6174,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-22T10:14:32.257Z","etag":null,"topics":["argocd","helm-charts","kubectl","kubernetes","microservices","nginx","replicated-database"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hangrybear666.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":"2024-08-24T08:34:42.000Z","updated_at":"2024-10-07T21:01:50.000Z","dependencies_parsed_at":"2024-09-07T13:30:52.039Z","dependency_job_id":"da74c97e-b0f6-4cbf-9036-42d7557f940c","html_url":"https://github.com/hangrybear666/10-devops-bootcamp__kubernetes","commit_stats":null,"previous_names":["hangrybear666/10-devops-bootcamp__kubernetes"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hangrybear666%2F10-devops-bootcamp__kubernetes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hangrybear666%2F10-devops-bootcamp__kubernetes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hangrybear666%2F10-devops-bootcamp__kubernetes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hangrybear666%2F10-devops-bootcamp__kubernetes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hangrybear666","download_url":"https://codeload.github.com/hangrybear666/10-devops-bootcamp__kubernetes/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243790999,"owners_count":20348385,"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","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":["argocd","helm-charts","kubectl","kubernetes","microservices","nginx","replicated-database"],"created_at":"2024-09-25T00:24:51.928Z","updated_at":"2026-01-02T08:15:48.486Z","avatar_url":"https://github.com/hangrybear666.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kubernetes manifests, helm charts, helmfiles and kubectl shell scripts to provision resources in managed Linode Kubernetes Engine\n\nKubernetes manifests, Helmcharts and kubectl scripts for Deployments, ConfigMaps, Secrets, PVCs, StatefulSets, internal \u0026 external Services, Ingress to deploy simple web-apps, or more complex microservices on the Linode Managed Kubernetes Engine.\n\n\u003cb\u003e\u003cu\u003eThe advanced exercise projects are:\u003c/u\u003e\u003c/b\u003e\n1. Write \u0026 Read (asynchronous row-based) replicated MySQL StatefulSet \u0026 PVC Block Storage with replicated SpringBoot Java \u0026 phpmyadmin Deployment, accessed via Ingress nginx-controller - \u003cb\u003estarted manually via kubectl apply commands\u003c/b\u003e\n2. Write \u0026 Read (asynchronous row-based) replicated MySQL StatefulSet \u0026 PVC Block Storage with replicated SpringBoot Java \u0026 phpmyadmin Deployment, accessed via Ingress nginx-controller - \u003cb\u003estarted via shell script running helm charts\u003c/b\u003e\n\n\u003cb\u003e\u003cu\u003eThe basic course examples are:\u003c/u\u003e\u003c/b\u003e\n1. A simple app with ConfigMap, locally generated Secret to avoid SCM exposure and external LoadBalancer Service in k8s cluster\n2. A simple app with ConfigMap File and Secret File Volume Mounting for initializing containers with custom files\n3. Managed k8s cluster on Linode running a replicated StatefulSet application with multiple nodes and attached persistent storage volumes using Helm Charts\n4. Deployment of a custom NodeJS-application image published and pulled from AWS ECR, with mongodb and mongo-express pods \u0026 services running\n5. Deployment of 11 replicated microservices with best-practice configuration via single k8s.yaml file\n6. Deployment of 11 replicated microservices with several helm install commands bundled in a bash script\n7. Deployment of 11 replicated microservices with single helmfile apply command\n\n\u003cb\u003e\u003cu\u003eThe bonus projects are:\u003c/u\u003e\u003c/b\u003e\n1. An ArgoCD deployment in Kubernetes following GitOps principles for declarative configuration versioning and storage.\n2. An nginx reverse proxy to route external traffic into a remote linux VPS to an ingress-nginx-controller which forwards the requests to an internal service\n\n## Setup\n\n### 1. Pull SCM\n\nPull the repository locally by running\n```\ngit clone https://github.com/hangrybear666/10-devops-bootcamp__kubernetes.git\n```\n### 2. Install Minikube on your local OS (or in our case a remote VPS)\n\nFor local development simply follow https://minikube.sigs.k8s.io/docs/start/.\n\nThe following steps execute automatic installation on remote debian based VPS:\n\na. Add `SERVICE_USER_PW=xxx` to your `.env` file so the installation script can add this to the new user. Overwrite`REMOTE_ADDRESS=xxx` to yours in `config/remote.properties`\n\nb. Run the installation script in `scripts/` folder and type `y` if you wish to install docker before installaing minikube and `n` if docker is already installed.\n```bash\n# this is aimed at Debian-like distros with the apt package manager\n./remote-install-minikube.sh\n# If you want to remove docker and/or minikube run\n./remote-uninstall-minikube.sh\n```\n\n### 3. Install additional dependencies\n\nInstall `jq` to parse json files. Install `openssl` to generate random passwords for environment vars.\n\n### 4. Install helm on your local OS\n\nSee https://helm.sh/docs/intro/install/\n```bash\ncurl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash\n```\n\n### 5. Install helmfile on your local OS and run helmfile init to install plugins\n\nFind the binary link for your OS at https://github.com/helmfile/helmfile/releases\n```bash\ncurl -LO https://github.com/helmfile/helmfile/releases/download/v1.0.0-rc.4/helmfile_1.0.0-rc.4_linux_386.tar.gz\ntar -xzf helmfile_1.0.0-rc.4_linux_386.tar.gz --wildcards '*helmfile'\nsudo chmod +x helmfile\nsudo mv helmfile /usr/bin/helmfile\nhelmfile init\n# install plugins by agreeing with \"y\"\n```\n\n## Usage (Exercises)\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e0. Test your java / mysql / phpmyadmin application locally with docker-compose \u003c/b\u003e\u003c/summary\u003e\n\n#### a. Create `.env` file in `java-app/` folder by running the following script, generating random passwords via openssl for you.\n```bash\ncd scripts\n./create-exercise-env-vars.sh\n```\n\n#### b. Add local dns name forwarding to your /etc/hosts file by adding the following entry: `127.0.0.1 my-java-app.com`\n\n#### c. Navigate to `java-app/` and run\n```bash\nVERSION_TAG=1.0 \\\nDB_SERVER_OVERRIDE=mysqldb \\\ndocker compose -f docker-compose-java-app-mysql.yaml up\n```\n\n#### d. Navigate to http://localhost:8085/ for phpmyadmin using `DB_USER` and `DB_PWD` for login.\nThen navigate to http://my-java-app.com/ for your java app.\n\u003c/details\u003e\n\n-----\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e1. Write \u0026 Read (asynchronous row-based) replicated MySQL StatefulSet \u0026 PVC Block Storage with replicated SpringBoot Java \u0026 phpmyadmin Deployment, accessed via Ingress nginx-controller - started manually via kubectl apply commands\u003c/b\u003e\u003c/summary\u003e\n\n#### a. Create an Account on the Linode Cloud\n\nThen Create a Kubernetes Cluster https://cloud.linode.com/kubernetes/clusters named `test-cluster` in your Region without High Availability (HA) Control Plane to save costs. Adding 3 Nodes with 2GB each on a shared CPU is sufficient.\n\n#### b. Once the cluster is running, download `test-cluster-kubeconfig.yaml`. If your file is named differently, add it to `.gitignore` as it contains sensitive data.\n\n#### c. Create an Elastic Container Registry (ECR) on AWS for your k8s images to live.\n\nThen retrieve the push commands in aws console and run the docker login command locally to properly setup `/home/$USER/.docker/config.json`. Replace the remote url with your own and then copy the config file to your `config/` folder. It is added to .gitignore, so don't rename it.\n```bash\n# setup docker registry credentials\naws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin 010928217051.dkr.ecr.eu-central-1.amazonaws.com\ncp /home/$USER/.docker/config.json config/\n```\n\n#### d. Create secret from prior docker login step so kubernetes can pull the AWS ECR image\n```bash\nexport KUBECONFIG=test-cluster-kubeconfig.yaml\nkubectl create namespace exercises\nkubectl create secret generic aws-ecr-config \\\n--from-file=.dockerconfigjson=config/config.json \\\n--type=kubernetes.io/dockerconfigjson \\\n--namespace exercises\n# check if secret looks correct\nkubectl get secret aws-ecr-config -n exercises --output=\"jsonpath={.data.\\.dockerconfigjson}\" | base64 --decode\n```\n\n#### e. Create Secret from `java-app/.env` file created by the `./create-exercise-env-vars.sh` script in exercise step 0)\n```bash\nkubectl create secret generic java-app-mysql-env \\\n--from-env-file=java-app/.env \\\n--namespace exercises\n# check if secret looks correct\nkubectl get secret java-app-mysql-env -n exercises -o yaml\n\n```\n\n#### f. Add nginx-ingress-controller to route incoming traffic from Linode's NodeBalancer to the phpmyadmin \u0026 java-app internal ClusterIP Service.\n\nInstallation of the Helm chart also automatically sets up a NodeBalancer on Linode, the public dns name of which we have to save and replace in `k8s/exercises/01-ingress-configuration.yaml` in the `- host: ` value\n```bash\nhelm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx\nhelm repo update\nhelm install nginx-ingress ingress-nginx/ingress-nginx --version 4.11.2 --namespace exercises\n```\n\n#### g. Before building and pushing the docker image to remote, change the HOST variable in line 48 of your `java-app/src/main/resources/static/index.html` to your Linode NodeBalancer DNS Name, for example:\n```js\nconst HOST = \"172-xxx-xxx-124.ip.linodeusercontent.com\";\n```\n\n#### h. Build and Push your java application image to AWS ECR remote repository. Replace the repo url with your own. Current Directory should be the git repo root dir.\n```bash\ndocker build -t java-app:2.3 java-app/.\ndocker tag java-app:2.3 010928217051.dkr.ecr.eu-central-1.amazonaws.com/k8s-imgs:java-app-2.3\ndocker push 010928217051.dkr.ecr.eu-central-1.amazonaws.com/k8s-imgs:java-app-2.3\n```\n\n#### i. To start mysql StatefulSet (replicas:2), attached to 10GB each of persistent linode block storage volume\n\nLaunch the java application (replicas:2) and start phpmyadmin UI, with an ingress-nginx controller for external access, replace the following values and then run the script.\n\n*NOTE: replace image name in `k8s/exercises/01-java-app-deployment.yaml` with your own*\n\n*NOTE: replace hostname in `k8s/exercises/01-ingress-configuration.yaml` with your Linode NodeBalancer dns name in \u003cb\u003eboth\u003c/b\u003e Ingress resources*\n\n*NOTE: replace pma-absolute-uri in `k8s/exercises/01-phpmyadmin-configmap.yaml` with your own but it \u003cb\u003ehas\u003c/b\u003e to end with `/phpmyadmin/` or the Ingress Regex Path Redirect won't work*\n\n```bash\nkubectl apply -f k8s/exercises/01-mysql-configmap.yaml\nkubectl apply -f k8s/exercises/01-mysql-service.yaml\nkubectl apply -f k8s/exercises/01-mysql-statefulset.yaml\n# change java image name to your own remote ecr img\nkubectl apply -f k8s/exercises/01-java-app-deployment.yaml\n# replace Linode NodeBalancer hostname in pma-absolute-uri\nkubectl apply -f k8s/exercises/01-phpmyadmin-configmap.yaml\nkubectl apply -f k8s/exercises/01-phpmyadmin-deployment.yaml\n# add Linode NodeBalancer hostname to both Ingress resources\nkubectl apply -f k8s/exercises/01-ingress-configuration.yaml\n\n```\n\n#### j. Access the java application on your Linode NodeBalancer DNS Name's root url  `http://172-xxx-xxx-124.ip.linodeusercontent.com`\n\n#### k. Access phpmyadmin on your Linode NodeBalancer DNS Name's root url followed by `/phpmyadmin/` including the last forward slash (!) for example `http://172-xxx-xxx-124.ip.linodeusercontent.com/phpmyadmin/`\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003eCommands to connect to db, debug, delete all resources\u003c/b\u003e\u003c/summary\u003e\n\n```bash\nkubectl run -it --rm --namespace=exercises --image=mysql:9.0.1 --restart=Never mysql-client -- mysql -h mysqldb -pa+XMLuFoJR6NQnHk\n# debug\nkubectl describe statefulset mysql -n exercises\nkubectl describe deployment java-app -n exercises\nkubectl describe deployment phpmyadmin -n exercises\n\n# delete all resources\nkubectl delete -f k8s/exercises/01-mysql-statefulset.yaml\nkubectl delete -f k8s/exercises/01-mysql-service.yaml\nkubectl delete -f k8s/exercises/01-mysql-configmap.yaml\nkubectl delete -f k8s/exercises/01-java-app-deployment.yaml\nkubectl delete -f k8s/exercises/01-phpmyadmin-deployment.yaml\nkubectl delete -f k8s/exercises/01-phpmyadmin-configmap.yaml\nkubectl delete -f k8s/exercises/01-ingress-configuration.yaml\nkubectl delete pvc data-mysql-0 data-mysql-1 data-mysql-2 -n exercises\nkubectl delete secret java-app-mysql-env -n exercises\nkubectl delete secret aws-ecr-config -n exercises\n# keep to retain nodebalancer dns name\nhelm uninstall nginx-ingress --namespace exercises\n\n#             __   __           __        ___  __     ___  __\n#   |\\/| \\ / /__` /  \\ |       /  \\ |  | |__  |__) | |__  /__`\n#   |  |  |  .__/ \\__X |___    \\__X \\__/ |___ |  \\ | |___ .__/\nsource java-app/.env\n# create new database with root user and insert\nkubectl run mysql-client --image=mysql:5.7 -i --rm --namespace=exercises --restart=Never --\\\n  mysql -h mysql-0.mysql -u root -p$MYSQL_ROOT_PASSWORD \u003c\u003cEOF\nCREATE DATABASE test;\nCREATE TABLE test.messages (id INT AUTO_INCREMENT PRIMARY KEY, message VARCHAR(250));\nINSERT INTO test.messages (message) VALUES ('hello from master replica mysql-0.mysql');\nEOF\n\n# this should throw an error since it tries to insert into read-only replica\nkubectl run mysql-client --image=mysql:5.7 -i --rm --namespace=exercises --restart=Never --\\\n  mysql -h mysql-1.mysql -u root -p$MYSQL_ROOT_PASSWORD \u003c\u003cEOF\nINSERT INTO test.messages (message) VALUES ('hello from read-only replica mysql-1.mysql');\nEOF\n\n# select all messages\nkubectl run mysql-client --image=mysql:5.7 -i --rm --namespace=exercises --restart=Never --\\\n  mysql -h mysql-0.mysql -u root -p$MYSQL_ROOT_PASSWORD test \u003c\u003cEOF\nSELECT\n    message\nFROM messages;\nEOF\n\n# query data inserted by java-app\nkubectl run mysql-client --image=mysql:5.7 -i --rm --namespace=exercises --restart=Never --\\\n  mysql -h mysql-read -u $MYSQL_USER -p$MYSQL_PASSWORD team-member-projects \u003c\u003cEOF\nSELECT member_name, member_role FROM team_members;\nEOF\n\n# loop through read replicas\nkubectl run mysql-client-loop --image=mysql:5.7 -i -t --rm --namespace=exercises --restart=Never --  bash -ic \"while sleep 1; do mysql -h mysql-read -u root -p$MYSQL_ROOT_PASSWORD -e 'SELECT @@server_id,NOW(), (SELECT message from test.messages ORDER BY id desc LIMIT 1) as testquery'; done\"\n\n```\n\u003c/details\u003e\n\n\u003c/details\u003e\n\n-----\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e2. Write \u0026 Read (asynchronous row-based) replicated MySQL StatefulSet \u0026 PVC Block Storage with replicated SpringBoot Java \u0026 phpmyadmin Deployment, accessed via Ingress nginx-controller - started via shell script running helm charts\u003c/b\u003e\u003c/summary\u003e\n\n#### a. Create an Account on the Linode Cloud\n\nThen Create a Kubernetes Cluster https://cloud.linode.com/kubernetes/clusters named `test-cluster` in your Region without High Availability (HA) Control Plane to save costs. Adding 3 Nodes with 2GB each on a shared CPU is sufficient.\n\n#### b. Once the cluster is running, download `test-cluster-kubeconfig.yaml`. If your file is named differently, add it to `.gitignore` as it contains sensitive data.\n\n#### c. Navigate to scripts folder and run the shell script providing your AWS ECR url, AWS ECR repo name, NodeBalancer Public DNS, and desired Java Application version.\n\n\u003cu\u003eThe script then\u003c/u\u003e\n\n- logs in to aws ecr\n- exports kubeconfig\n- creates namespace and secrets\n- installs nginx ingress\n- replaces the index.html HOST address with your Nodebalancer DNS Name\n- builds and pushes the java app image\n- installs the helmchart\n```bash\ncd scripts\n./helm-launch-exercises.sh\ncd .. \u0026\u0026 watch -n 5 'kubectl get all -n exercises'\n```\n#### d. Access the java application on your Linode NodeBalancer DNS Name's root url  `http://172-xxx-xxx-124.ip.linodeusercontent.com`\n\n#### e. Access phpmyadmin on your Linode NodeBalancer DNS Name's root url followed by `/phpmyadmin/` including the last forward slash (!) for example `http://172-xxx-xxx-124.ip.linodeusercontent.com/phpmyadmin/`\n\n```bash\n# to delete all resources\n./helm-teardown-exercises.sh\n```\n\u003c/details\u003e\n\n-----\n\n\n## Usage (basic course examples)\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e1. Deploy a simple application with ConfigMap, locally generated Secret to avoid SCM exposure and external LoadBalancer Service in k8s cluster\u003c/b\u003e\u003c/summary\u003e\n\n\nNOTE: Replace `mongo-root-username` and `mongo-root-password` values with your own.\n```bash\nkubectl create secret generic mongodb-secret \\\n    --namespace=default \\\n    --from-literal=mongo-root-username='admin' \\\n    --from-literal=mongo-root-password='password'\nkubectl apply -f k8s/mongodb.yaml\nkubectl apply -f k8s/mongo-configmap.yaml\nkubectl apply -f k8s/mongo-express.yaml\n# access minicube-ip:30000 in the browser or run\nminikube service mongo-express-service\n#default credentials for mongo-express are admin:pass\n```\n\n```bash\nMONGO_POD=$(kubectl get pods --no-headers | grep \"mongodb-deployment\" | awk '{print $1}')\nEXPRESS_POD=$(kubectl get pods --no-headers | grep \"mongo-express\" | awk '{print $1}')\nkubectl describe pod $MONGO_POD\nkubectl logs $EXPRESS_POD\nkubectl describe service mongodb-service\nkubectl get all | grep mongo\n```\n\u003c/details\u003e\n\n-----\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e2. Deploy ConfigMap File and Secret File Volume Mounting for initializing containers with custom files\u003c/b\u003e\u003c/summary\u003e\n\n\n#### a. To start a basic mosquitto container with default values and log the configuration file, run:\n```bash\n# basic mosquitto app with standard conf\nkubectl apply -f k8s/mosquitto-without-volumes.yaml\n\n# log default config\nMOSQUITTO_POD=$(kubectl get pods --no-headers -o custom-columns=\":metadata.name\" | grep \"mosquitto\")\nkubectl exec $MOSQUITTO_POD -- cat /mosquitto/config/mosquitto.conf\n```\n\n#### b. To overwrite the mosquitto.conf file and create a secret.file in the containers via Volume mounts, run:\n\nNOTE: replace `-from-literal=secret.file='Password123!'` with your desired password\n```bash\nkubectl apply -f k8s/mosquitto-config-file.yaml\nkubectl create secret generic mosquitto-secret-file \\\n    --from-literal=secret.file='Password123!' \\\n    --type=Opaque\nkubectl apply -f k8s/mosquitto.yaml\n\n# log both conf and secret file from volume mount to console\nMOSQUITTO_POD=$(kubectl get pods --no-headers -o custom-columns=\":metadata.name\" | grep \"mosquitto\")\nkubectl exec $MOSQUITTO_POD -- sh -c \\\n    \"echo -e '\\nmosquitto.conf:' \\\n    \u0026\u0026 cat /mosquitto/config/mosquitto.conf \\\n    \u0026\u0026 echo -e '\\nsecret.file:' \\\n    \u0026\u0026 cat /mosquitto/secret/secret.file\"\n```\n\u003c/details\u003e\n\n-----\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e3. Start a Managed k8s cluster on Linode and run a replicated StatefulSet application with multiple nodes and attached persistent storage volumes using Helm Charts\u003c/b\u003e\u003c/summary\u003e\n\n\n#### a. Create an Account on the Linode Cloud and then Create a Kubernetes Cluster https://cloud.linode.com/kubernetes/clusters named `test-cluster` in your Region without High Availability (HA) Control Plane to save costs. Adding 3 Nodes with 2GB each on a shared CPU is sufficient.\n\n#### b. Once the cluster is running, download `test-cluster-kubeconfig.yaml`. If your file is named differently, add it to `.gitignore` as it contains sensitive data.\n\nThen uninstall minikube and install kubectl manually, otherwise kubectl will be used with the minikube binary resulting in connection errors.\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003eClick for installation instructions\u003c/b\u003e\u003c/summary\u003e\n\nInstallation help: https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/\n```bash\nminikube stop\nminikube delete --all --purge\n# delete alias kubectl=\"minikube kubectl --\" from .bashrc\nvim ~/.bashrc\n# e.g. remove from ubuntu\nsudo rm /usr/local/bin/minikube\n# or remove from debian\ndpkg --remove minikube\n\n# install kubectl\ncurl -LO \"https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl\"\nsudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl\n```\n\u003c/details\u003e\n\nThen run:\n```bash\n# change permissions for downloaded kubeconfig\nchmod 400 test-cluster-kubeconfig.yaml\nexport KUBECONFIG=test-cluster-kubeconfig.yaml\nkubectl get nodes\n```\n\n#### c. Add the helm repo and install a mongodb helm chart. Then connect to the db with a temporary mongo client to test the connection. For reference see https://artifacthub.io/packages/helm/bitnami/mongodb\n```bash\nhelm repo add bitnami https://charts.bitnami.com/bitnami\nhelm search repo bitnami/mongodb\nhelm install mongodb --values k8s/helm-mongodb.yaml bitnami/mongodb --version 13.16.3\n# username is root - for password run:\nexport MONGODB_ROOT_PASSWORD=$(kubectl get secret --namespace default mongodb -o jsonpath=\"{.data.mongodb-root-password}\" | base64 -d)\n# create mongo client\nkubectl run --namespace default mongodb-client --rm --tty -i --restart='Never' --env=\"MONGODB_ROOT_PASSWORD=$MONGODB_ROOT_PASSWORD\" --image docker.io/bitnami/mongodb:6.0.8-debian-11-r12 --command -- bash\n# connect to db within mongo client\nmongosh admin --host \"mongodb-0.mongodb-headless.default.svc.cluster.local:27017,mongodb-1.mongodb-headless.default.svc.cluster.local:27017,mongodb-2.mongodb-headless.default.svc.cluster.local:27017\" --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD\n```\n\n#### d. Add a mongo-express container and service listening on port 8081 internally for incoming traffic to render a GUI in browser.\n```bash\nkubectl apply -f k8s/helm-mongo-express.yaml\n```\n\n#### e. Add nginx-ingress-controller to route incoming traffic from Linode's NodeBalancer to the mongo-express internal ClusterIP Service. \n\nInstallation of the Helm chart also automatically sets up a NodeBalancer on Linode, the public dns name of which we have to save and replace in `k8s/helm-ingress.yaml` in the `- host: ` value\n```bash\nhelm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx\nhelm install nginx-ingress ingress-nginx/ingress-nginx --version 4.11.2 --set controller.publishService.enabled=true\n# add Linode NodeBalancer hostname to k8s/helm-ingress.yaml\nkubectl apply -f k8s/helm-ingress.yaml\n```\n\n#### f. Navigate to your Nodebalancer DNS host name to access mongo-express with default credentials `admin` and `pass` to persist data. \n\nYou can uninstall the database by running `helm uninstall mongodb` then start it back up with the command from step c) and see that data has been persisted in the persistent volume on Linode which are subsequently reattached to their respective pods.\n\u003c/details\u003e\n\n-----\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e4. Deployment of a custom NodeJS-application image published and pulled from AWS ECR, with mongodb and mongo-express pods \u0026 services running\u003c/b\u003e\u003c/summary\u003e\n\n#### a. Create an Elastic Container Registry (ECR) on AWS for your k8s images to live\n\nThen retrieve the push commands in aws console and run the docker login command locally to properly setup `/home/$USER/.docker/config.json`. Replace the remote url with your own and then copy the config file to your `config/` folder. It is added to .gitignore, so don't rename it.\n```bash\n# setup docker registry credentials\naws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin 010928217051.dkr.ecr.eu-central-1.amazonaws.com\ncp /home/$USER/.docker/config.json config/\n```\n\n#### b. Build and Push your NodeJS application image to AWS ECR remote repository. Replace the repo url with your own. Current Directory should be the git repo root dir.\n```bash\ndocker build -t node-app:1.5 node-app/.\ndocker tag node-app:1.5 010928217051.dkr.ecr.eu-central-1.amazonaws.com/k8s-imgs:node-app-1.5\ndocker push 010928217051.dkr.ecr.eu-central-1.amazonaws.com/k8s-imgs:node-app-1.5\n```\n\n#### c. Create secret in k8s cluster with registry credentials\n\nAlternative 1 (allowing multiple registries to be added, since they are comma delimited in config file)\n```bash\nkubectl create secret generic my-registry-key-1 \\\n    --from-file=.dockerconfigjson=config/config.json \\\n    --type=kubernetes.io/dockerconfigjson\n```\n\nAlternative 2 (allowing only a single registry to be set)\nNOTE: To use this, overwrite `imagePullSecrets:- name: my-registry-key-1` in `k8s/node-app-deployment.yaml`\n```bash\nkubectl create secret docker-registry my-registry-key-2 \\\n    --docker-server=010928217051.dkr.ecr.eu-central-1.amazonaws.com \\\n    --docker-username=AWS \\\n    --docker-password=$(aws ecr get-login-password)\n```\n\n#### d. Setup environment and container secrets to avoid exposure in SCM. Create an `node-app/app/.env` file and add the following keys, changing credentials to your own:\n```bash\nME_CONFIG_MONGODB_ADMINUSERNAME=admin\nME_CONFIG_MONGODB_ADMINPASSWORD=password\nME_CONFIG_MONGODB_SERVER=mongodb\nME_CONFIG_MONGODB_URL=mongodb://mongodb:27017\nMONGO_DB_USERNAME=admin\nMONGO_DB_PWD=password\nMONGO_INITDB_ROOT_USERNAME=admin\nMONGO_INITDB_ROOT_PASSWORD=password\n```\n\nThen export your AWS ECR Image URL as environment variable and test whether or not your setup is correct by running\n\n```bash\nexport AWS_NODE_IMG_URL=010928217051.dkr.ecr.eu-central-1.amazonaws.com/k8s-imgs:node-app-1.5\ndocker compose -f node-app/docker-compose.yaml up\n```\nNOTE: if you are running the docker compose on a remote VPS, you have simply have to copy the `docker-compose.yaml` to your remote via scp and then copy the `node-app/app/.env` file to your remote and create an `app/` folder next to the docker compose file where the `.env` can recide. One additional step is to enter your running node-app docker container via docker exec -it CONTAINER_HASH /bin/sh and execute `vi index.html` and exchange `localhost` with your remote ip, e.g. `64.226.117.247`\n\n#### e. Replace `image: 010928217051.dkr.ecr.eu-central-1.amazonaws.com/k8s-imgs:node-app-1.5` with your own AWS ECR image-tag in the file `k8s/node-app-deployment.yaml` and run the following commands\n\nIMPORTANT: `mongo-root-username` and `mongo-root-password` have to be identical to the ones in your `.env` file from step d)!\n```bash\nkubectl create secret generic mongodb-secret \\\n    --namespace=default \\\n    --from-literal=mongo-root-username='admin' \\\n    --from-literal=mongo-root-password='password'\nkubectl apply -f k8s/mongodb.yaml\nkubectl apply -f k8s/mongo-configmap.yaml\nkubectl apply -f k8s/mongo-express.yaml\nkubectl apply -f k8s/node-app-deployment.yaml\n```\n\n#### f. Since your ip will differ from mine and also the docker-compose variant and depends on the minikube cluster configuration\n\nWe have to exec a shell in the node-app pod and replace `localhost` in `index.html` with our minikube ip and the port with our loadbalancer nodeport\n```bash\nNODE_APP_POD_NAME=$(kubectl get pods --no-headers -o custom-columns=\":metadata.name\" | grep \"node-app\")\nkubectl exec -it $NODE_APP_POD_NAME -- /bin/sh\nvi index.html # and replace localhost with your minikube ip and 3000 with your loadbalancer nodeport!\n# then access minicube-ip:30001 in the browser or run\nminikube service node-app-service\n```\n\u003c/details\u003e\n\n-----\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e5. Deployment of 11 replicated microservices with best-practice configuration via single k8s.yaml file\u003c/b\u003e\u003c/summary\u003e\n\n*NOTE:* The microservices app is a google developed multi-language application with service-to-service communication via gRPC. See https://github.com/GoogleCloudPlatform/microservices-demo/tree/main\n\n#### a. Create an Account on the Linode Cloud and then Create a Kubernetes Cluster https://cloud.linode.com/kubernetes/clusters named `test-cluster` in your Region without High Availability (HA) Control Plane to save costs. Adding 3 Nodes with 4GB each on a shared CPU is sufficient.\n\n#### b. Once the cluster is running, download `test-cluster-kubeconfig.yaml`. If your file is named differently, add it to `.gitignore` as it contains sensitive data.\n\nThen run:\n```bash\n# change permissions for downloaded kubeconfig\nchmod 400 test-cluster-kubeconfig.yaml\nexport KUBECONFIG=test-cluster-kubeconfig.yaml\nkubectl get nodes\n```\n\n#### c. Start the microservice application including a LoadBalancer receiving an external DNS Name from your Linode NodeBalancer for public access.\n\n```bash\nkubectl apply -f k8s/microservices-best-practice.yaml\n#kubectl delete -f k8s/microservices-best-practice.yaml\n```\n\n#### d. Navigate to your Nodebalancer DNS host name to access the microservices frontend.\n\u003c/details\u003e\n\n-----\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e6. Deployment of 11 replicated microservices with several helm install commands bundled in a bash script\u003c/b\u003e\u003c/summary\u003e\n\n#### a. Simply execute the following command from the git project root directory\n```bash\nexport KUBECONFIG=test-cluster-kubeconfig.yaml\n# install\nbash scripts/helm-install-microservices.sh\n# uninstall\nbash scripts/helm-uninstall-microservices.sh\n```\n\u003c/details\u003e\n\n-----\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e7. Deployment of 11 replicated microservices with single helmfile apply command\u003c/b\u003e\u003c/summary\u003e\n\n#### a. Simply execute the following command from the git project root directory\n\n```bash\n# install\nKUBECONFIG=$(pwd)/test-cluster-kubeconfig.yaml \\\nhelmfile apply \\\n--file helm/helmfile.yaml \\\n-n microservices\n# uninstall\nKUBECONFIG=$(pwd)/test-cluster-kubeconfig.yaml \\\nhelmfile destroy \\\n--file helm/helmfile.yaml \\\n-n microservices\n```\n\u003c/details\u003e\n\n-----\n\n## Usage (Bonus Remote VPS Setup)\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e1. Setup ArgoCD to use GitOps principles for writing declarative configuration, versioning, storing and running our k8s cluster \u003c/b\u003e\u003c/summary\u003e\n\nSee https://argo-cd.readthedocs.io/en/stable/getting_started/\n\n#### a. Add `ARGOCD_ADMIN_PW=xxx` to `.env` file\n\n#### b. Navigate to `scripts/` folder and execute the installation script.\n```bash\n./remote-setup-ArgoCD.sh\n```\n\u003c/details\u003e\n\n-----\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\u003cb\u003e2. Setup ingress-nginx for minikube to handle incoming traffic from the outside world into our remote VPS\u003c/b\u003e\u003c/summary\u003e\nSee https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/\n\n#### a. Navigate to `scripts/` folder and execute the installation script.\n```bash\n./remote-setup-ingress-nginx.sh\n```\n\n#### b. Install nginx reverse proxy to forward outside requests to the VPS to the minikube ip address on the ingress controller port. To configure nginx replace `proxy_pass` ip with your minikube ip from the output of step a)\n```bash\nssh root@\u003cREMOTE_ADDRESS\u003e\nsudo apt update\nsudo apt install nginx-full\n\necho \"\nstream {\n    server {\n        listen 30080;\n        proxy_pass 192.168.49.2:80;\n    }\n\n    server {\n        listen 30443;\n        proxy_pass 192.168.49.2:443;\n    }\n}\n\" \u003e\u003e /etc/nginx/nginx.conf\n\nsudo nginx -t\n\nsudo systemctl restart nginx\n```\nYou can access the plain site http://\u003cREMOTE_ADDRESS\u003e:30080 in a browser from any external device.\nYou can access the TLS site https://\u003cREMOTE_ADDRESS\u003e:30443 in a browser from any external device.\nNOTE: HTTPS certificate config to remove security warning is a topic for another day. See potentially https://www.zepworks.com/posts/access-minikube-remotely-kvm/#4-certs or https://minikube.sigs.k8s.io/docs/handbook/untrusted_certs/\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhangrybear666%2F10-devops-bootcamp__kubernetes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhangrybear666%2F10-devops-bootcamp__kubernetes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhangrybear666%2F10-devops-bootcamp__kubernetes/lists"}