Kubernetes DevOps

☸️ Kubernetes Architecture & Orchestration

ℹ️

Version Coverage This article covers Kubernetes v1.28+. Commands and APIs may differ for older cluster versions. Always verify with kubectl version.

Kubernetes (K8s) is an open-source container orchestration platform developed by Google and now maintained by the Cloud Native Computing Foundation (CNCF). It automates the deployment, scaling, and management of containerized applications across clusters of machines.

Architecture Overview

A Kubernetes cluster is composed of a control plane and one or more worker nodes. The control plane manages the cluster state, while worker nodes run your application workloads.

Control Plane Components

  • kube-apiserver β€” The front-end for the Kubernetes API. All kubectl commands and internal components communicate through it.
  • etcd β€” A highly available key-value store that persists all cluster state and configuration data.
  • kube-scheduler β€” Watches for unscheduled pods and assigns them to nodes based on resource requirements, affinity rules, and policies.
  • kube-controller-manager β€” Runs controller loops that reconcile the current state of the cluster toward the desired state.
  • cloud-controller-manager β€” Integrates with the underlying cloud provider's API for load balancers, volumes, and node management.

Node Components

  • kubelet β€” An agent on each node that ensures containers are running in Pods as declared in PodSpecs.
  • kube-proxy β€” Maintains network rules on nodes using iptables or IPVS to enable Service communication.
  • Container runtime β€” The software responsible for running containers (containerd, CRI-O).

Pods & Workloads

A Pod is the smallest deployable unit in Kubernetes β€” a group of one or more containers that share network and storage. Pods are ephemeral by design; controllers manage their lifecycle.

yaml
# pod.yaml β€” basic nginx Pod
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  namespace: production
  labels:
    app: nginx
    version: "1.25"
spec:
  containers:
    - name: nginx
      image: nginx:1.25-alpine
      ports:
        - containerPort: 80
      resources:
        requests:
          cpu: "100m"
          memory: "128Mi"
        limits:
          cpu: "500m"
          memory: "256Mi"
      livenessProbe:
        httpGet:
          path: /healthz
          port: 80
        initialDelaySeconds: 10
        periodSeconds: 15
      readinessProbe:
        httpGet:
          path: /ready
          port: 80
        initialDelaySeconds: 5
        periodSeconds: 10

Deployments

A Deployment provides declarative updates for Pods and ReplicaSets, enabling rolling updates, rollbacks, and scaling.

yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
  namespace: production
  labels:
    app: api-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-server
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: api-server
        version: "2.1.0"
    spec:
      containers:
        - name: api
          image: registry.maxiscomputers.com/api-server:2.1.0
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: api-config
            - secretRef:
                name: api-secrets
          resources:
            requests:
              cpu: "250m"
              memory: "512Mi"
            limits:
              cpu: "1"
              memory: "1Gi"

Services & Networking

Services provide stable network endpoints for a set of Pods. Since Pods are ephemeral and their IPs change, Services use label selectors to abstract and expose them.

Service Types

  • ClusterIP β€” Default. Exposes the service on an internal cluster IP. Only reachable within the cluster.
  • NodePort β€” Exposes the service on each node's IP at a static port (30000–32767).
  • LoadBalancer β€” Creates an external load balancer in cloud providers. Assigns a public IP.
  • ExternalName β€” Maps the service to a DNS name outside the cluster.
yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: api-service
  namespace: production
spec:
  selector:
    app: api-server
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.maxiscomputers.com
      secretName: api-tls-secret
  rules:
    - host: api.maxiscomputers.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80

Storage

Kubernetes abstracts storage through PersistentVolumes (PV), PersistentVolumeClaims (PVC), and StorageClasses. ConfigMaps and Secrets are used for configuration data.

yaml
# pvc.yaml β€” dynamic provisioning
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: database-pvc
  namespace: production
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: gp3-encrypted
  resources:
    requests:
      storage: 50Gi
---
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: api-config
  namespace: production
data:
  APP_ENV: "production"
  LOG_LEVEL: "warn"
  API_PORT: "8080"
  DB_HOST: "postgres-service.production.svc.cluster.local"

RBAC & Security

Role-Based Access Control (RBAC) restricts who can perform which operations on which resources. It uses four key objects: Role, ClusterRole, RoleBinding, and ClusterRoleBinding.

yaml
# rbac.yaml β€” least-privilege role for CI/CD service account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: cicd-deployer
  namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployer-role
  namespace: production
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "update", "patch"]
  - apiGroups: [""]
    resources: ["pods", "services"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cicd-deployer-binding
  namespace: production
subjects:
  - kind: ServiceAccount
    name: cicd-deployer
    namespace: production
roleRef:
  kind: Role
  name: deployer-role
  apiGroup: rbac.authorization.k8s.io

Helm Charts

Helm is the package manager for Kubernetes. Charts bundle Kubernetes manifests into reusable, versioned packages with templating support.

bash
# Install a chart
helm install my-release ./charts/api-server \
  --namespace production \
  --create-namespace \
  --values values.production.yaml \
  --set image.tag=2.1.0

# Upgrade with zero-downtime
helm upgrade my-release ./charts/api-server \
  --namespace production \
  --values values.production.yaml \
  --set image.tag=2.2.0 \
  --atomic \
  --timeout 5m

# Rollback to previous version
helm rollback my-release 1 --namespace production

# List all releases
helm list --all-namespaces

kubectl Reference

Essential kubectl commands for daily cluster operations:

bash
# --- Context Management ---
kubectl config get-contexts
kubectl config use-context prod-cluster
kubectl config set-context --current --namespace=production

# --- Pod Operations ---
kubectl get pods -n production -o wide
kubectl describe pod api-server-7d6f8b9c-xkp2l -n production
kubectl logs -f api-server-7d6f8b9c-xkp2l -n production --tail=100
kubectl exec -it api-server-7d6f8b9c-xkp2l -n production -- /bin/sh

# --- Deployment Operations ---
kubectl rollout status deployment/api-server -n production
kubectl rollout history deployment/api-server -n production
kubectl rollout undo deployment/api-server -n production
kubectl scale deployment api-server --replicas=5 -n production

# --- Resource Inspection ---
kubectl top nodes
kubectl top pods -n production
kubectl get events -n production --sort-by=.metadata.creationTimestamp

# --- Apply & Delete ---
kubectl apply -f ./manifests/ --dry-run=client
kubectl apply -f ./manifests/
kubectl delete -f ./manifests/

Production Best Practices

⚠️

Resource Limits Always set CPU and memory requests/limits on every container. Unbounded containers can destabilize the entire node.

  • Use namespaces to isolate environments (dev, staging, production) within the same cluster.
  • Enable Pod Disruption Budgets (PDB) to guarantee minimum availability during rolling updates and node drains.
  • Use Horizontal Pod Autoscaler (HPA) with CPU/memory metrics and custom metrics via KEDA for dynamic scaling.
  • Secure secrets with external secret managers (AWS Secrets Manager, HashiCorp Vault) instead of base64-encoded Kubernetes Secrets.
  • Implement NetworkPolicies to restrict Pod-to-Pod communication and enforce zero-trust networking.
  • Use readiness and liveness probes on all workloads to prevent traffic routing to unhealthy Pods.
  • Monitor with Prometheus + Grafana and set alerts on SLI/SLO metrics.
  • Tag all resources with app, version, environment, and managed-by labels for observability and cost attribution.
πŸ’‘

Pro Tip Use kubectl neat plugin to strip cluster-managed fields from manifests when exporting resources for GitOps repositories.