Kubernetes Workloads

Run production apps, not just containers

01 / 16

A 60-minute session covering Deployments, Services, ConfigMaps, Secrets, resource limits, and rolling updates through one end-to-end Kubernetes app lab.

60minutes total
45minutes theory + guided walkthrough
10minutes lab runbook
5minutes quiz + recap
Session Map

Agenda and learning outcomes

02 / 16

Agenda

0-5 min
Why workloads matter in real clusters
5-20 min
Pods, Deployments, ReplicaSets, StatefulSets, DaemonSets
20-30 min
Services, Ingress, and stable networking
30-40 min
ConfigMaps, Secrets, requests/limits, rollout strategy
40-55 min
Lab: deploy a full app to Kubernetes
55-60 min
Quiz and takeaways

By the end, learners should be able to

  • Explain why Pods alone are not an operations model
  • Choose the right workload controller for stateless vs stateful vs node-level jobs
  • Expose applications safely with the right Service type
  • Externalize config and protect secrets
  • Set resource requests and limits to avoid noisy-neighbor failures
  • Use rolling updates and rollout history to ship safely
Core Idea

Pods are runtime units, not deployment strategy

03 / 16

Pod

  • Smallest deployable unit in Kubernetes
  • One or more tightly coupled containers
  • Ephemeral by design: if it dies, Kubernetes can replace it with a new Pod
  • IP address changes across restarts

Why not create Pods directly?

  • No built-in desired state beyond that one object
  • No rollout strategy, rollback history, or replica management
  • Operationally fragile for production workloads
  • Correct default: use a controller such as Deployment, StatefulSet, or DaemonSet

Rule of thumb

Pod = runtime envelope Deployment = stateless app controller StatefulSet = stable identity + storage DaemonSet = one Pod per node
Controllers

Choose the right workload primitive

04 / 16

Deployment

  • Best default for stateless services
  • Manages ReplicaSets
  • Supports rolling updates and rollback

StatefulSet

  • For databases and clustered stateful systems
  • Stable pod names such as `db-0`, `db-1`
  • Stable persistent volumes

DaemonSet

  • Runs one pod on every node
  • Ideal for log collectors and monitoring agents
  • Examples: Fluent Bit, node exporters

ReplicaSet in context

ReplicaSets are rarely authored directly. A Deployment creates and owns them to guarantee that the requested replica count is continuously enforced.

Networking

Services give ephemeral Pods a stable address

05 / 16

Why Services exist

  • Pods come and go, so Pod IPs are not a reliable endpoint
  • A Service adds a stable virtual IP and DNS name
  • Kube-proxy routes traffic to healthy matching Pods
ClientCalls `api-service`
ServiceStable IP + DNS
Pods`api-abc`, `api-def`

Service types

  • ClusterIP: internal-only, default choice for service-to-service traffic
  • NodePort: exposes a port on every node, useful for demos and testing
  • LoadBalancer: cloud-managed external traffic entrypoint
  • Ingress: L7 routing by host/path to multiple Services
Configuration

Separate application config from the image

06 / 16

ConfigMap

  • Non-sensitive configuration
  • Feature flags, base URLs, environment labels, config files
  • Can be injected as environment variables or mounted as files

Secret

  • Sensitive values such as tokens, passwords, certificates
  • Base64 encoded in manifest form
  • Use RBAC, encryption at rest, and external secret managers in production

Production guidance

Kubernetes Secrets are not magically safe because they are encoded. Treat them as sensitive data, enable encryption at rest, and prefer systems like External Secrets Operator with Azure Key Vault, AWS Secrets Manager, or HashiCorp Vault.

Reliability

Resource requests and limits protect the cluster

07 / 16

Requests

  • Minimum CPU and memory reserved for scheduling
  • Used by the scheduler to place Pods
  • Without requests, scheduling becomes guesswork

Limits

  • Upper bound for CPU and memory consumption
  • CPU can be throttled
  • Memory overuse can lead to OOMKilled containers
resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
  limits:
    cpu: "500m"
    memory: "512Mi"
Delivery

Rolling updates reduce deployment risk

08 / 16

What a Deployment gives you

  • Gradual replacement of old Pods with new Pods
  • Health-driven progression using readiness probes
  • Rollout history and rollback if the new version fails

Key commands

kubectl apply -f app.yaml
kubectl rollout status deploy/web
kubectl rollout history deploy/web
kubectl rollout undo deploy/web
Use readiness probes before traffic Never ship by deleting Pods manually Observe rollout status every time
Lab

Scenario: deploy a full app to Kubernetes

09 / 16

Application topology

FrontendNginx or React UI
APIStateless Deployment
DatabaseUse existing managed DB or mock backend
ConfigMapApp mode, URLs, feature flags
SecretDB password, API key
ServiceStable frontend and API endpoints

