Files
atelier/examples/good/k8s-deployment.md
T
Jon Chery d1aa5daf2b docs(milestone): complete v0.2 — infrastructure-as-code + kubernetes
---ci---
project: atelier
phase: 5
milestone: v0.2
status: complete
requirements:
  covered: [ATELIER-36, ATELIER-37, ATELIER-38, ATELIER-39, ATELIER-40, ATELIER-41, ATELIER-42, ATELIER-43, ATELIER-44, ATELIER-45, ATELIER-46, ATELIER-47, ATELIER-48, ATELIER-49, ATELIER-50, ATELIER-51, ATELIER-52, ATELIER-53, ATELIER-54, ATELIER-55, ATELIER-56, ATELIER-57, ATELIER-58, ATELIER-59]
  partial: []
---/ci---
2026-08-05 02:20:17 +00:00

5.7 KiB

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

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.
  • 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.