CNI, CSI and CRI
The three plugin interfaces that run containers, wire Pod networks and attach storage: where each lives on a node, which component calls it, and where it shows up when something breaks.
After this lesson
- 01You can find a node's container runtime, its endpoint and its configuration, and use crictl to inspect pods and containers below the API.
- 02You can locate the CNI configuration and plugin binaries on a node and explain how a new Pod gets its network.
- 03You can read CSIDriver, CSINode and StorageClass objects and map a storage, network or runtime symptom to the right interface.
The competency is Understand extension interfaces (CNI, CSI, CRI, etc.). Kubernetes does not run containers, build Pod networks or attach disks itself. The kubelet calls a container runtime through the CRI, the runtime calls network plugins through the CNI, and storage vendors plug in through the CSI. Exam tasks here are short and concrete: find a value on a node and write it to a file, use crictl where kubectl cannot reach, or recognize which interface a broken node or Pod is pointing at. On this lab a node shell is docker exec -it cka-worker bash; on the exam it is ssh <node>, usually followed by sudo -i.
CRI: the kubelet talks to a runtime, not to Docker
Since dockershim was removed in v1.24, every node runs a CRI runtime, almost always containerd or CRI-O. The kubelet finds it through containerRuntimeEndpoint in its config file /var/lib/kubelet/config.yaml; older kubeadm clusters may still pass the deprecated --container-runtime-endpoint flag in /var/lib/kubelet/kubeadm-flags.env. crictl talks to the same socket (set in /etc/crictl.yaml) and shows what the runtime sees, which is what you need when the API server or kubelet is down. kubeadm clusters use the systemd cgroup driver, so containerd's runc options set SystemdCgroup = true. containerd 2.x keeps CRI settings under plugins.'io.containerd.cri.v1.runtime'; files written for containerd 1.x use version = 2 and plugins."io.containerd.grpc.v1.cri", and containerd config dump prints the effective result either way.
docker exec -it cka-worker bash # exam: ssh <node>, then sudo -i
grep containerRuntimeEndpoint /var/lib/kubelet/config.yaml
cat /var/lib/kubelet/kubeadm-flags.env # extra kubelet flags kubeadm wrote
cat /etc/crictl.yaml # runtime-endpoint crictl uses
systemctl status containerd --no-pager
grep -nE 'SystemdCgroup|sandbox|snapshotter' /etc/containerd/config.toml
containerd config dump | grep -A4 "cri.v1.runtime'.cni]"
crictl pods --namespace kube-system # pod sandboxes (POD ID)
crictl ps -a --name coredns # containers, including exited ones (CONTAINER)
crictl ps --name web --no-trunc -q # full 64-character IDs only
crictl inspect <container-id> | grep -m1 '"pid"'
crictl logs --tail 20 <container-id>
crictl images
crictl pull busybox:1.36CNI: how a Pod gets its network
When the kubelet asks the runtime for a new Pod sandbox, containerd creates a network namespace, reads the first file in lexical order in /etc/cni/net.d (.conflist, .conf or .json), and executes the binaries named by each plugin's type from /opt/cni/bin. The kubelet does not load CNI itself any more; it only reports what the runtime says, which is why a node without a CNI config stays NotReady with cni plugin not initialized. A network add-on like Calico ships as a DaemonSet whose init containers drop the binaries and the config onto every node, and whose agent programs routes and NetworkPolicy. A leftover file such as 05-old.conf sorts before 10-calico.conflist and wins, a classic cause of Pods getting the wrong network.
docker exec cka-worker ls -l /etc/cni/net.d # 10-calico.conflist and calico-kubeconfig
docker exec cka-worker cat /etc/cni/net.d/10-calico.conflist # plugins: "calico" (ipam "calico-ipam"), then "portmap"
docker exec cka-worker ls /opt/cni/bin # calico, calico-ipam, host-local, loopback, portmap, ...
docker exec cka-worker tail -5 /var/log/calico/cni/cni.log
kubectl -n kube-system get ds calico-node
kubectl -n kube-system get pods -l k8s-app=calico-node -o wide
kubectl describe node cka-worker | grep -iE 'networkunavailable|ready'CSI: storage drivers outside the tree
A CSI driver usually has two parts: a node plugin DaemonSet that registers its socket with the kubelet and performs mounts, and a controller Deployment whose sidecars watch PVCs and VolumeAttachments to create, attach, resize and snapshot volumes. A StorageClass names the driver in provisioner (for example ebs.csi.aws.com). The CSIDriver object describes the driver's capabilities, and each node's CSINode lists the drivers registered there. Not every provisioner is CSI: this lab's standard class uses rancher.io/local-path, an external provisioner that creates hostPath-backed volumes, so kubectl get csidrivers returns nothing here and every CSINode shows zero drivers.
kubectl get csidrivers
kubectl get csinode
kubectl get csinode cka-worker -o jsonpath='{.spec.drivers[*].name}'
kubectl get storageclass -o custom-columns=NAME:.metadata.name,PROVISIONER:.provisioner,BINDING:.volumeBindingMode
kubectl get volumeattachments
kubectl -n local-path-storage get deploy,pods # the provisioner behind "standard"
kubectl describe pvc <name> | tail -5 # "waiting for a volume to be created by ..." names the provisionerIn the docs · the tab you get on exam day
- Network Plugins ↗search: “network plugins”
- Container Runtimes ↗search: “container runtimes”
- Debugging Kubernetes nodes with crictl ↗search: “crictl”
- Volumes: CSI ↗search: “csi volume”
context · kubectl config use-context kind-cka
Record a node's CNI and runtime configuration
cka-worker (lab: docker exec -it cka-worker bash; exam: ssh cka-worker) and write these answers to files on your workstation under /tmp/cka/ext/: in cni-config.txt, the file name (without its directory) of the CNI network configuration the container runtime loads on that node; in cni-plugin.txt, the type of the first plugin in that configuration; in runtime-endpoint.txt, the container runtime endpoint the kubelet on that node is configured to use.- 01
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ext-1/setup | bash - 02
Solve it in your terminal
Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under
/tmp/cka/. - 03
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ext-1/verify | bashCounts toward your readiness score. - 04
Clean up
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ext-1/cleanup | bash
context · kubectl config use-context kind-cka
Find a container below the API with crictl
storefront in namespace arx-ext runs two containers. On the node where it runs, use crictl to find the ID of the Pod's sandbox and write it to /tmp/cka/ext/storefront-sandbox.txt, then find the ID of its log-agent container and write it to /tmp/cka/ext/log-agent-id.txt. Write the full, untruncated IDs.- 01
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ext-2/setup | bash - 02
Solve it in your terminal
Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under
/tmp/cka/. - 03
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ext-2/verify | bashCounts toward your readiness score. - 04
Clean up
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ext-2/cleanup | bash
Finished reading?
0 of 2 tasks passed. Readiness counts tasks, so run them before you move on.