{"id":17967180,"url":"https://github.com/dmytro-rybak/kube-essentials","last_synced_at":"2025-08-16T15:31:56.070Z","repository":{"id":259518661,"uuid":"878089119","full_name":"dmytro-rybak/kube-essentials","owner":"dmytro-rybak","description":"A hands-on project template to practice Kubernetes fundamentals by deploying a small full-stack application (FastAPI, React, PostgreSQL) in a kind cluster.","archived":false,"fork":false,"pushed_at":"2024-11-03T15:55:11.000Z","size":13,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-03T16:32:35.871Z","etag":null,"topics":["deployment","devops","docker","helm","kind","kubernetes"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":false,"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/dmytro-rybak.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-10-24T19:02:33.000Z","updated_at":"2024-11-03T15:55:14.000Z","dependencies_parsed_at":"2024-10-26T06:26:47.497Z","dependency_job_id":"2135c5bb-1e85-4aa4-bbfc-40ccddd439a4","html_url":"https://github.com/dmytro-rybak/kube-essentials","commit_stats":null,"previous_names":["dmytro-rybak/kube-essentials"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmytro-rybak%2Fkube-essentials","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmytro-rybak%2Fkube-essentials/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmytro-rybak%2Fkube-essentials/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmytro-rybak%2Fkube-essentials/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmytro-rybak","download_url":"https://codeload.github.com/dmytro-rybak/kube-essentials/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230043147,"owners_count":18163966,"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":["deployment","devops","docker","helm","kind","kubernetes"],"created_at":"2024-10-29T14:04:26.193Z","updated_at":"2025-08-16T15:31:56.055Z","avatar_url":"https://github.com/dmytro-rybak.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kube-Essentials\n\nA learning project focused on working with **Kubernetes**. The goal is to deploy a full-stack application using the [fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template), which includes a **React** frontend, **FastAPI** backend, and **PostgreSQL** database.\n\n## Prerequisites\n\nBefore you begin, ensure you have the following tools installed on your machine:\n\n- **Docker**: Required for building and running container images. Follow the installation instructions for your platform:\n  - [Docker installation guide](https://docs.docker.com/get-docker/)\n\n- **Kind** (Kubernetes in Docker): Used to create local Kubernetes clusters using Docker. Install Kind by following the official documentation:\n  - [Kind installation guide](https://kind.sigs.k8s.io/docs/user/quick-start/)\n\n- **kubectl**: The command-line tool for interacting with your Kubernetes cluster. Install it using the official Kubernetes documentation:\n  - [kubectl installation guide](https://kubernetes.io/docs/tasks/tools/install-kubectl/)\n\n- **Helm**: A package manager for Kubernetes that simplifies the deployment of applications. Install Helm by following the instructions here:\n  - [Helm installation guide](https://helm.sh/docs/intro/install/)\n\nMake sure each of these tools is installed and properly configured before proceeding with the setup of **kube-essentials**.\n\n## Recommendations\n\nFor those looking to deepen their understanding of Kubernetes, it’s recommended to take the **CKAD (Certified Kubernetes Application Developer)** course by **Mumshad Mannambeth** if you have an opportunity. This course covers all the essential concepts and provides hands-on labs, which are crucial for mastering Kubernetes.\n\nAdditionally, the [official Kubernetes documentation](https://kubernetes.io/docs/home/) is an invaluable resource for learning and referencing all Kubernetes concepts. It provides thorough guides, examples, and best practices for deploying and managing applications in Kubernetes.\n\nSince you will be working frequently with `kubectl`, it's recommended to create an alias for easier command execution. Setting up an alias like `k` can significantly simplify your workflow. You can find the instructions on how to create this alias in the [official Kubernetes documentation](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#kubectl-autocomplete).\n\n## Cluster Setup\n\nTo set up your Kubernetes cluster with **kind** and configure the necessary components, follow the steps below:\n\n### Step 1: Create the Kind Cluster\n\nThe **kind** configuration is already prepared with 1 control-plane node and 3 worker nodes: `node-basic`, `node-fast`, and `node-db`. To create the cluster, run:\n\n```bash\nkind create cluster --config kind-config.yaml\n```\n\nThis command will create a local Kubernetes cluster using the `kind-config.yaml` configuration file, which includes the desired node setup.\n\n### Step 2: Install the Nginx Ingress Controller\n\nThe Nginx Ingress Controller is required to manage external access to your services within the cluster. To install the Nginx Ingress Controller, apply the following manifest:\n\n```bash\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml\n```\n\nThis command deploys the Nginx Ingress Controller, allowing you to define ingress rules for routing traffic to your applications within the cluster.\n\nMake sure to verify the setup by checking the status of the ingress controller pods:\n\n```bash\nkubectl get pods -n ingress-nginx\n```\n\nThe controller pod should be in a Running state before you proceed.\n\n### Step 3: PostgreSQL Provisioning\n\nTo set up the **PostgreSQL** database in your Kubernetes cluster, follow the steps below:\n\n**Add the Bitnami Helm repository**:\n```bash\nhelm repo add bitnami https://charts.bitnami.com/bitnami\n```\n\n**Install PostgreSQL using the Bitnami Helm chart**:\n\n```bash\nhelm install postgres bitnami/postgresql --version 16.0.3 -n postgres --create-namespace \\\n  --set architecture=standalone \\\n  --set \"primary.tolerations[0].key=postgres-only\" \\\n  --set \"primary.tolerations[0].operator=Exists\" \\\n  --set \"primary.tolerations[0].effect=NoSchedule\" \\\n  --set \"primary.nodeSelector.kubernetes\\.io/hostname=node-db\" \\\n  --set primary.persistence.size=2Gi \\\n  --set primary.resourcesPreset=none \\\n  --set primary.resources.requests.cpu=125m \\\n  --set primary.resources.requests.memory=256Mi \\\n  --set primary.resources.limits.cpu=250m \\\n  --set primary.resources.limits.memory=512Mi\n```\n\nThis command deploys a standalone PostgreSQL instance in the postgres namespace, with resources tailored for local development and a node selector to ensure it runs on the `node-db` node.\n\n\u003e [!NOTE]\n\u003e While deploying databases inside a Kubernetes cluster can be complex and challenging for production environments, this setup is suitable for learning purposes. In production, it is recommended to use a managed database service or run the database outside the Kubernetes cluster to ensure better data availability, backup, and disaster recovery capabilities.\n\n### Step 4: Prepare the Frontend and Backend Images\n\nTo prepare the Docker images for the frontend and backend components and load them into your **kind** cluster, follow these steps:\n\n**Build the Docker images** using the source code from the `0.7.1` release of the FastAPI full-stack template:\n\n```bash\ndocker build -t frontend:0.7.1 https://github.com/fastapi/full-stack-fastapi-template.git#0.7.1:frontend\n```\n\n```bash\ndocker build -t backend:0.7.1 https://github.com/fastapi/full-stack-fastapi-template.git#0.7.1:backend\n```\n\n**Load the Docker images** into the kind cluster. This step ensures that the images are available to your Kubernetes cluster without needing to push them to a remote registry:\n\n```bash\nkind load docker-image frontend:0.7.1\n```\n\n```bash\nkind load docker-image backend:0.7.1\n```\n\n### Step 5: Create a Development Namespace\n\nTo keep your resources organized and avoid using the default namespace, create a `dev` namespace for deploying your application components:\n\n```bash\nkubectl create ns dev\n```\n\n### Step 6 (Optional): Rename the Containers\n\n```bash\ndocker rename kind-control-plane control-plane\n```\n\n```bash\ndocker rename kind-worker node-basic\n```\n\n```bash\ndocker rename kind-worker2 node-fast\n```\n\n```bash\ndocker rename kind-worker3 node-db\n```\n\n## Tasks\n\nAll you need to do is add the required configuration into **8 files** inside the `manifests` folder. You can add configuration to one file and apply it right away, or you can add multiple configurations and apply them all at once. You can also make changes to existing configurations and reapply them as needed. To apply your changes to the **dev** environment, run the following command:\n\n```bash\nkubectl apply -f manifests --recursive -n dev\n```\n\n- Create a Deployment named \"backend\" in `manifests/backend/deployment.yaml`. It should have 1 replica, and the container should use the image `backend:0.7.1`, and expose port `8000`.\n\n- Create a Secret in `manifests/backend/secret.yaml` named `backend-secrets`. Some values are predefined, but you need to generate a `FIRST_SUPERUSER_PASSWORD` and find the `POSTGRES_PASSWORD` from your cluster. Refer to the comments inside the `secret.yaml` file for detailed instructions.\n\n- Update the \"backend\" Deployment in `manifests/backend/deployment.yaml` to use environment variables from `backend-secrets` so that they are available to the backend container.\n\n- Add an init container to the \"backend\" Deployment in `manifests/backend/deployment.yaml` to ensure that the backend waits for PostgreSQL to be ready before starting. Use the `cgr.dev/chainguard/wait-for-it` image and configure it correctly to wait for the PostgreSQL service. Research how to use this image and adjust the settings as needed.\n\n- Add a second init container to the \"backend\" Deployment in `manifests/backend/deployment.yaml` to perform database migrations before the main application starts. Use the `backend:0.7.1` image for this init container, and ensure it uses the same secret that is mounted to the backend container for accessing environment variables. Configure the init container to run the following command: `python app/backend_pre_start.py \u0026\u0026 alembic upgrade head \u0026\u0026 python app/initial_data.py`\n\n- Create a Service in `manifests/backend/service.yaml` to expose the \"backend\" Deployment. You already have all the necessary information to configure this service correctly.\n\n- Apply the configuration you have created so far to the `dev` namespace.\n\n- Verify that the following resources have been created successfully:\n  - Pod\n  - ReplicaSet\n  - Deployment\n  - Secret\n  - Service\n\n  Use appropriate commands to check the status of each resource and ensure that they are in the expected state before proceeding.\n\n- Create a Deployment named \"frontend\" in `manifests/frontend/deployment.yaml`. It should have 1 replica, and the container should use the image `frontend:0.7.1`, and expose port `80`.\n\n- Create a Service in `manifests/frontend/service.yaml` to expose the \"frontend\" Deployment. You already have all the necessary information to configure this service correctly.\n\n- Create an Ingress resource in `manifests/ingress.yaml` with the following specifications:\n  - Set the `ingressClassName` to `nginx`.\n  - Use `localhost` as the host.\n  - Configure the path `/docs` to redirect traffic to the `backend` service.\n  - Configure the path `/api` to also redirect traffic to the `backend` service.\n  - Configure the root path `/` to redirect traffic to the `frontend` service.\n\n- If you have configured everything properly, you can open `localhost` in your browser and see the application. Try logging in using the credentials from the secret you created and explore the app. Also, check if `localhost/docs` is working to access the API documentation.\n\n  If you encounter any issues, don't worry — troubleshooting is a crucial skill, and solving these challenges will help you learn even more.\n\n- In real-world scenarios, we often need to control where applications are deployed. To practice this, let's establish the following rule for our setup:\n\n  The `backend` should only be deployed on the `fast-node`, while the `frontend` can be deployed on either the `fast-node` or `basic-node` (since the `db-node` is exclusively reserved for PostgreSQL).\n\n  Find a way to update the backend deployment to make it true.\n\n- Understand **resource requests** and **limits** in Kubernetes, which manage how much CPU and memory a container can use. Then, add the following settings to your deployments:\n\n  **Backend**: Requests `100m` CPU, `256Mi` memory; Limits `500m` CPU, `1Gi` memory\n  **Frontend**: Requests `75m` CPU, `128Mi` memory; Limits `150m` CPU, `256Mi` memory\n\n- Add **liveness** and **readiness** probes to the `backend` and `frontend` deployments to monitor the health of your services:\n\n  **Frontend**:\n  - Liveness: Check `path: /` on `port: 80`, with a 15-second initial delay and a 20-second interval.\n  - Readiness: Check `path: /` on `port: 80`, with a 7-second initial delay and a 10-second interval.\n\n  **Backend**:\n  - Liveness: Check `path: /api/v1/utils/health-check/` on `port: 8000`, with a 15-second initial delay and a 20-second interval.\n  - Readiness: Check `path: /api/v1/utils/health-check/` on `port: 8000`, with a 15-second initial delay and a 10-second interval.\n\n- We'll set up a periodic job to back up our PostgreSQL database, ensuring regular data protection. Start by creating a PersistentVolumeClaim (PVC) in `manifests/pvc.yaml` named `postgres-backup` with `ReadWriteOnce` access, `0.5Gi` of storage, and `standard` as the storage class.\n\n- Create a CronJob in `manifests/cronjob.yaml` named `postgres-backup` to automate daily backups of the PostgreSQL database. The job should:\n  - Run every day at midnight (`\"0 0 * * *\"`).\n  - Use the `postgres:17.0` image.\n  - Use environment variables from the `backend-secrets` Secret.\n  - Store the backups in a volume mounted at `/backups` using the `postgres-backup` PVC.\n  - Ensure the job runs on `node-basic` using a node selector.\n  - Use the command bellow to make the backup with timespamps\n\n  ```bash\n  export TIMESTAMP=$(date +\"%Y%m%d%H%M%S\") \u0026\u0026 \\\n  export PGPASSWORD=$POSTGRES_PASSWORD \u0026\u0026 \\\n  pg_dump -h $POSTGRES_SERVER -U $POSTGRES_USER -f /backups/backup-$TIMESTAMP.sql\n  ```\n\n- To test the `postgres-backup` CronJob without waiting until midnight, create a one-time Job from the CronJob. This will allow you to trigger a backup immediately and verify that the setup is working correctly. Use `kubectl` to create a job from the existing `postgres-backup` CronJob, ensuring it runs with the same configuration.\n\n- And the last one: try to find the backup file directly on the `node-basic` node, It won't be easy)))\n\n## Final thoughts\n\nCongratulations on making it through this challenging project! Whether you completed all the tasks or tackled just a few, you've taken significant steps toward mastering Kubernetes. Deep diving into a project like this isn't the easy path — it's the right path. It’s the way to truly understand the concepts, work through real-world scenarios, and see the results of your efforts.\n\nThis project has introduced you to essential Kubernetes concepts, from managing deployments and secrets to handling persistence and automating tasks with CronJobs. Along the way, you’ve faced real challenges and gained practical skills that will serve you well in future projects.\n\n## CleanUp\n\nAfter completing the project and testing your setup, make sure to clean up all resources to avoid unnecessary use of local resources:\n\n**Delete the kind cluster** to remove all Kubernetes resources and the cluster itself:\n```bash\nkind delete cluster\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmytro-rybak%2Fkube-essentials","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmytro-rybak%2Fkube-essentials","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmytro-rybak%2Fkube-essentials/lists"}