Docker · Kubernetes · Grafana · ArgoCD · AWS

🏗️ Cluster Architecture

Kubernetes Cluster ┌─────────────────────────────────────────────────────────────────┐ │ Control Plane (Master Node) │ │ ├── API Server ← all kubectl commands go here │ │ ├── etcd ← cluster state database │ │ ├── Scheduler ← decides which node to run pods on │ │ └── Controller Manager← watches cluster and reconciles state │ └──────────────────────────────────────────────────────────────────┘ │ │ │ ┌───────────┐ ┌──────────┐ ┌───────────┐ │ Worker Node 1│ │ Worker Node 2│ │ Worker Node 3│ │ ├─ kubelet │ │ ├─ kubelet│ │ ├─ kubelet │ ← node agent │ ├─ kube-proxy ├─ kube-proxy ├─ kube-proxy ← network rules │ │ │ │ │ │ │ │ │ Pod A │ │ Pod B │ │ Pod C │ │ │ [app:v2] │ │ [app:v2] │ │ [db:16] │ └───────────┘ └──────────┘ └───────────┘

🧱 Core Objects

ObjectWhat It DoesYAML Kind
PodSmallest unit — one or more containers sharing a network and volumesPod
DeploymentManages a set of identical pods, handles rolling updates and rollbacksDeployment
ServiceStable DNS name + load balancing to a group of pods (via label selector)Service
ConfigMapNon-secret config data (env vars, config files)ConfigMap
SecretSensitive data (passwords, API keys) — base64 encodedSecret
NamespaceVirtual cluster — isolates resources (dev / staging / prod)Namespace
PersistentVolumeClaimRequest for storage — bound to a PersistentVolumePersistentVolumeClaim
HorizontalPodAutoscalerAuto-scale pod count based on CPU/memoryHorizontalPodAutoscaler
IngressHTTP routing rules — routes external traffic to servicesIngress

⌨️ kubectl Basics

# ── Context & Cluster ──────────────────────────────────
kubectl config get-contexts           # list all clusters
kubectl config use-context my-cluster # switch cluster
kubectl cluster-info                  # show cluster endpoints

# ── Get resources ──────────────────────────────────────
kubectl get pods                      # pods in default namespace
kubectl get pods -n kube-system       # pods in a namespace
kubectl get pods -A                   # pods in ALL namespaces
kubectl get pods -o wide              # with node + IP
kubectl get all -n myapp              # everything in namespace

# ── Describe (detailed info + events) ─────────────────
kubectl describe pod my-pod-abc123
kubectl describe deployment web
kubectl describe service db

# ── Logs ───────────────────────────────────────────────
kubectl logs my-pod-abc123            # logs from pod
kubectl logs -f my-pod-abc123         # stream logs
kubectl logs deployment/web           # logs from any pod in deployment
kubectl logs my-pod -c sidecar        # multi-container pod — pick container
kubectl logs -l app=web --tail=100    # logs from all pods with label

# ── Shell into a pod ────────────────────────────────────
kubectl exec -it my-pod-abc123 -- bash
kubectl exec -it my-pod-abc123 -- sh
kubectl exec -it deployment/web -- bash

# ── Apply / Delete ──────────────────────────────────────
kubectl apply -f deployment.yaml      # create or update
kubectl apply -f ./manifests/         # apply whole directory
kubectl delete -f deployment.yaml     # delete from file
kubectl delete pod my-pod-abc123      # delete specific resource
kubectl delete pod -l app=web         # delete by label

# ── Scale ───────────────────────────────────────────────
kubectl scale deployment web --replicas=5
kubectl scale deployment web --replicas=0  # stop all pods

# ── Port forward ────────────────────────────────────────
kubectl port-forward pod/my-pod 8080:8080
kubectl port-forward service/web 8080:80
kubectl port-forward deployment/api 3000:3000

# ── Rollout ─────────────────────────────────────────────
kubectl rollout status deployment/web
kubectl rollout history deployment/web
kubectl rollout undo deployment/web   # rollback

🫁 Pod

apiVersion: v1
kind: Pod
metadata:
  name: myapp
  namespace: default
  labels:
    app: myapp
    version: "1.0"
spec:
  containers:
  - name: app
    image: myapp:1.0
    ports:
    - containerPort: 8080
    env:
    - name: LOG_LEVEL
      value: "info"
    - name: DB_PASSWORD           # from a Secret
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: password
    resources:
      requests:
        cpu: "100m"               # 100 millicores = 0.1 CPU
        memory: "128Mi"
      limits:
        cpu: "500m"
        memory: "512Mi"
    livenessProbe:                # restart container if this fails
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 15
    readinessProbe:               # remove from Service if not ready
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10

