kubeadm 搭建多节点集群
kubeadm 搭建多节点集群
用 kubeadm 在 CentOS 7 上从零搭一套多节点 k8s 集群的完整记录,包含 cri-dockerd 适配器、容器运行时配置,以及节点 IP 变更后重新初始化集群的办法。IP、token、cert-hash 都用占位符,实际操作时换成自己的。
硬件和网络要求
- 每台机器 2GB 以上内存,CPU 2 核以上
- 所有机器网络互通(公网内网都行)
- 节点之间不能有重复的主机名、MAC 地址或 product_uuid(
ip a可看) - 必须禁用交换分区,否则 kubelet 工作不正常:
swapoff -a
vi /etc/fstab # 注释掉 swap 那行
转发 IPv4 并让 iptables 看到桥接流量
所有机器上执行:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
确认模块加载和参数生效:
lsmod | grep br_netfilter
lsmod | grep overlay
sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward
安装 kubelet kubeadm kubectl
所有机器上:
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
# SELinux 设为 permissive
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable --now kubelet
安装 docker,用 containerd 作运行时
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
systemctl enable --now docker
systemctl enable --now containerd
容器运行时的 cgroup 驱动设成 systemd:
containerd config default > /etc/containerd/config.toml
# 在 /etc/containerd/config.toml 里设置:
# [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
# SystemdCgroup = true
systemctl restart containerd
关于 cri-dockerd
K8s 1.23 及之前可以通过内置的 dockershim 用 Docker Engine。1.24 起 dockershim 被移除,要用第三方的 cri-dockerd 适配器,通过 CRI 接口接 Docker Engine。
本文用的是 containerd 运行时,不用 docker,所以不需要 cri-dockerd。如果确实要用 Docker Engine,装 cri-dockerd:
从 Mirantis/cri-dockerd releases 下对应版本,解压安装:
tar xf cri-dockerd-0.3.7.amd64.tgz
cd cri-dockerd
install -o root -g root -m 0755 cri-dockerd /usr/local/bin/cri-dockerd
创建 systemd service(/lib/systemd/system/cri-docker.service),ExecStart 里指定 pause 镜像:
ExecStart=/usr/local/bin/cri-dockerd --container-runtime-endpoint fd:// --pod-infra-container-image registry.aliyuncs.com/google_containers/pause:3.9
和 socket(/lib/systemd/system/cri-docker.socket,ListenStream=%t/cri-dockerd.sock)。然后:
systemctl enable --now cri-docker.socket cri-docker.service
初始化集群
写 kubeadm-config.yaml,podSubnet 必须和网络插件一致,否则 flannel pod 会一直 CrashLoopBackOff:
kind: ClusterConfiguration
apiVersion: kubeadm.k8s.io/v1beta3
kubernetesVersion: v1.26.0
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16 # 必须与 flannel pod 网段一致
---
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
cgroupDriver: systemd
kubeadm init --config kubeadm-config.yaml --v=5
# 保存输出里的 join 命令,加节点时要用
装 flannel 网络插件:
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.20.2/Documentation/kube-flannel.yml
按 kubeadm init 输出配置 kubeconfig:
mkdir -p ~/.kube
cp -i /etc/kubernetes/admin.conf ~/.kube/config
chown $(id -u):$(id -g) ~/.kube/config
节点机加入集群(在节点机上执行):
kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<ca-cert-hash>
token 有时效,过期了重新生成:
kubeadm token create
# 重新取 ca-cert-hash
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'
关防火墙,验证:
systemctl stop firewalld && systemctl disable firewalld
kubectl get nodes
kubectl get pods -A
安装 Kuboard(集群管理网页)
docker run -d --restart=unless-stopped --name=kuboard -p 80:80/tcp -p 10081:10081/tcp \
-e KUBOARD_ENDPOINT="http://<master-ip>:80" \
-e KUBOARD_AGENT_SERVER_TCP_PORT="10081" \
-v /root/kuboard-data:/data eipwork/kuboard:v3
# 访问 http://<master-ip>:80,按提示导入集群、装 agent
踩过的坑
- 1.24 起 dockershim 被移除。本文用 containerd,看容器用
crictl(命令和 docker 差不多)。用docker build构建的镜像通用,不影响 containerd。 - crictl ps 报错:
crictl config runtime-endpoint unix:///var/run/containerd/containerd.sock。 - 节点机重启后 not ready:
systemctl restart kubelet。
集群重置:
kubeadm reset
rm -rf /root/.kube /etc/cni/net.d
yum install -y ipvsadm && ipvsadm -C
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
# 再重新 init + apply flannel + join
常用命令:
yum install -y net-tools telnet
netstat -tunlp # 看进程及监听端口
journalctl -fu kubelet # 看 kubelet 日志
kubectl delete pod xxx -n ns --force --grace-period=0 # 强删 pod
节点 IP 变更后重新初始化集群
control plane 节点 IP 变了,用已有的 etcd 数据重新初始化集群。
先在 control plane 节点备份原配置:
systemctl stop kubelet
mv /etc/kubernetes /etc/kubernetes-bak
mv /var/lib/kubelet/ /var/lib/kubelet-bak
保留 pki 证书目录,但删掉和旧 IP 绑定的 apiserver、etcd peer 证书:
mkdir -p /etc/kubernetes
cp -r /etc/kubernetes-bak/pki /etc/kubernetes
rm /etc/kubernetes/pki/{apiserver.*,etcd/peer.*}
重新初始化,关键是用预先存在的 etcd 数据(--ignore-preflight-errors=DirAvailable--var-lib-etcd):
kubeadm init --config kubeadm.yaml --ignore-preflight-errors=DirAvailable--var-lib-etcd
如果提示端口被占,查 pid 杀掉再重试:
netstat -tunlp
kill <pid>
拷贝 kubeconfig:
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
每个 node 节点上重新 join:
kubeadm reset
kubeadm join <master-ip>:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<ca-cert-hash>
最后 kubectl get nodes 看状态。