All topics
DevOps · Learning hub

Kubernetes notes for developers

Master Kubernetes with a curated set of 3 developer notes — core concepts, patterns, and interview prep. Maintained by the DevRecall team.

Save this stack to your DevRecallMore DevOps notes
Kubernetes

Core Concepts & kubectl

Core Concepts & kubectl Key Objects Pod — smallest deployable unit; one or more containers sharing network/storage Deployment — manages replicated Pods with rol

Core Concepts & kubectl

Key Objects

  • Pod — smallest deployable unit; one or more containers sharing network/storage

  • Deployment — manages replicated Pods with rolling updates and rollback

  • Service — stable network endpoint for a set of Pods (ClusterIP/NodePort/LoadBalancer)

  • ConfigMap — non-sensitive config data injected as env vars or files

  • Secret — sensitive data (base64 encoded, not encrypted by default — use Sealed Secrets or external secret managers)

  • Ingress — HTTP routing rules into cluster Services (requires an Ingress controller)

  • Namespace — virtual cluster for resource isolation (default, kube-system, etc.)

  • PersistentVolume / PVC — storage abstraction; PVC claims storage from a PV

kubectl Essentials

# Cluster info
kubectl cluster-info
kubectl get nodes
kubectl config current-context
kubectl config use-context my-cluster

# Namespaces
kubectl get namespaces
kubectl create namespace staging
kubectl -n staging get pods        # operate in a specific namespace
kubectl config set-context --current --namespace=staging  # set default ns

# Pods
kubectl get pods                   # list pods
kubectl get pods -o wide           # with IP and node
kubectl get pods --all-namespaces  # all namespaces
kubectl describe pod my-pod        # detailed info + events
kubectl logs my-pod                # view logs
kubectl logs my-pod -f             # follow logs
kubectl logs my-pod -c sidecar     # specific container
kubectl exec -it my-pod -- bash    # interactive shell
kubectl exec my-pod -- env         # run command
kubectl delete pod my-pod          # delete (will be recreated if in Deployment)

# Deployments
kubectl get deployments
kubectl describe deployment my-app
kubectl scale deployment my-app --replicas=5
kubectl rollout status deployment my-app
kubectl rollout history deployment my-app
kubectl rollout undo deployment my-app          # roll back
kubectl rollout undo deployment my-app --to-revision=2

# Apply / delete manifests
kubectl apply -f deployment.yaml
kubectl apply -f ./k8s/                # apply all files in directory
kubectl delete -f deployment.yaml
kubectl diff -f deployment.yaml        # see what would change

# Port forwarding (local access to pod/service)
kubectl port-forward pod/my-pod 8080:3000
kubectl port-forward service/my-service 8080:80

# Copy files
kubectl cp my-pod:/app/logs ./local-logs
kubectl cp ./file.txt my-pod:/tmp/

# Get resource as YAML
kubectl get deployment my-app -o yaml
kubectl get all -l app=my-app

Labels & Selectors

# Filter by label
kubectl get pods -l app=my-app
kubectl get pods -l env=prod,tier=frontend
kubectl get pods -l 'env in (prod,staging)'
kubectl get pods -l '!test'            # no 'test' label

# Label resources
kubectl label pod my-pod env=prod
kubectl label pod my-pod env-          # remove label
kubectl annotate pod my-pod team=backend
Kubernetes

Deployments, Services & Manifests

Deployments, Services & Manifests Deployment YAML apiVersion: apps/v1 kind: Deployment metadata: name: my-app namespace: production labels: app: my-app spec: re

Deployments, Services & Manifests

Deployment YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1           # extra pods during update
      maxUnavailable: 0     # no downtime
  template:
    metadata:
      labels:
        app: my-app
        version: "1.5"
    spec:
      containers:
        - name: app
          image: ghcr.io/myorg/myapp:1.5
          ports:
            - containerPort: 3000
          env:
            - name: NODE_ENV
              value: production
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: database-url
          envFrom:
            - configMapRef:
                name: app-config
          resources:
            requests:
              memory: "256Mi"
              cpu: "100m"
            limits:
              memory: "512Mi"
              cpu: "500m"
          readinessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 5
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 30
            periodSeconds: 10
          volumeMounts:
            - name: config-volume
              mountPath: /app/config
      volumes:
        - name: config-volume
          configMap:
            name: app-config-files

Service Types

# ClusterIP — internal only (default)
apiVersion: v1
kind: Service
metadata:
  name: my-app
spec:
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 3000
  type: ClusterIP

---
# LoadBalancer — external via cloud provider
apiVersion: v1
kind: Service
metadata:
  name: my-app-lb
spec:
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 3000
  type: LoadBalancer

---
# NodePort — expose on each node's IP (debugging only)
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 3000
      nodePort: 30080      # 30000-32767

Ingress

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

ConfigMap & Secret

# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  NODE_ENV: production
  PORT: "3000"
  LOG_LEVEL: info
  config.json: |
    {
      "timeout": 5000,
      "retries": 3
    }

---
# Secret (values are base64 encoded)
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  database-url: cG9zdGdyZXM6Ly8...   # base64
  jwt-secret: c2VjcmV0a2V5...

# Create from CLI
kubectl create secret generic app-secrets   --from-literal=database-url="postgres://..."   --from-literal=jwt-secret="mysecret"

kubectl create configmap app-config   --from-file=config.json   --from-literal=NODE_ENV=production
Kubernetes

Interview Questions

Kubernetes Interview Questions Q: What is the difference between a Pod and a Deployment? A Pod is the smallest unit — one or more containers with shared network

Kubernetes Interview Questions

Q: What is the difference between a Pod and a Deployment?

A Pod is the smallest unit — one or more containers with shared networking/storage. Running Pods directly is not recommended — if it crashes, it stays dead. A Deployment wraps Pods in a ReplicaSet that maintains a desired number of replicas, provides rolling updates, rollback capability, and auto-restarts failed Pods.

Q: What is the difference between liveness and readiness probes?

Liveness probe checks if the container is alive — if it fails, Kubernetes restarts the container. Readiness probe checks if the container is ready to serve traffic — if it fails, the Pod is removed from Service endpoints (no requests routed to it) but not restarted. Use readiness for warm-up; use liveness for deadlock detection.

Q: What is the difference between ClusterIP, NodePort, and LoadBalancer?

  • ClusterIP — internal DNS name, reachable only within the cluster

  • NodePort — exposes on every node at a static port (30000-32767), useful for testing

  • LoadBalancer — provisions a cloud load balancer (GKE, EKS, AKS); for production external traffic

Q: What is a namespace and why use it?

Namespaces provide virtual isolation within a cluster. Common uses: separate environments (dev/staging/prod in one cluster), team isolation, resource quota enforcement. Resources with the same name can coexist in different namespaces. ClusterIP services are DNS-resolvable across namespaces as service.namespace.svc.cluster.local.

Q: What is a rolling update and how does it work?

A rolling update gradually replaces old Pods with new ones. With maxSurge=1 and maxUnavailable=0: one new Pod is created (total N+1), waits for it to be ready, then terminates one old Pod — repeating until all are replaced. Zero-downtime deployment. kubectl rollout undo reverses it.

Q: What are resource requests and limits?

Requests are what the scheduler uses to find a node with enough capacity — the Pod is guaranteed this amount. Limits are the maximum a container can use before being throttled (CPU) or OOM-killed (memory). Always set both: requests too high wastes resources, too low causes scheduling failures; limits prevent noisy-neighbor problems.

Keep your Kubernetes knowledge sharp.

Save this stack to your personal DevRecall — add your own notes, track what you're learning, and share what you know with the community.

Get started — free forever