# Good Example: Kubernetes Deployment > A Kubernetes Deployment that follows Atelier's Kubernetes principles. Each aspect cites the principle it satisfies. ## The Deployment A stateless web service deployed as a Deployment with probes, resource contracts, RBAC, and a rolling update strategy — the canonical "production workload" pattern. ### Manifest ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: api namespace: api-prod labels: app: api tier: web spec: replicas: 3 selector: matchLabels: app: api strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: metadata: labels: app: api tier: web spec: serviceAccountName: api automountServiceAccountToken: false containers: - name: api image: registry.example.com/api:v1.4.2 # pinned, not :latest ports: - containerPort: 8080 resources: requests: cpu: 250m memory: 256Mi limits: memory: 512Mi readinessProbe: httpGet: path: /healthz/ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5 livenessProbe: httpGet: path: /healthz/live port: 8080 initialDelaySeconds: 15 periodSeconds: 10 env: - name: LOG_LEVEL valueFrom: configMapKeyRef: name: api-config key: log_level - name: DATABASE_URL valueFrom: secretKeyRef: name: api-secrets key: database_url volumeMounts: - name: config mountPath: /etc/api readOnly: true volumes: - name: config configMap: name: api-config --- apiVersion: v1 kind: Service metadata: name: api namespace: api-prod spec: selector: app: api ports: - port: 80 targetPort: 8080 --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: api-deny-ingress namespace: api-prod spec: podSelector: matchLabels: app: api policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: tier: edge ``` ## What Makes It Good ### Controller, Not Bare Pod (k8s P2 Pods are Mortal) - A `Deployment` manages the pods. If one dies, the controller replaces it. A bare pod has no recovery. - See `domains/kubernetes/workloads.md`. ### Resource Contracts (k8s P4 Requests and Limits are Contracts) - Every container has CPU and memory requests and a memory limit. The workload is `Burstable`, not `BestEffort` (first evicted under pressure). - See `domains/kubernetes/workloads.md` for QoS classes. ### Probes (k8s P5 Probes Drive Health) - `readinessProbe` gates traffic: a pod that is not ready is removed from the Service's endpoints. - `livenessProbe` restarts a wedged container. - The probes check the workload's own health (`/healthz/ready`, `/healthz/live`), not a dependency. A liveness probe that calls the database would cascade-restart on a DB blip. - See `domains/kubernetes/workloads.md`. ### Image Pinning (k8s P1 + IaC P5 Version Everything) - `image: registry.example.com/api:v1.4.2` — pinned to a version, not `:latest`. A pod restart pulls the same image it was built with. - See `domains/infrastructure-as-code/terraform.md` and `domains/devops/P7 Immutability` for the immutability angle. ### RBAC (k8s P7 RBAC by Intent, Not Identity) - `serviceAccountName: api` — the workload runs as a dedicated ServiceAccount, not the `default` shared identity. - `automountServiceAccountToken: false` — the workload does not call the API, so it gets no token. See `domains/kubernetes/rbac.md`. - A matching `Role` + `RoleBinding` (not shown) would grant `get, list, watch` on `configmaps` in this namespace — least privilege, scoped by intent. ### Config and Secrets Separate (k8s P9 Config and Secrets are Separate) - `LOG_LEVEL` from a ConfigMap (non-sensitive). `DATABASE_URL` from a Secret (sensitive). Both injected at runtime; neither baked into the image. - A configuration change does not require a rebuild. A secret rotation does not require an image redeploy. - See `domains/kubernetes/rbac.md` and `domains/security/secrets.md`. ### Namespaces Bound Blast Radius (k8s P6 Namespaces Bound Blast Radius) - The workload lives in `api-prod`, not `default`. The namespace is the unit of quota, RBAC, and NetworkPolicy. A problem in `api-prod` does not leak to other workloads. - See `domains/kubernetes/networking.md`. ### NetworkPolicy Default-Deny (k8s P6, P7) - The `NetworkPolicy` allows ingress only from the `edge` namespace. Without it, every pod in the cluster could reach `api`. Default-deny is the baseline; allows are the exceptions. - See `domains/kubernetes/networking.md`. ### Roll Forward, Roll Back (k8s P10 Roll Forward Roll Back) - `strategy: RollingUpdate` with `maxSurge: 1, maxUnavailable: 0` — the rollout adds a new pod before removing an old one. Availability is maintained. - `kubectl rollout undo deployment/api` reverts to the previous ReplicaSet. The rollback is tested before it is needed. - See `domains/kubernetes/workloads.md` and `domains/devops/P5 Progressive Delivery`. ### Cross-Domain Links - `domains/devops/P4 Rollback First` — the rollout strategy makes the deploy reversible. - `domains/security/authorization` — the ServiceAccount + Role model is the k8s expression of least-privilege authorization. - `domains/observability/metrics` — the probes are the platform's observability into the workload's health; the workload's own metrics complete the picture.