🚀 Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web               # must match pod template labels
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1      # at most 1 pod down during update
      maxSurge: 1            # at most 1 extra pod during update
  template:
    metadata:
      labels:
        app: web             # Service selector targets this
    spec:
      containers:
      - name: web
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests: { cpu: "50m",  memory: "64Mi"  }
          limits:   { cpu: "200m", memory: "256Mi" }
      - name: log-sidecar    # sidecar container in same pod
        image: fluentd:latest
        volumeMounts:
        - name: logs
          mountPath: /logs
      volumes:
      - name: logs
        emptyDir: {}         # shared between containers, wiped on pod deletion

🔌 Service

# ClusterIP — internal only (default)
apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: myapp
spec:
  selector:
    app: web                 # routes to pods with this label
  ports:
  - name: http
    port: 80                 # service port (what you curl)
    targetPort: 8080         # pod port
---
# NodePort — accessible on every node at nodePort
spec:
  type: NodePort
  selector: { app: web }
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30080          # 30000–32767
---
# LoadBalancer — creates a cloud load balancer (AWS/GCP/Azure)
spec:
  type: LoadBalancer
  selector: { app: web }
  ports:
  - port: 80
    targetPort: 8080
Service TypeReachable FromUse When
ClusterIPInside cluster onlyService-to-service communication
NodePortNode IP + portDev/testing, local kind clusters
LoadBalancerPublic IP (cloud)Production on AWS/GCP/Azure
ExternalNameDNS aliasBridge to external service via DNS

🔐 ConfigMap & Secret

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: myapp
data:
  LOG_LEVEL: "info"
  CACHE_TTL: "300"
  config.json: |
    { "feature_flags": { "new_ui": true } }
---
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
  namespace: myapp
type: Opaque
stringData:                    # plain text — k8s encodes to base64
  DB_HOST: "postgres.myapp.svc.cluster.local"
  DB_PASSWORD: "supersecret"
  DB_USER: "appuser"
# Create from literals
kubectl create secret generic db-secret \
  --from-literal=DB_PASSWORD=secret123 \
  --from-literal=DB_USER=appuser

# Create from file
kubectl create secret generic tls-secret \
  --from-file=tls.crt=./cert.pem \
  --from-file=tls.key=./key.pem

# Read a secret value
kubectl get secret db-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -d

💾 Volumes & PVCs

# 1. Claim storage
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-data
  namespace: myapp
spec:
  accessModes:
  - ReadWriteOnce             # mounted by one node at a time
  resources:
    requests:
      storage: 10Gi
  storageClassName: standard  # or gp2 on AWS, standard on kind
---
# 2. Mount it in a pod
spec:
  containers:
  - name: postgres
    image: postgres:16
    volumeMounts:
    - name: data
      mountPath: /var/lib/postgresql/data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: postgres-data

📁 Namespaces

# Create namespace
kubectl create namespace staging

# Set default namespace for your session
kubectl config set-context --current --namespace=staging

# All commands respect namespace
kubectl get pods -n staging
kubectl apply -f . -n staging

# Cross-namespace DNS
# web.staging.svc.cluster.local  →  service "web" in namespace "staging"
# Full form: ..svc.cluster.local

📈 Autoscaling (HPA)

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
  namespace: myapp
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 2
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60   # scale out when avg CPU > 60%
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70
kubectl get hpa -n myapp
kubectl describe hpa web-hpa -n myapp

📌 kubectl Cheat Sheet

TaskCommand
List pods (all namespaces)kubectl get pods -A
Watch pod restarts livekubectl get pods -w
Describe a pod (events + config)kubectl describe pod NAME
Shell into podkubectl exec -it NAME -- bash
Stream logskubectl logs -f NAME
Forward portkubectl port-forward svc/NAME 8080:80
Apply manifestkubectl apply -f file.yaml
Delete resourcekubectl delete -f file.yaml
Scale deploymentkubectl scale deploy NAME --replicas=3
Rollback deploymentkubectl rollout undo deploy/NAME
Get events (sorted)kubectl get events --sort-by=.lastTimestamp
Get resource YAMLkubectl get deploy NAME -o yaml
Edit live resourcekubectl edit deployment NAME
Force restart podskubectl rollout restart deploy/NAME
Show node resourceskubectl top nodes
Show pod resourceskubectl top pods -A