K8S Kubeadm 搭建流程
把最近用 kubeadm 搭建 K8S 集群的流程,以及途中遇到的部分问题,作为笔记记录下来。
部署环境
- 搭建版本:kubernetes-1.24.4(HA)
- 容器运行时:containerd-1.6.8
- 操作系统:CentOS7
前置条件
1)集群节点计算资源必须是 2h-cpu 2g-ram 以上的机器,节点内网或公网需要可达。
2)每个机器的 hostname、mac 地址不能相同,product_uuid 需要唯一;通过 hostname 可以访问对应节点,需要配置 /etc/hosts 文件。
3)kubernetes 1.24 版本后默认的容器运行时不再使用 Docker,改为 Containerd 容器运行时,如果需要使用 docker 则需要安装 cri-dockerd。
4)HA 架构必须存在 3 个 master 控制平面节点,高可用分为外部 etcd 与堆叠 etcd 两种拓扑,架构如下图。
外部etcd

优点:失去控制平面实例或者 etcd 成员的影响较小,不会像堆叠的 HA 拓扑那样影响集群冗余。
缺点:需要更多机器节点,要 3 台服务器单独部署 etcd HA 集群。
堆叠etcd

优点:这种拓扑将控制平面和 etcd 成员耦合在同一节点上。相对使用外部 etcd 集群,设置起来更简单,而且更易于副本管理。
缺点:堆叠集群存在耦合失败的风险。如果一个节点发生故障,则 etcd 成员和控制平面实例都将丢失,并且冗余会受到影响。你可以通过添加更多控制平面节点来降低此风险。
load balancer: 内部负载均衡器,需要保证自身 HA。为 worker 节点反向代理 apiServer,提供统一访问 apiServer 的 ip,并且可以感知 master 的可用性。
5)禁用 Linux 交换分区。(交换分区:内存不足时使用硬盘存储,会降低系统性能,好处是可以存储更多内存数据,并且内存占满也不会导致服务器马上出现卡顿)
# 设置 CentOS 禁用交换分区:
# 永久关闭:
# 1、vim /etc/fstab 进入配置文件注释掉下面这个配置
/dev/mapper/cl-swap swap swap defaults 0 0
# 2、注释掉并保存
# 临时关闭:
# 执行 swapoff -a 命令
swapoff -a
6)关闭防火墙或者开启官网指定端口
# 查看防火墙状态
firewall-cmd --state
# 1、打开防火墙端口 master 节点需要 6443 2379-2380 10250 10251 10252
firewall-cmd --permanent --add-port=6443/tcp
firewall-cmd --permanent --add-port=2379-2380/tcp
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=10251/tcp
firewall-cmd --permanent --add-port=10252/tcp
# 打开防火墙端口 node-worker 节点需要 10250 30000-32767
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=30000-32767/tcp
# 防火墙重载配置
firewall-cmd --reload
# 检测端口是否已经配置成功
firewall-cmd --zone=public --list-ports
# 2、也可选择关闭防火墙 !不安全 但可以避免很多问题,比如后续的CNI网络组件所需端口
# 停止firewall
systemctl stop firewalld.service
# 禁止firewall开机启动
systemctl disable firewalld.service
7)配置 yum 源信息 /etc/yum.repos.d/kubernetes.repo(官方源有可能无法使用,需要科学上网,所以此处使用国内阿里源)
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
8)开启内核转发与网桥过滤,安装 ipset、ipvsadm,并启用对应内核模块
官方文档:容器运行时 | Kubernetes
# 声明需要加载的内核模块
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-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
vm.swappiness = 0
EOF
# 使配置生效
sudo sysctl --system
# 安装 ipset ipvsadm
yum -y install ipset ipvsadm
mkdir -p /etc/sysconfig/modules/
# 声明 ipvs 所需内核模块
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
EOF
# 授予执行权限并运行
chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules
# 查看是否生效
lsmod | grep ip_vs
# 控制台输出
ip_vs_sh 16384 0
ip_vs_wrr 16384 0
ip_vs_rr 16384 0
ip_vs 180224 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack 176128 1 ip_vs
nf_defrag_ipv6 24576 2 nf_conntrack,ip_vs
libcrc32c 16384 2 nf_conntrack,ip_vs
9)将 SELinux 设置为 permissive 模式(相当于将其禁用)
sudo setenforce 0
安装容器运行时
Containerd
参考:实战:centos7上containerd的安装-20211023_一念一生~one的博客-CSDN博客_centos安装containerd
在 Containerd 1.6 后的版本中,需要升级本地依赖 libseccomp 到 2.4 以上,不然可能出现无法启动容器的情况。本人亲自踩坑,错误信息非常不好找,并且 CentOS yum 源中最高只有 2.3.1,只能自己从官方下载并安装。
相关命令:
# 查看当前 libseccomp 版本
rpm -qa | grep libseccomp
# 卸载旧版本
rpm -e libseccomp-devel-2.3.1-4.el7.x86_64 --nodeps
rpm -e libseccomp-2.3.1-4.el7.x86_64 --nodeps
# 下载新版本 libseccomp
wget http://rpmfind.net/linux/centos/8-stream/BaseOS/x86_64/os/Packages/libseccomp-2.5.1-1.el8.x86_64.rpm
# 安装 libseccomp
rpm -ivh libseccomp-2.5.1-1.el8.x86_64.rpm
集群初始化
1)安装 kubeadm、kubectl、kubelet 三大组件
# 安装组件
sudo yum install -y kubelet-1.24.4 kubeadm-1.24.4 kubectl-1.24.4 --disableexcludes=kubernetes
# 设置kubelet开机自启
sudo systemctl enable --now kubelet
2)初始化平面控制节点
使用 kubeadm 初始化节点,命令为 kubeadm init 【参数】。
更多参数可以查看官网文档:Kubeadm | Kubernetes
此处我使用我本地环境的配置参数,生产环境只需要把对应 ip 地址改为线上内网 ip 即可。
# 可使用命令初始化控制平面
sudo kubeadm init \
--control-plane-endpoint "k8s-cluster:6443" \
--apiserver-advertise-address=192.168.5.27 \
--apiserver-bind-port=6443 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.24.4 \
--cert-dir=/etc/kubernetes/pki \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=172.24.0.0/16 \
--upload-certs
# 也可使用初始化文件 先生成初始化文件,再根据自身场景修改其参数
kubeadm config print init-defaults > kubeadm-config.yaml
kubeadm init --config = kubeadm-config.yaml --upload-certs
关键参数说明:
--control-plane-endpoint:填写内部 load balancer 的 ip 地址或者内网的 DNS 域名信息。worker 节点通过此域名或 ip 访问集群内部的 master 节点,从而确保 master 高可用。
--apiserver-advertise-address:填写当前控制平面的内网 ip 地址。
--pod-network-cidr:pod 内网网段 ip。
--service-cidr:service 内网网段 ip。
--image-repository:镜像地址,设置为国内的,我这里使用的 ali 源,拉取速度提升。
初始化时,kubeadm 需要拉取 k8s.gcr.io/pause 镜像,由于国内被墙,很有可能无法成功下载,导致初始化失败。如果你初始化失败了则查看容器运行时的日志信息,如果发现无法拉取到对应镜像,说明就是此问题(被坑几天查找问题)。解决办法:
# 查看容器运行时日志
journalctl -xeu containerd
# 由于k8s.gcr.io 需要连外网才可以拉取到,导致 k8s 的基础容器 pause 经常无法获取。
# 可使用 crictl 从国内镜像仓库拉取,再利用 ctr tag 解决问题
# 拉取国内镜像
crictl pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.6
# 进行tag打标
ctr -n k8s.io image tag registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.6 k8s.gcr.io/pause:3.6
3)初始化成功后的输出
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as 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/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join k8s-cluster:6443 --token v6rrcg.vnl78b94fo740xv9 \
--discovery-token-ca-cert-hash sha256:5dd2edf3d668bd0608897a0097455c6a514a91fd0b1ad4d1044789d9f56123ce \
--control-plane --certificate-key 4c9b2b3a2d19db4b4f58681e6cf264a0b7bb1eacf443ae90a50bd0e8c11e0c31
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join k8s-cluster:6443 --token v6rrcg.vnl78b94fo740xv9 \
--discovery-token-ca-cert-hash sha256:5dd2edf3d668bd0608897a0097455c6a514a91fd0b1ad4d1044789d9f56123ce
通过以上输出信息,已经得知对应 node 节点加入集群的指令信息。
节点加入集群
kubeadm join 指令附带上 token 信息即可加入其他的 master 节点与 worker 节点。token 默认 6 小时生效,重新生成的 token 是 24 小时生效,如果 token 过期可使用命令重新生成:
# master平面节点加入执行:(获取证书加密信息)平面节点加入需要 token + certs 信息
kubeadm init phase upload-certs --upload-certs
# worker节点加入生成token信息
kubeadm token create --print-join-command
# 执行查看当前已有token列表
kubeadm token list
安装网络CNI组件
可根据自身企业业务场景与规模,从安全与性能上考虑,选择适合的 CNI 组件。注意:集群中只能有一种 CNI 组件。
更多细节也可查看官方文档:使用 kubeadm 创建集群 | Kubernetes

