Install and config containerd¶
You can find the official doc for installing containerd here.
1. Prerequisites¶
To make containerd run correctly, we need to do the following config
- add two moduls into the linux kernel(e.g. overlay, br_netfilter)
- if containerd needs to work with k8s cri, you need to reconfigure some kernel parameters
1.1 Add modules to linux kernel¶
The below command will create a file containerd.conf in /etc/modules-load.d/, and add two lines overlay, and br_netfilter
in the containerd.conf file.
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
The file specifies the kernel modules overlay, and br_netfilter should be automatically loaded at boot.
- overlay: This module is required for
containerdandDocker. It enables theOverlayFS filesystem, which helps efficiently store container layers. - br_netfilter: This module ensures that bridged traffic is correctly processed by iptables. It's an essential module for Kubernetes networking (iptables-based rules)
To load the module without rebooting, you can load the module manually with the below command
sudo modprobe overlay
sudo modprobe br_netfilter
To check if the module is loaded correctly or not, you can use the below command.
lsmod | grep -E 'overlay|br_netfilter'
# the expected output
br_netfilter 32768 0
bridge 262144 1 br_netfilter
overlay 147456 0
1.2 Reconfigure kernel parameters (If containerd is installed for k8s cluster)¶
We need to modify the value of the below kernel parameters:
- net.bridge.bridge-nf-call-iptables = 1: this parameter ensures that
iptables processes traffic from bridged network interfaces. It's required forKubernetes networking(especially CNI plugins like Flannel,Calico). - net.ipv4.ip_forward = 1: this parameter enables
IP forwarding, allowing the machine to route packets. It's required forKubernetes pod-to-pod communication. - net.bridge.bridge-nf-call-ip6tables = 1: this parameter enables
ip6tables processes IPv6 bridged traffic. It's useful if your cluster supports IPv6 networking.
IP forwarding is a feature in the Linux kernel that allows a
machine to act as a router, forwarding network packets from one interface to another. By default, Linux does not forward packets between network interfaces unless explicitly enabled.
As all kernel parameters are stored in /etc/sysctl.d/, by convention, we create a config file 9-kubernetes-cri.conf,
and put the above three lines in it. You can use the below command to do it.
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
To apply the change you can use
# The below command will trigger the system to read and apply all settings from:
# /etc/sysctl.conf
# /run/sysctl.d/*.conf
# /etc/sysctl.d/*.conf
# /usr/lib/sysctl.d/*.conf
sudo sysctl --system
# test the updated value
sudo sysctl net.bridge.bridge-nf-call-iptables
sudo sysctl net.ipv4.ip_forward
sudo sysctl net.bridge.bridge-nf-call-ip6tables
# or you can test all with oneliner
sudo sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward
2. Install containerd (via apt)¶
The containerd.io packages in DEB and RPM formats are distributed by Docker (not by the containerd project).
The Docker documentation for how to
set up apt-get to install containerd.io packages:
2.1 Remove old versions if exist¶
Your Linux distribution may provide unofficial Docker packages, which may conflict with the official packages
provided by Docker. You must uninstall these packages before you install the official version of Docker Engine.
The unofficial packages to uninstall are:
- docker.io
- docker-compose
- docker-doc
- podman-docker
Run the following command to uninstall all conflicting packages:
# remove all conflicting packages
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
# Remove the installed default config file
rm /etc/containerd/config.toml
2.2 Configure the official repo¶
# install required packages
sudo apt-get install \
ca-certificates \
curl \
gnupg
# add gpg key for the containerd.io repo
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# add docker.io repo to source.list
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
2.3 Install containerd binary and set up config¶
Install the containerd binary via new repo
sudo apt update
sudo apt install containerd.io
# check the installed version
containerd --version
# expected output
containerd containerd.io 1.7.25 bcc810d6b9066471b0b6fa75f557a15a1cbf31bb
3. Configure containerd after installation¶
There is no default configuration file after installation. You need to create one by yourself.
3.1 Generate a default config¶
# generate a default config
containerd config default | sudo tee /etc/containerd/config.toml
The default config file needs to be modified, below are some points you need to pay attention to:
- cgroup driver setting: containerd requires cgroup(linux kernel) to setup resources(e.g. cpu, memory, etc.) and
security policies. It uses a cgroup driver to communicate with the cgroup.
You need to adapt this value based on your system setting
- sandbox image url: In k8s, all pods have a sandbox container that uses sandbox image.
- custom image registry: If you want to use custom image registry, you need to change the default config too.
3.2 Change the cgroup driver to systemd¶
Find the following section [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] in /etc/containerd/config.toml, then add this line SystemdCgroup = true under it.
Or you can run the below command to change it, note it only works if the generated config contains SystemdCgroup = false
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
After the above command, you should see the below lines in etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
3.3 change sandbox image pull url¶
All pods in k8s require a sandbox image, the containerd default config has a default sandbox image pulling image. Based on the k8s version, you need to adapt this value.
You should find the below line, and change the image url to your k8s required image url.
sandbox_image = "k8s.lixx.cn/pause:3.10"
Every Kubernetes Pod has a
Pause container(sandbox container) that holds thenetwork namespaceand acts as the parent of all other containers in the Pod. It has two main goals: - Keeps Pod Resources Active – It ensures thatnetworking and IPC resources remain stableeven if app containers restart. - Efficient Namespace Sharing – Other containers in the Pod share itsPID, network, and IPC namespaces.
3.4 Custom image registry¶
containerd allows us to use custom image registry. Suppose our image registry runs at https://reg.casd.local.
You need to edit the containerd config file /etc/containerd/config.toml
sudo vim /etc/containerd/config.toml
# find the plugins."io.containerd.grpc.v1.cri".registry section in the config.tom
# add the below line, you need to change the url value to your url
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."reg.casd.local"]
endpoint = ["https://reg.casd.local"]
[plugins."io.containerd.grpc.v1.cri".registry.configs."reg.casd.local".tls]
insecure_skip_verify = true
[plugins."io.containerd.grpc.v1.cri".registry.configs."reg.casd.local".auth]
username = "toto"
password = "chagneMe"
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://registry-1.docker.io"]
# now we need to reload the daemon
sudo systemctl daemon-reload
# restart containerd
sudo systemctl restart containerd
# try to pull an image from the private image registry
sudo crictl pull reg.casd.local/casd/redis
DEPRECATION: The
mirrorsproperty of[plugins."io.containerd.grpc.v1.cri".registry]is deprecated since containerd v1.5 and will be removed in containerd v2.1. Useconfig_pathinstead. For now, we don't migrate toconfig_path, because it does not provide all features(for example .auth).
3.5 Restart and enable containerd service on all the nodes¶
$ sudo systemctl restart containerd
$ sudo systemctl enable containerd
# you can check the service status
$ sudo systemctl status containerd
# check the version
containerd --version
# you can use the default containerd client to test
ctr version
4. Install and setup containerd client¶
Below is a list of containerd major clients:
- ctr: default
- crictl: client compatbile with k8s
4.1 ctr¶
containerd provides a CLI called ctr. It's a low-level CLI tool designed for direct interaction with containerd.
It supports the complete life-cycle of a container(e.g. pull image, create
container, etc.) But it does not support the Kubernetes CRI (Container Runtime Interface).
# list containers
ctr containers list
# pull image
ctr images pull docker.io/library/nginx:latest
# list images
sudo ctr images ls
# run a container
ctr run --rm -t docker.io/library/nginx:latest my-nginx
All the cri pluging configurations in
/etc/containerd/config.tomlare ignored by ctr, because it does not support CRI. That's we recommend you to use crictl for testing.
For more details of ctr , you can visit this page
4.2 crictl¶
The official docs of crictl can be found here.
The latest release version can be found here.
Follow the below steps to install and config crictl
# install crictl bin
VERSION="v1.32.0"
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
rm -f crictl-$VERSION-linux-amd64.tar.gz
# config crictl.yaml
cat <<EOF | sudo tee /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: false
pull-image-on-create: false
EOF
# list all images
sudo crictl images
# pull images
sudo crictl pull reg.casd.local/casd/redis
# list pods
sudo crictl pods
# list containers
sudo crictl ps -a
# get logs of a container
sudo crictl logs <conainer_id>
Appendix: cgroup and systemd¶
Control Groups (cgroups) and systemd are closely related because systemd is responsible for managing
system services and processes, and it heavily relies on cgroups to do so.
- systemd organizes processes using cgroups to track and manage resource usage;
- Every service, user session, or scope started by systemd gets its own cgroup. For example, the
nginx.serviceruns in/sys/fs/cgroup/system.slice/nginx.service/ - This allows fine-grained control over CPU, memory, I/O, and other resources.
# test cgroup version
mount | grep cgroup
# expected output
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)
# we can set max cpu and memory for a service
systemctl set-property nginx.service CPUQuota=50%
systemctl set-property nginx.service MemoryMax=500M