Back to Blog

Kubernetes and Container Orchestration Guide

A practical introduction to Kubernetes for development teams ready to move beyond manual container management to production-grade orchestration.

Why Containers Changed Everything

Before containers, deploying an application meant configuring a server, installing dependencies, managing conflicts between application versions, and hoping that what worked on the developer’s laptop would work in production. Containers solved this by packaging the application, its dependencies, and its runtime environment into a single portable unit.

Docker made containers accessible. But running a few containers on a single server is simple. Running dozens or hundreds of containers across multiple servers, keeping them healthy, scaling them based on demand, and updating them without downtime requires orchestration. That is where Kubernetes comes in.

Kubernetes Architecture

The Control Plane

Kubernetes operates on a master-worker model. The control plane manages the cluster:

  • API Server: The front door for all management commands. Every kubectl command talks to this component.
  • etcd: A distributed key-value store that holds all cluster state. If etcd loses data, the cluster loses its memory.
  • Scheduler: Decides which worker node should run a new pod based on resource availability, affinity rules, and constraints.
  • Controller Manager: Runs background loops that ensure the actual state matches the desired state. If you request three replicas and one dies, the controller creates a replacement.

Worker Nodes

Each worker node runs:

  • kubelet: An agent that receives instructions from the control plane and manages pods on the node
  • Container runtime: The software that actually runs containers (containerd, CRI-O)
  • kube-proxy: Handles network rules so pods can communicate with each other and with external clients

The Pod

The pod is the smallest deployable unit in Kubernetes. A pod contains one or more containers that share networking and storage:

apiVersion: v1
kind: Pod
metadata:
  name: web-app
  labels:
    app: web
    tier: frontend
spec:
  containers:
    - name: app
      image: registry.example.com/web-app:1.4.2
      ports:
        - containerPort: 3000
      resources:
        requests:
          memory: "128Mi"
          cpu: "250m"
        limits:
          memory: "256Mi"
          cpu: "500m"
      livenessProbe:
        httpGet:
          path: /health
          port: 3000
        initialDelaySeconds: 10
        periodSeconds: 15

Always set resource requests and limits. Without them, a single misbehaving pod can consume all node resources and starve everything else.

Essential Kubernetes Objects

Deployments

You rarely create pods directly. Instead, you create a Deployment that manages a set of identical pods:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: app
          image: registry.example.com/web-app:1.4.2
          ports:
            - containerPort: 3000

The Deployment ensures three replicas are always running. When you update the image version, it performs a rolling update: bringing up new pods before terminating old ones. The maxUnavailable: 0 setting means zero downtime during updates.

Services

Pods get random IP addresses that change when they restart. A Service provides a stable network endpoint:

apiVersion: v1
kind: Service
metadata:
  name: web-app-service
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 3000

Service types include:

  • ClusterIP: Internal only. Other pods in the cluster can reach it.
  • NodePort: Exposes the service on each node’s IP at a static port.
  • LoadBalancer: Creates an external load balancer (works with cloud providers).

ConfigMaps and Secrets

Externalize configuration from your container images:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: "postgres-service"
  LOG_LEVEL: "info"
  CACHE_TTL: "300"

Secrets work similarly but base64-encode the values and can be encrypted at rest:

apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  DATABASE_PASSWORD: cGFzc3dvcmQxMjM=

Never commit Secret manifests with real values to version control. Use external secret management tools like Sealed Secrets or integrate with your cloud provider’s secret manager.

Scaling and Auto-scaling

Horizontal Pod Autoscaler

Scale pods based on CPU utilization, memory usage, or custom metrics:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

This maintains two to ten replicas, adding pods when average CPU exceeds 70% and removing them when it drops.

Cluster Autoscaler

When pods cannot be scheduled because no node has sufficient resources, the Cluster Autoscaler provisions additional nodes from your cloud provider. When nodes are underutilized, it drains and removes them.

Networking

Ingress Controllers

An Ingress defines external access to services, typically HTTP/HTTPS routing:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
    - hosts:
        - app.example.com
      secretName: app-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-app-service
                port:
                  number: 80

Popular ingress controllers include NGINX, Traefik, and cloud-native options like AWS ALB Ingress Controller.

Network Policies

By default, every pod can communicate with every other pod. Network Policies restrict this:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-policy
spec:
  podSelector:
    matchLabels:
      app: api
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: web
      ports:
        - port: 8080

This allows only pods labeled app: web to connect to the API pods on port 8080. All other traffic is denied.

Observability

The Three Pillars

Running containers in production requires visibility into what is happening:

  1. Logging: Aggregate logs from all pods into a centralized system (ELK stack, Grafana Loki)
  2. Metrics: Collect CPU, memory, request rates, and error rates (Prometheus + Grafana)
  3. Tracing: Follow requests across multiple services (Jaeger, Zipkin)

Health Checks

Kubernetes uses probes to determine pod health:

  • Liveness probe: Is the container still running? If it fails, Kubernetes restarts the container.
  • Readiness probe: Is the container ready to receive traffic? If it fails, the pod is removed from the service endpoint.
  • Startup probe: Has the container finished starting up? Useful for slow-starting applications.

Configure all three for production workloads. A pod without health checks is a pod that Kubernetes cannot self-heal.

Production Readiness Checklist

Before running workloads in production:

  • Resource requests and limits set for all containers
  • Liveness and readiness probes configured
  • Pod Disruption Budgets defined for critical services
  • Network Policies restricting unnecessary communication
  • Secrets managed externally, not in plain text manifests
  • Logging, metrics, and alerting in place
  • Horizontal Pod Autoscaler configured for variable workloads
  • Namespace isolation between environments (dev, staging, production)
  • RBAC policies limiting who can do what in each namespace
  • Backup and disaster recovery procedures tested

Getting Started

Start small. Containerize one application, deploy it to a managed Kubernetes service (GKE, EKS, AKS, or a local cluster with k3s), and learn the workflow. Add complexity incrementally: services, ingress, autoscaling, monitoring.

Kubernetes has a steep learning curve, but the operational benefits for production workloads are substantial. Automated healing, rolling updates, scaling, and resource management free your team to focus on building applications rather than babysitting servers.

Baca dalam Bahasa Indonesia Versi Indonesia