此处我选用常用的 CNI 组件:Calico。
Calico 官方网站:为本地部署安装 Calico 网络和网络策略 (tigera.io)
# 首先,在群集上安装运算符。
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.24.0/manifests/tigera-operator.yaml
# 下载配置 Calico 所需的自定义资源
curl https://raw.githubusercontent.com/projectcalico/calico/v3.24.0/manifests/custom-resources.yaml -O
# 自定义配置custom-resources.yaml文件
# 修改其中pod网络网段ip信息
# calicoNetwork:
# # Note: The ipPools section cannot be modified post-install.
# ipPools:
# - blockSize: 26
# cidr: 172.24.0.0/16 (修改此处与kubeadm时相同的pod网段)
# encapsulation: VXLANCrossSubnet
# natOutgoing: Enabled
# nodeSelector: all()
# 创建清单以安装 Calico。
kubectl create -f custom-resources.yaml
# 运行查看Calico相关pod运行状态,需要等待4分钟左右
kubectl get pod -all-namespace
部署控制平面
kuboard
通过 docker 镜像直接一键启动容器,然后进行集群导入引导操作。
成功监控集群信息:

小结
到这一步,集群已经基本可用:kubeadm 完成控制平面初始化,节点通过 token 加入,Calico 提供 pod 网络,kuboard 负责可视化监控。整个流程里最容易踩的坑集中在两处:Containerd 的 libseccomp 版本过低,以及 pause 镜像因网络原因拉取失败,两者的报错都不直观,需要去容器运行时日志里找线索。后续还需要加入 NAS 文件服务,便于集群内部的文件存储,以及考虑是否引入 Istio 和网络入口 Ingress 的设置,根据企业自身进行合理配置。
评论 / COMMENTS