How to Build a Kubernetes v1.22.1 Cluster with containerd Using kubeadm
This step‑by‑step guide shows how to prepare three CentOS 7 nodes, install containerd, configure system settings, deploy kubeadm/kubelet/kubectl, initialize a Kubernetes v1.22.1 control plane, add worker nodes, install the flannel CNI plugin, set up the Dashboard, and clean up the environment.
Environment preparation
Three CentOS 7.6 nodes (master, node1, node2) must have unique hostnames, firewalld and SELinux disabled, br_netfilter module loaded, and the following sysctl settings in /etc/sysctl.d/k8s.conf:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
vm.swappiness = 0Apply the settings with sysctl -p /etc/sysctl.d/k8s.conf. Install IPVS support:
cat > /etc/sysconfig/modules/ipvs.modules <<'EOF'
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
chmod 755 /etc/sysconfig/modules/ipvs.modules
bash /etc/sysconfig/modules/ipvs.modules
lsmod | grep -e ip_vs -e nf_conntrack_ipv4Install ipset and ipvsadm, synchronize time with chrony, and disable swap ( swapoff -a and comment out swap entries in /etc/fstab).
Install containerd
Download the bundled release that contains containerd, runc and CNI plugins, then extract it to the root filesystem:
wget https://github.com/containerd/containerd/releases/download/v1.5.5/cri-containerd-cni-1.5.5-linux-amd64.tar.gz
tar -C / -xzf cri-containerd-cni-1.5.5-linux-amd64.tar.gzGenerate a default configuration and enable the systemd cgroup driver:
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.tomlEdit /etc/containerd/config.toml to set:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://bqr1dr1n.mirror.aliyuncs.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint = ["https://registry.aliyuncs.com/k8sxio"]Start containerd with systemd:
systemctl daemon-reload
systemctl enable --now containerdInstall kubeadm, kubelet and kubectl
Add the Kubernetes yum repository (Google or Alibaba mirror) and install version 1.22.1:
cat > /etc/yum.repos.d/kubernetes.repo <<'EOF'
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
yum makecache fast
yum install -y kubelet-1.22.1 kubeadm-1.22.1 kubectl-1.22.1 --disableexcludes=kubernetes
systemctl enable --now kubeletCluster initialization configuration
Create kubeadm.yaml with the required settings (image repository, IPVS proxy mode, pod subnet, etc.):
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.31.30
bindPort: 6443
nodeRegistration:
criSocket: /run/containerd/containerd.sock
name: master
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
imageRepository: registry.aliyuncs.com/k8sxio
kubernetesVersion: v1.22.1
networking:
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
dnsDomain: cluster.localPre‑pull the required images (the coredns image may need manual handling):
kubeadm config images pull --config kubeadm.yaml
# If coredns is missing:
ctr -n k8s.io i pull docker.io/coredns/coredns:1.8.4
ctr -n k8s.io i tag docker.io/coredns/coredns:1.8.4 registry.aliyuncs.com/k8sxio/coredns:v1.8.4Initialize the control plane:
kubeadm init --config kubeadm.yamlCopy the admin kubeconfig for a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/configVerify the master node:
kubectl get nodesAdd worker nodes
Run the kubeadm join command printed at the end of kubeadm init (or regenerate it with kubeadm token create --print-join-command) on each worker after copying the same kubeconfig file. Verify with kubectl get nodes on the master.
Install Flannel CNI plugin
Download the manifest, optionally set --iface=eth0 for multi‑NIC hosts, and apply:
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# edit if needed: vi kube-flannel.yml (set --iface)
kubectl apply -f kube-flannel.ymlAfter a short wait, confirm that Flannel and CoreDNS pods are running in the 10.244.0.0/16 pod network.
Resolve containerd default CNI conflict
Containerd ships a default bridge CNI configuration ( 10-containerd-net.conflist) that conflicts with Flannel. Rename the file, delete the bridge interface, and restart services:
mv /etc/cni/net.d/10-containerd-net.conflist /etc/cni/net.d/10-containerd-net.conflist.bak
ifconfig cni0 down && ip link delete cni0
systemctl daemon-reload
systemctl restart containerd kubeletRe‑create CoreDNS and Dashboard pods so they obtain IPs from the Flannel subnet.
Deploy Kubernetes Dashboard
Download the latest Dashboard manifest (v2.3.1), change the Service type to NodePort, and apply:
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml
# edit: set spec.type: NodePort
kubectl apply -f recommended.yamlCreate an admin ServiceAccount and ClusterRoleBinding to obtain a login token:
cat > admin.yaml <<'EOF'
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: admin
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: admin
namespace: kubernetes-dashboard
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin
namespace: kubernetes-dashboard
EOF
kubectl apply -f admin.yaml
# Retrieve token:
kubectl -n kubernetes-dashboard get secret | grep admin-token
kubectl -n kubernetes-dashboard get secret admin-token-xxxx -o jsonpath={.data.token} | base64 -dAccess the Dashboard at https://<master‑IP>:<NodePort> (e.g., https://192.168.31.30:31050) and log in with the decoded token.
Final verification
Run the following to confirm the cluster state:
kubectl get nodes -o wide
kubectl get pods -n kube-system
kubectl get svc -n kubernetes-dashboardAll nodes should be Ready, the container runtime should be containerd://1.5.5, and pod IPs should belong to the 10.244.0.0/16 range.
Cluster cleanup
If a full reset is required:
kubeadm reset
ifconfig cni0 down && ip link delete cni0
ifconfig flannel.1 down && ip link delete flannel.1
rm -rf /var/lib/cni/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.
Cloud Native Technology Community
The Cloud Native Technology Community, part of the CNBPA Cloud Native Technology Practice Alliance, focuses on evangelizing cutting‑edge cloud‑native technologies and practical implementations. It shares in‑depth content, case studies, and event/meetup information on containers, Kubernetes, DevOps, Service Mesh, and other cloud‑native tech, along with updates from the CNBPA alliance.
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.
