Skip to content

Notes02-Core Concepts

Core Concepts

Cluster architecture and the objects you create every day: Pods, ReplicaSets, Deployments, Namespaces, and Services, plus the kubectl forms that build them.

Updated Oct 1, 2026

Core Concepts Quick Notes





Cluster shape

A cluster is a control plane plus worker nodes. The control plane decides. Workers run your containers.

kubectl → kube-apiserver → etcd
↑
scheduler, controller-manager, cloud-controller-manager

worker: kubelet → container runtime (CRI) → containers
kube-proxy → Service forwarding rules

  • Every change goes through the API server. Controllers, the scheduler, and kubectl are clients of that API. They do not write to etcd themselves.


Control plane

  • kube-apiserver: REST front door. Authenticates the caller, authorizes the verb, runs admission, then persists the object in etcd. It is the only component that talks to etcd.
  • etcd: Consistent key-value store. Cluster state lives under the /registry prefix. Lose etcd and you lose the cluster’s memory. Snapshot a kubeadm member with ETCDCTL_API=3 etcdctl snapshot save /opt/etcd-backup.db against https://127.0.0.1:2379, using /etc/kubernetes/pki/etcd/ca.crt, server.crt, and server.key. snapshot restore writes a new data directory. Point the etcd static Pod’s hostPath and --data-dir at that directory and the kubelet restarts etcd.
  • kube-scheduler: Watches Pods with no nodeName and picks a node. It writes the binding back through the API. It does not start containers.
  • kube-controller-manager: A set of loops that reconcile desired state with actual state: ReplicaSet, Deployment, Node, Job, Namespace, EndpointSlice, ServiceAccount, and others. If a Pod disappears, the replica controller creates a replacement.
  • cloud-controller-manager: Cloud-only loops (load balancer Services, node addresses, routes). Absent on a kubeadm cluster with no cloud provider.

On a kubeadm cluster these run as static Pods in kube-system. Their manifests are files on the control-plane node:

/etc/kubernetes/manifests/kube-apiserver.yaml
/etc/kubernetes/manifests/etcd.yaml
/etc/kubernetes/manifests/kube-controller-manager.yaml
/etc/kubernetes/manifests/kube-scheduler.yaml

The kubelet on that node starts them even when the API server is down. That is how the control plane boots.


Worker node

  • kubelet: Agent on every node. Watches the API for Pods bound to this node, calls the runtime through CRI, mounts volumes, runs probes, and reports node status.
  • Container runtime: containerd is the usual CRI runtime (cri-o is the other common one). Docker Engine is a separate product. Kubernetes talks to the runtime only through CRI. On the node, crictl ps and crictl logs inspect containers.
  • kube-proxy: Programs the host so a Service’s virtual IP reaches ready Pods. Modes are iptables, ipvs, or nftables-based, depending on the cluster. It does not assign Pod IPs.
  • CNI plugin: Assigns each Pod an IP and connects that network namespace to the node (bridge, route, or overlay). Config lives in /etc/cni/net.d, binaries in /opt/cni/bin. After kubeadm init the node stays NotReady until a plugin is installed. Pod-to-Pod traffic is the CNI’s job. ClusterIP traffic is kube-proxy’s job, aimed at the Pod IPs the CNI already assigned.


Pods

  • What a Pod is: The smallest object the scheduler places. One Pod is one or more containers that share a network namespace, IPC, and volumes, and that share a lifecycle.
  • One IP: Containers in the same Pod reach each other on localhost and must use different ports. Two containers that both bind :80 will not start.
  • Typical shape: One application container. Extra containers share the Pod IP and any volumes you mount into more than one of them.
    • Sidecar: Helps the app for the whole Pod lifetime (ships logs from a shared volume, refreshes certificates).
    • Adapter: Rewrites the app’s output into the shape the rest of the system expects.
    • Ambassador: Proxies outbound calls. The app talks to localhost. The ambassador opens the remote connection.
    • Init container: Runs to completion, in list order, before app containers start. The next init starts only after the previous one exits 0. Use one to wait for a dependency, run a migration, or prepare a volume. A failing init retries according to restartPolicy. App containers stay stopped until every init succeeds.
  • Ephemeral: A Pod is not repaired in place. If the node dies, a controller creates a new Pod with a new IP. Stable names and disks belong to higher-level objects (Deployment, StatefulSet, PVC).
  • Phases: Pending (accepted, not running yet), Running, Succeeded, Failed, Unknown.


bash
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.27
    ports:
    - containerPort: 80


containerPort is documentation for humans and for probes. It does not publish the port on the node. A Service does that.


