Deploying a Kubernetes 1.26 Cluster with containerd and Calico

Node Configuration Table

Role IP Address
master1 192.168.40.180
master2* 192.168.40.183
node1 192.168.40.181
node2* 192.168.40.182

*Nodes marked with an asterisk are reserved for future cluster expansion.

Prerequisites for All Node

Hostname Assignment

hostnamectl set-hostname master1 && bash   # Run on master1
hostnamectl set-hostname node1 && bash     # Run on node1

Disable Firewall and SELinux

systemctl stop firewalld && systemctl disable firewalld
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
reboot

Configure Host Resolution

Append the following to /etc/hosts on every machine:

192.168.40.180 master1
192.168.40.181 node1

Establish Password-less SSH from master1

ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa
ssh-copy-id node1

Disable Swap

swapoff -a
sed -i '/swap/ s/^/#/' /etc/fstab

Kernel Tuning and Bridged Traffic

modprobe br_netfilter
cat > /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system

Add Yum Repositories

yum install -y yum-utils
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
cat > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
EOF

Time Synchronization

yum install -y ntpdate
ntpdate cn.pool.ntp.org
echo "* * * * * /usr/sbin/ntpdate cn.pool.ntp.org" | crontab
service crond restart

Install Essential Packages

yum install -y device-mapper-persistent-data lvm2 wget net-tools nfs-utils \
  gcc make openssl-devel curl unzip vim socat ipvsadm conntrack

Container Runtime: containerd and Docker

Install and Configure containerd

yum install -y containerd.io-1.6.6
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml

Edit /etc/containerd/config.toml:

  • Set SystemdCgroup = true
  • Replace sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.7"
systemctl enable --now containerd
cat > /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF
systemctl restart containerd

Image Acceleration for containerd

In /etc/containerd/config.toml, set:

config_path = "/etc/containerd/certs.d"

Then create the mirror configuration:

mkdir -p /etc/containerd/certs.d/docker.io
cat > /etc/containerd/certs.d/docker.io/hosts.toml <<EOF
[host."https://ag38j4ig.mirror.aliyuncs.com",host."https://registry.docker-cn.com"]
  capabilities = ["pull"]
EOF
systemctl restart containerd

Install Docker (Optional, for Image Building)

yum install -y docker-ce
systemctl enable --now docker
cat > /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": ["https://ag38j4ig.mirror.aliyuncs.com","https://registry.docker-cn.com"],
  "exec-opts": ["native.cgroupdriver=systemd"]
}
EOF
systemctl restart docker

Kubernetes Component Installation

yum install -y kubelet-1.26.0 kubeadm-1.26.0 kubectl-1.26.0
systemctl enable kubelet

Set the container runtime for crictl:

crictl config runtime-endpoint unix:///run/containerd/containerd.sock

Cluster Initialization on master1

Generate and Modify the Configuration

kubeadm config print init-defaults > kubeadm-init.yaml

Edit kubeadm-init.yaml with the following essential sections:

apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.40.180
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///run/containerd/containerd.sock
  name: master1
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: 1.26.0
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
networking:
  podSubnet: 10.244.0.0/16
  serviceSubnet: 10.96.0.0/12
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd

Import Container Images Locally (Optional)

If you have pre-downloaded images (k8s_1.26.0.tar.gz), import them:

ctr -n=k8s.io images import k8s_1.26.0.tar.gz

Bootstrap the Control Plane

kubeadm init --config=kubeadm-init.yaml --ignore-preflight-errors=SystemVerification
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

Joining Worker Nodes

Retrieve the join command on master1:

kubeadm token create --print-join-command

Execute the command on node1:

kubeadm join 192.168.40.180:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash> --ignore-preflight-errors=SystemVerification

Network Plugin: Calico

Install Calico

Import the Calico image (calico.tar.gz) on both nodes:

ctr -n=k8s.io images import calico.tar.gz

Deploy Calico using the provided manifest:

kubectl apply -f calico.yaml

Verify that all pods are runing and nodes become Ready:

kubectl get nodes -w

Testing Pod Connectivity

kubectl run test-busybox --image=docker.io/library/busybox:1.28 --restart=Never --rm -it -- sh
# Inside the pod
ping www.baidu.com
nslookup kubernetes.default.svc.cluster.local
exit

Adding Secondary Nodes for Expansion

Worker Node 2 (node2)

Repeat all prerequisite steps and then run the same kubeadm join command (without the --control-plane flag).

Additional Control Plane Node (master2)

  1. Complete the prerequisite configuration as for node1.
  2. Import k8s_1.26.0.tar.gz and calico.tar.gz images.
  3. On master1, distribute certificate files:
    mkdir -p /etc/kubernetes/pki/etcd && mkdir -p ~/.kube/
    scp /etc/kubernetes/pki/{ca.crt,ca.key,sa.key,sa.pub,front-proxy-ca.crt,front-proxy-ca.key} master2:/etc/kubernetes/pki/
    scp /etc/kubernetes/pki/etcd/{ca.crt,ca.key} master2:/etc/kubernetes/pki/etcd/
    
  4. Confirm that the kubeadm-config ConfigMap includes controlPlaneEndpoint:
    kubectl -n kube-system edit cm kubeadm-config
    # Add or ensure the following exists:
    controlPlaneEndpoint: "192.168.40.180:6443"
    
  5. Join the cluster as a control plane node:
    kubeadm join 192.168.40.180:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash> --control-plane --ignore-preflight-errors=SystemVerification
    
  6. Setup kubeconfig on master2:
    mkdir -p $HOME/.kube
    cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    chown $(id -u):$(id -g) $HOME/.kube/config
    

CLI Tools Comparison: ctr vs crictl

  • ctr: The native CLI for containerd. Can manage images outside of Kubernetes namespaces.
  • crictl: Designed as a Kubernetes CRI client. Ideal for troubleshooting pods and containers but lacks direct image management commands like pull/push. Use crictl for operations within the k8s.io namespace.

Tags: kubernetes kubeadm containerd Calico cluster-deployment

Posted on Tue, 19 May 2026 13:31:15 +0000 by yarons