Lab flow

  • Step 0: verify cluster access and create a dedicated namespace
  • Step 1: create ConfigMap and Secret for runtime configuration
  • Step 2: deploy the API using a Deployment and ClusterIP Service
  • Step 3: deploy the frontend and expose it outside the cluster
  • Step 4: test scaling, rolling update, rollback, and cleanup
Lab Runbook

Step 0: prepare the namespace and check the cluster

10 / 16
kubectl config current-context
kubectl get nodes
kubectl create namespace workloads-lab
kubectl get ns workloads-lab

kubectl config set-context --current \
  --namespace=workloads-lab

What each command does

  • kubectl config current-context: verify the active cluster
  • kubectl get nodes: confirm schedulable worker nodes
  • kubectl create namespace workloads-lab: isolate the lab objects
  • kubectl config set-context --current --namespace=workloads-lab: set the default namespace

Clean namespace scoping keeps the demo safe and makes cleanup simple.

Lab Runbook

Step 1: create shared config and secret data

11 / 16
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: workloads-lab
data:
  APP_MODE: "demo"
  API_BASE_URL: "http://api-service:8080"
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
  namespace: workloads-lab
type: Opaque
stringData:
  DB_PASSWORD: "ChangeMe123!"
  API_TOKEN: "demo-token-123"

Key idea

  • Create config first so Pods start with required values
  • ConfigMap stores non-sensitive runtime settings
  • Secret stores credentials and tokens
  • stringData keeps the manifest easier to author

Run

kubectl apply -f config.yaml
kubectl get configmap,secret
kubectl describe configmap app-config
Lab Runbook

Step 2: deploy the API and explain the Deployment fields

12 / 16
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: workloads-lab
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: ghcr.io/example/demo-api:v1
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        envFrom:
        - configMapRef:
            name: app-config
        - secretRef:
            name: app-secret
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
---
apiVersion: v1
kind: Service
metadata:
  name: api-service
  namespace: workloads-lab
spec:
  selector:
    app: api
  ports:
  - port: 8080
    targetPort: 8080
  type: ClusterIP

What to notice

  • replicas: 2 keeps the API available during restarts
  • selector must match Pod labels exactly
  • readinessProbe blocks traffic until the app is ready
  • envFrom injects ConfigMap and Secret values
  • api-service becomes the stable internal endpoint

Run

kubectl apply -f api.yaml
kubectl get deploy,rs,pods,svc
kubectl describe deployment api
kubectl logs deploy/api --tail=20
Lab Runbook

Step 3: deploy the frontend and expose the app externally

13 / 16
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: workloads-lab
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: frontend
        image: ghcr.io/example/demo-frontend:v1
        env:
        - name: API_BASE_URL
          value: "http://api-service:8080"
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
  namespace: workloads-lab
spec:
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30080
  type: NodePort

What to notice

  • The frontend is also a stateless Deployment
  • It reaches the API through the Service name, not a Pod IP
  • NodePort is fine for labs; use LoadBalancer or Ingress in production
  • This step connects internal service discovery to external access

Run

kubectl apply -f frontend.yaml
kubectl get pods,svc
kubectl get endpoints
kubectl port-forward svc/frontend-service 8088:80
Lab Runbook

Step 4: scale, roll forward, rollback, and clean up

14 / 16
kubectl scale deployment/api --replicas=3
kubectl get pods -w

kubectl set image deployment/api \
  api=ghcr.io/example/demo-api:v2
kubectl rollout status deployment/api
kubectl rollout history deployment/api

kubectl rollout undo deployment/api

kubectl delete namespace workloads-lab

What to notice

  • scale changes desired state at the controller level
  • set image triggers a rolling update
  • rollout status is the primary health check during release
  • rollout history shows revision history
  • rollout undo reverts a failed release
  • Deleting the namespace removes the entire lab cleanly

Check

  • Watch Pods and ReplicaSets before and after the update
  • Confirm the new image revision is active
  • Try rollback if the rollout stalls
Watch Outs

Common mistakes in workload design

15 / 16

Mistake 1

Creating naked Pods and calling that a deployment model.

Mistake 2

Hardcoding passwords or URLs into images instead of externalizing them.

Mistake 3

Skipping requests, limits, readiness checks, and rollout observation.

Quiz

5-minute knowledge check

16 / 16
1. Why is a Deployment preferred over creating Pods directly for stateless apps?
2. Which Service type would you use for internal pod-to-pod communication?
3. What is the difference between a ConfigMap and a Secret?
4. What happens when a container exceeds its memory limit?
5. Which command lets you roll back a failed Deployment rollout?

Takeaways

Deployment for stateless
Service for stable access
Config outside image
Limits for safety
Rolling updates for safer change