Kubernetes

Kubernetes - Medium

Page 2 of 4

Storage

Real production storage is dynamic, not a hand-provisioned PV per app. A StorageClass defines how to provision storage on demand - which provisioner to call, what disk type/IOPS tier, what happens to the underlying disk when the PVC is deleted (reclaimPolicy: Delete vs Retain). The moment a PVC references a StorageClass and no matching PV exists yet, the provisioner creates one automatically - nobody pre-creates PVs by hand in a cloud environment.

Access modes matter more than they look: ReadWriteOnce (one node, read/write - the common case for a database), ReadOnlyMany (many nodes, read-only), ReadWriteMany (many nodes, read/write - only supported by certain storage backends, e.g. NFS-backed classes, not typical cloud block storage). Trying to attach a ReadWriteOnce volume to Pods on two different nodes simultaneously is a real, common failure mode - the second Pod's volume mount just hangs.

Volume expansion lets a PVC's size be increased in place (if the StorageClass has allowVolumeExpansion: true) without recreating the Pod - edit the PVC's requested size and the underlying disk grows.

CSI (Container Storage Interface) is the standard plugin interface every modern storage provider implements against, decoupling Kubernetes core from any specific vendor's driver - this is why adding a new storage backend to a cluster today means installing a CSI driver, not patching Kubernetes itself.

kubectl get storageclass
kubectl patch pvc app-data -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'   # trigger expansion
kubectl describe pvc app-data       # check Conditions for resize progress/errors

Networking

EndpointSlices are the modern backing data for Service load-balancing (superseding the older single Endpoints object at scale) - each slice holds a batch of Pod IPs/ports for a Service, sharded so a Service with thousands of backing Pods doesn't create one giant object that has to be fully rewritten on every single Pod change.

Ingress solves a real gap: Services alone give you L4 (IP/port) load balancing, but HTTP routing (host-based, path-based, TLS termination) needs something L7-aware. An Ingress object declares routing rules ("/api goes to the api-service, / goes to the web-service, both under example.com"), and an Ingress Controller (nginx-ingress, Traefik, cloud-specific ones) is the actual running component that reads Ingress objects and configures a real reverse proxy accordingly - an Ingress object does nothing on its own without a controller watching for it.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80

NetworkPolicy is the Kubernetes-native firewall - by default, every Pod can talk to every other Pod in the cluster with no restriction at all. A NetworkPolicy scoped to a namespace or a label selector can lock that down: ingress rules (who's allowed to talk to these Pods), egress rules (what these Pods are allowed to talk to), matched by Pod selectors, namespace selectors, or raw IP blocks. NetworkPolicies are only enforced if the cluster's CNI plugin actually implements them - some do, some silently ignore them, which is a real, common gotcha worth verifying rather than assuming.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-from-other-namespaces
spec:
  podSelector: {}
  policyTypes: ["Ingress"]
  ingress:
    - from:
        - podSelector: {}     # only allow from Pods in the SAME namespace

Security

SecurityContext controls what a container is allowed to do at the OS level, applied at the Pod level (affects every container) or per-container (overrides the Pod-level setting):

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  readOnlyRootFilesystem: true
  capabilities:
    drop: ["ALL"]
  • runAsNonRoot / runAsUser - refuse to run as root inside the container (or force a specific UID) - root-in-container is still meaningfully more dangerous than a non-root user, especially combined with a container-escape vulnerability.
  • readOnlyRootFilesystem - the container's own filesystem is mounted read-only; only explicitly-mounted volumes are writable. Sharply limits what a compromised process can actually persist or modify.
  • Linux capabilities - rather than all-or-nothing root, Linux capabilities let you grant just the specific privileged operation a container needs (e.g. NET_BIND_SERVICE to bind a low port) - drop: ["ALL"] then add back only what's genuinely required, rather than the default (a surprisingly large capability set) staying implicitly granted.

Pod Security Standards (the built-in replacement for the deprecated PodSecurityPolicy) define three enforceable profiles - privileged (no restrictions), baseline (blocks known privilege escalations), restricted (locks down to current security best practice) - applied per-namespace via a label, and enforced automatically by the admission controller rather than needing a separate policy engine for basic cases.


    Welcome to OpsQuiz!

    Real scenario-based DevOps questions, hands-on practice, and clear explanations for every answer.