ReplicaSets

  • Job: Keep a stable count of Pods that match a selector.
  • You rarely create one by hand. A Deployment owns ReplicaSets, one per revision.
  • Selector must match the Pod template labels. If it does not, the API rejects the object.
  • Orphans: A ReplicaSet adopts existing Pods whose labels match. That is why changing labels on a live Pod can move it between controllers.


bash
kubectl get rs
kubectl scale rs frontend --replicas=4


Deployments

  • Job: Declarative updates of a Pod template. Each change creates a new ReplicaSet and shifts replicas according to the strategy.
  • RollingUpdate (default): New Pods come up while old ones are removed. maxUnavailable (often 25%) is how many Pods may be down. maxSurge (often 25%) is how many extra Pods may exist above replicas. kubectl set image deployment/web nginx=nginx:1.28 starts a rollout. kubectl rollout status, rollout history, and rollout undo follow it. Undo scales the previous ReplicaSet back up. History is kept while revisionHistoryLimit is above 0 (default 10).
  • Recreate: Kill the old Pods, then start the new ones. A gap in availability, used when two versions must not run together.


bash
kubectl create deployment web --image=nginx:1.27 --replicas=3
kubectl get deploy,rs,pods
kubectl scale deployment web --replicas=5


Namespaces

  • What they are: A naming and policy boundary inside one cluster. Object names only need to be unique inside the namespace.
  • Built-in: default (where your objects go if you omit -n), kube-system (control plane and addons), kube-public (readable cluster-wide, including unauthenticated in some setups), kube-node-lease (node heartbeats).
  • Namespaced objects: Pods, Services, Deployments, ConfigMaps, Secrets, Roles, RoleBindings, NetworkPolicies, PVCs.
  • Cluster-scoped objects: Nodes, Namespaces, PersistentVolumes, StorageClasses, ClusterRoles, ClusterRoleBindings.
  • DNS: A Service named web in shop is web.shop.svc.cluster.local.
  • Not a security boundary by themselves. Isolation needs RBAC and NetworkPolicy. ResourceQuota and LimitRange cap what a namespace may consume.


bash
kubectl create namespace shop
kubectl get pods -n shop
kubectl config set-context --current --namespace=shop



Services

A Service gives a stable virtual IP and DNS name to a changing set of Pods.

Type

What you get

Typical use

ClusterIP

VIP reachable only inside the cluster. Default.

Pod-to-Pod calls

NodePort

ClusterIP plus a port on every node (default range 30000–32767)

Labs, or a load balancer you run yourself

LoadBalancer

NodePort plus an external load balancer, when a cloud controller exists

North-south traffic on a cloud cluster

ExternalName

DNS CNAME to an external host. No proxy, no selectors

Alias to a name outside the cluster

  • Selector: Labels that choose member Pods. kubectl get endpointslices shows the ready addresses kube-proxy uses.
  • Empty endpoints: The selector matches nothing, or the Pods are not Ready. Traffic to the ClusterIP is blackholed.
  • Headless: clusterIP: None. DNS returns the Pod IPs directly. Used with StatefulSets.
  • targetPort: Port on the container. port: Port on the Service VIP. They can differ.
  • kube-proxy installs the forwarding rules. CoreDNS publishes the name. Neither is optional if you want “normal” Service behavior.


bash
kubectl expose deployment web --port=80 --target-port=80 --name=web
kubectl expose deployment web --type=NodePort --port=80 --name=web-ext



yaml
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
  - port: 80
    target-port: 80


Imperative kubectl you will actually type


bash
kubectl run nginx --image=nginx --port=80
kubectl create deployment web --image=nginx:1.27 --replicas=2
kubectl create service clusterip web --tcp=80:80
kubectl create namespace dev
kubectl label pod nginx env=prod --overwrite
kubectl annotate pod nginx owner=platform
kubectl set image deployment/web nginx=nginx:1.28
kubectl delete pod nginx --force --grace-period=0

# correct YAML without applying it
kubectl create deployment web --image=nginx --dry-run=client -o yaml > web.yaml
kubectl apply -f web.yaml
kubectl explain deployment.spec.strategy
kubectl get deploy web -o yaml
kubectl api-resources | head


  • kubectl run creates a Pod (older tutorials sometimes imply a Deployment; current kubectl creates a Pod).
  • create deployment creates a Deployment. Prefer that when you want replicas and rollouts.
  • --dry-run=client -o yaml is the fastest way to get a valid manifest you can edit (add a volume, a probe, a nodeSelector).


Object model in one line

  • Spec: what you asked for.
  • Status: what the controllers last observed.
  • metadata.labels: used by selectors (Services, ReplicaSets, NetworkPolicies).
  • metadata.annotations: arbitrary notes. Selectors ignore them.
  • ownerReferences: why a deleted Deployment also deletes its ReplicaSets and Pods (garbage collection).


Official docs