DevOps & Cloud Topic

Kubernetes Deployments: A Practical Guide with Health Checks

Kubernetes helps run workloads across a group of machines called a cluster. You describe the state you want. Controllers keep working to bring the live system towards it.

It can replace a failed container. It cannot fix broken code or make every database operation safe.

Four objects to understand

  • Pod: A unit that runs one or more closely related containers.
  • Deployment: Manages copies of suitable stateless Pods and their updates.
  • Service: Provides a stable way to reach matching Pods.
  • ConfigMap: Holds non-secret configuration.

Prepare a local lab

Use the app.py and Dockerfile from the Docker lesson. Install kind and kubectl from their official sites. kind runs a learning cluster using your local container engine.

docker build -t lecturre-web:1.0 .
kind create cluster --name lecturre-lab
kind load docker-image lecturre-web:1.0 --name lecturre-lab
kubectl --context kind-lecturre-lab cluster-info

The named context keeps these instructions aimed at the learning cluster. Do not remove that part when you also have real clusters configured.

Create a namespace

Save this as k8s/namespace.yaml:

apiVersion: v1
kind: Namespace
metadata:
  name: lecturre-lab

Add the complete web workload

Save this as k8s/web.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: web-config
  namespace: lecturre-lab
data:
  APP_VERSION: "1.0"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: lecturre-lab
spec:
  replicas: 2
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        runAsGroup: 10001
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: web
          image: lecturre-web:1.0
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: web-config
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
            limits:
              cpu: 250m
              memory: 128Mi
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: ["ALL"]
          startupProbe:
            httpGet:
              path: /health
              port: 8080
            failureThreshold: 12
            periodSeconds: 5
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: lecturre-lab
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

The Service selector matches the Pod label app: web. Its port 80 forwards to container port 8080. A wrong selector can leave a working Pod unreachable through the Service.

Apply and check

kubectl --context kind-lecturre-lab apply -f k8s/namespace.yaml
kubectl --context kind-lecturre-lab apply -f k8s/web.yaml
kubectl --context kind-lecturre-lab -n lecturre-lab rollout status deployment/web
kubectl --context kind-lecturre-lab -n lecturre-lab get pods,services
kubectl --context kind-lecturre-lab -n lecturre-lab port-forward service/web 8086:80

Open http://127.0.0.1:8086/health. Leave port-forward running while you test it. It is a local connection, not a public production endpoint.

Three different health questions

Startup: Has the app had enough time to start? Until it succeeds, the other probes wait.

Readiness: Should this Pod receive new Service traffic?

Liveness: Is the container stuck in a way that a restart may fix?

Our tiny app uses one endpoint for all three. A real app may need different checks. Making liveness depend on a failing external database can cause many needless restarts.

Resources and scaling

A CPU or memory request helps the scheduler place the Pod. A limit constrains usage. Memory above a limit can lead to a killed container. CPU limits can cause throttling.

You can practise manual scaling with kubectl --context kind-lecturre-lab -n lecturre-lab scale deployment/web --replicas=3.

A Horizontal Pod Autoscaler can change replica count based on metrics. Our optional hpa.yaml uses CPU, so the cluster needs a working metrics API. The CPU request is also important for its percentage calculation. A default kind cluster may need extra setup first.

Optional example, saved outside k8s as hpa.yaml. Apply it only after the metrics prerequisite works:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web
  namespace: lecturre-lab
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 1
  maxReplicas: 3
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

Updates, Helm and GitOps

For an update, build a new image tag, load or publish it, and update the manifest. Watch rollout status and user errors. Do not keep changing the contents behind one release tag.

Helm packages related manifests with configurable values. Kustomize changes a base without a template language. GitOps adds a controller that compares Git with the cluster. Learn the plain objects before adding these tools.

Production questions

Plan for node and zone failures, permissions, storage, network rules and backups. Multiple replicas on one laptop do not prove high availability. A Pod disruption budget helps with some voluntary disruptions, not every failure.

A Kubernetes Secret is not protected just because its value is base64-encoded. Use proper access controls, encryption settings and a suitable secret-management process.

Practice and cleanup

Change a selector in a copy of the manifest. Explain why the Service stops finding Pods. Restore it and check recovery.

When finished, stop port-forward and run kind delete cluster --name lecturre-lab to remove only this named local lab.

Official references and further reading

Reviewed on 25 October 2026. Tools change, so check the official documentation for the version you use.

DevOps learning roadmap · All DevOps & Cloud tutorials

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?