How to Seamlessly Upgrade Kubernetes from Docker to Containerd
Learn a step‑by‑step process for migrating Kubernetes clusters (v1.24+) from the deprecated Docker runtime to the native Containerd CRI, covering compatibility checks, node preparation, installation, configuration, node draining, kubelet updates, validation, and common pitfalls such as cgroup driver mismatches.
Background
Kubernetes 1.24+ deprecates the Docker shim; containerd is the native CRI‑compatible runtime. Replacing Docker removes the intermediate layer, making the control plane lighter and more efficient.
Key concepts
It is a container‑runtime replacement, not a Kubernetes version upgrade.
Docker is deprecated; Kubernetes no longer communicates via dockershim.
Containerd implements the CRI directly, allowing K8s to talk to it.
Docker itself builds on containerd, so the migration essentially removes the middle layer.
Upgrade procedure (test in a staging environment, then apply node‑by‑node)
Phase 1 – Preparation
Compatibility check
Ensure the Kubernetes version is compatible with Containerd (e.g., K8s 1.24+ with Containerd 1.6+).
Refer to the official version matrix for exact compatibility.
Backup
Back up persistent container data.
Important paths to back up:
/etc/containerd/config.toml /var/lib/containerd /etc/docker/daemon.jsonRecord current state
kubectl get pods -o wide | grep <node-name> docker images crictl images # if crictl is installedInstall Containerd and CRI tools
Ubuntu/Debian:
sudo apt-get update
sudo apt-get install -y containerd cri-toolsCentOS/RHEL: sudo yum install -y containerd cri-tools Configure Containerd
Generate the default configuration and write it to /etc/containerd/config.toml:
sudo containerd config default | sudo tee /etc/containerd/config.tomlSet the cgroup driver to match the Kubelet (systemd):
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = trueOptionally configure a private registry in the same way as Docker’s /etc/docker/daemon.json.
Load kernel modules
sudo modprobe overlay
sudo modprobe br_netfilterEnsure the modules are loaded on boot (e.g., add them to /etc/modules-load.d/containerd.conf).
Phase 2 – Node switch
Drain the node
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-dataStop Docker and the Kubelet
sudo systemctl stop kubelet
sudo systemctl stop docker
sudo systemctl disable dockerEnable and start Containerd
sudo systemctl enable containerd
sudo systemctl start containerdUpdate the Kubelet configuration
The configuration file is usually /var/lib/kubelet/kubeadm-flags.env or a file passed via --config.
Set the runtime to remote and point to the Containerd socket:
--container-runtime=remote
--container-runtime-endpoint=unix:///run/containerd/containerd.sockRemove any Docker‑specific flags.
Reload systemd and restart the Kubelet
sudo systemctl daemon-reload
sudo systemctl start kubeletValidate the node
kubectl get nodes <node-name>
kubectl uncordon <node-name>Repeat the above steps for each remaining node.
Phase 3 – Post‑migration validation & cleanup
Verify workloads
Check that networking, storage, and DNS are functional.
Ensure application pods restart correctly and become Ready.
Optional: uninstall Docker
Ubuntu/Debian:
sudo apt-get remove -y docker-ce docker-ce-cli containerd.ioCentOS/RHEL:
sudo yum remove -y docker-ce docker-ce-cli containerd.ioRemoving Docker does not affect containers managed by Containerd, which are stored under /var/lib/containerd.
Learn the new debugging tools crictl ps, crictl pods, crictl images,
crictl logs <container-id> ctrfor low‑level container operations.
Common issues and mitigations
Kubelet fails to start (cgroup driver mismatch) – Ensure SystemdCgroup = true in /etc/containerd/config.toml matches the Kubelet’s cgroup driver.
Images need to be re‑pulled – Docker and Containerd use different storage paths. Pre‑save images with docker save or push them to a private registry before migration.
Log path or format changes – Logs remain under /var/log/pods/ and /var/log/containers/. Adjust log collectors if they rely on Docker‑specific paths.
Monitoring metric changes – Update Prometheus or other scrapers to collect Containerd‑specific metrics or rely on Kubelet CRI metrics.
Network plugin compatibility – Most CNI plugins are runtime‑agnostic, but verify compatibility in the plugin’s documentation.
Debugging experience differs – Replace docker ps/logs with crictl ps/logs; use ctr for deeper inspection.
Security policies (AppArmor/SELinux) – Adjust policies for Containerd if required; usually they inherit host settings.
Conclusion
Successful migration hinges on thorough preparation, node‑by‑node execution, and correct cgroup configuration. After the switch, the cluster becomes lighter, more efficient, and aligns with Kubernetes’ future direction.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ray's Galactic Tech
Practice together, never alone. We cover programming languages, development tools, learning methods, and pitfall notes. We simplify complex topics, guiding you from beginner to advanced. Weekly practical content—let's grow together!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
