--- layout: post title: 'Step 1: K3d Cluster Architecture' date: 2025-12-28 09:00:00 -0400 categories: - blog_app highlight: true --- [[2025-12-27-intro]] # 1. K3d Cluster Architecture In a standard Docker setup, containers share the host's kernel and networking space directly. In Kubernetes, we introduce an abstraction layer: a **Cluster**. For this project, we use **K3d**, which packages **K3s** (a lightweight production-grade K8s distribution) into Docker containers. ```text Severed-Infra % tree . ├── README.md ├── apps │ ├── severed-blog-config.yaml │ ├── severed-blog-hpa.yaml │ ├── severed-blog-service.yaml │ ├── severed-blog.yaml │ └── severed-ingress.yaml ├── infra │ ├── alloy-env.yaml │ ├── alloy-setup.yaml │ ├── dashboard │ │ ├── dashboard-admin.yaml │ │ ├── permanent-token.yaml │ │ └── traefik-config.yaml │ ├── observer │ │ ├── adapter-values.yaml │ │ ├── dashboard-json.yaml │ │ ├── grafana-ingress.yaml │ │ ├── grafana.yaml │ │ ├── loki.yaml │ │ └── prometheus.yaml │ └── storage │ └── openebs-sc.yaml ├── namespaces.yaml └── scripts ├── README.md ├── access-hub.sh ├── deploy-all.sh ├── setup-grafana-creds.sh └── tests ├── generated-202-404-blog.sh └── stress-blog.sh ``` ## 1.1 Multi-Node Simulation - **Server (Control Plane):** The master node. Runs the API server, scheduler, and etcd. - **Agents (Workers):** The worker nodes where our application pods run. ### Setting up the environment We map port `8080` to the internal Traefik LoadBalancer to access services via `*.localhost`. ```bash k3d cluster create severed-cluster \ --agents 2 \ -p "8080:80@loadbalancer" \ -p "8443:443@loadbalancer" ``` ## 1.2 Image Registry Lifecycle Since our `severed-blog` image is local, we side-load it directly into the cluster's internal image store rather than pushing to Docker Hub. ```bash docker build -t severed-blog:v0.3 . k3d image import severed-blog:v0.3 -c severed-cluster ``` ## 1.3 Namespaces & Storage We partition the cluster into logical domains. We also install **OpenEBS** to provide dynamic storage provisioning (PersistentVolumes) for our databases. **`namespaces.yaml`** ```yaml apiVersion: v1 kind: Namespace metadata: name: severed-apps --- apiVersion: v1 kind: Namespace metadata: name: monitoring --- apiVersion: v1 kind: Namespace metadata: name: kubernetes-dashboard --- apiVersion: v1 kind: Namespace metadata: name: openebs ``` **`infra/storage/openebs-sc.yaml`** ```yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: severed-storage provisioner: openebs.io/local reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer ``` --- ## 1.4. Infrastructure Concepts Cheat Sheet | Object | Docker Equivalent | Kubernetes Purpose | | ----------- | ------------------------------ | ----------------------------------------------------------------- | | Node | The Host Machine | A physical or virtual server in the cluster. | | Pod | A Container | The smallest deployable unit (can contain multiple containers). | | Deployments | `docker-compose up` | Manages the lifecycle and scaling of Pods. | | Services | Network Aliases | Provides a stable DNS name/IP for a group of Pods. | | HPA | Auto-Scaling Group | Automatically scales replicas based on traffic/load. | | Ingress | Nginx Proxy / Traefik | Manages external access to Services via HTTP/HTTPS. | | ConfigMap | `docker run -v config:/etc...` | Decouples configuration files from the container image. | | Secret | Environment Variables (Secure) | Stores sensitive data (passwords, tokens) encoded in Base64. | | DaemonSet | `mode: global` (Swarm) | Ensures one copy of a Pod runs on _every_ Node (logs/monitoring). | | StatefulSet | N/A | Manages apps requiring stable identities and storage (Databases). | [[2025-12-27-part-2]]