kubeadm 搭建 kubenetes 集群
Lapin Gris Lv3

本文介绍如何使用 kubeadm,创建一个符合最佳实践的最小化 Kubernetes 的单节点集群。虽然本文搭建的是,单节点 master 集群,依然可以通过 kubeadm 扩容新的 Node 节点加入到集群。本文会将重心放在如何拉起一个集群,集群扩容会简要介绍。

准备工作

关闭 firewalld

关闭 ECS 运行的防火墙,

systemctl stop firewalld
systemctl disable firewalld

安装 containerd

安装容器运行时 containerd 并生成默认配置,

# 配置源
dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo


# 安装
yum install -y containerd

# 生成默认配置
containerd config default > /etc/containerd/config.toml

# 修改pause镜像为阿里云镜像地址
sed -i 's|registry.k8s.io/pause|registry.aliyuncs.com/google_containers/pause|' /etc/containerd/config.toml
# 启用 systemd cgroup
sed -i 's|SystemdCgroup = false|SystemdCgroup = true|' /etc/containerd/config.toml

# 重启
systemctl restart containerd

注意:请确保你已经将 runc options SystemdCgroup 配置修改为 true

否则,你可能会在启用了 cgroupv2 操作系统上,遇到如下报错,导致 pod 被 kubelet 重建

Pod sandbox changed, it will be killed and re-created.

安装 kubernetes

安装 kubenetes 1.31,

# 配置 kubenetes 源
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.tuna.tsinghua.edu.cn/kubernetes/core:/stable:/v1.31/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.31/rpm/repodata/repomd.xml.key
EOF

# 安装
yum install -y kubelet kubeadm kubectl

安装 crictl

安装 crictl 工具,crictl 帮助我们更方便的在节点上管理 Pod,

# 安装 crictl
yum install cri-tools -y

# 生成 crictl 配置,
cat > /etc/crictl.yaml << EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: false
pull-image-on-create: false
EOF

加载 内核模块和修改内核配置

k8s 集群 Pod 之间通信依赖一些内核能力,需要加载必备的 br_netfilter 模块开启 ip_forward 内核参数并持久化,

modprobe br_netfilter
tee /etc/modules-load.d/br_netfilter.conf <<EOF
br_netfilter
EOF

echo 1 > /proc/sys/net/ipv4/ip_forward
tee /etc/sysctl.d/99-ipv4-ip-forward.conf <<EOF
net.ipv4.ip_forward = 1
EOF

Kubenetes部署

从现在开始,部署 k8s 集群正式开始。部署分为两个部分,
第一部分是部署集群控制面(即 master),第二部分是将 node 节点加入集群中。如果只部署单节点的集群,只需要第一部分即可。

生成Kubeadm init配置

使用 kubeadm 生成集群 yaml 配置,

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

修改 kubeadm-init.yaml 配置,主要修改地方有 3 处,

  • advertiseAddress: APIServer 内网地址
  • name: APIServer 的主机名
  • imageRepository: 镜像仓库地址
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: x.x.x.x # 修改为 master 内网 IP
bindPort: 6443
nodeRegistration:
criSocket: unix:///var/run/containerd/containerd.sock
imagePullPolicy: IfNotPresent
name: k8s-master # 修改为主机名
taints: null
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers # 修改国内镜像源
kind: ClusterConfiguration
kubernetesVersion: 1.28.0
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
scheduler: {}

初始化集群

用刚才生成的配置文件,执行 kubeadm init 初始化集群。调高日志等级方便故障排查,

kubeadm init --config kubeadm-init.yaml --v 5

集群初始化完成后,我们通常会通过 kubectl 命令行查看集群状态,
kubeadm 已经生成了连接集群 APIServer 的配置,告诉 kubectl 如何连接集群的配置文件并持久化,

export KUBECONFIG=/etc/kubernetes/admin.conf
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bashrc

为 kubectl 命令添加自动补全并持久化,

source <(kubectl completion bash)
echo 'source <(kubectl completion bash)' >> ~/.bashrc

执行完这一步,集群所需的关键组件(etcd/apiserver/cm/scheduler)已经 up。虽然此时当前节点依然是 not-ready 状态,,因为我们还差集群网络没有配置,配置完毕后,集群状态会变为 ready。coredns 容器也会 up。

[root@k8s-master ~]# kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-855c4dd65d-hssl9 0/1 Pending 0 29s
kube-system coredns-855c4dd65d-ldrtc 0/1 Pending 0 29s
kube-system etcd-k8s-master 1/1 Running 0 34s
kube-system kube-apiserver-k8s-master 1/1 Running 0 36s
kube-system kube-controller-manager-k8s-master 1/1 Running 0 34s
kube-system kube-proxy-7kx42 1/1 Running 0 29s
kube-system kube-scheduler-k8s-master 1/1 Running 0 34s

[root@k8s-master ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master NotReady control-plane 3m44s v1.31.14

配置集群网络

k8s 集群网络有很多种方案,这里就列几种最常用的方案(cilium、flannel、calico…)配置方法,选择任意一种即可。

cilium

使用 cilium 1.18.4 作为集群的网络方案,

cilium 安装需要使用 helm,首先我们安装 helm(需要启用 epel 源),

yum install -y helm

通过 helm 安装 cilium,

# 下载 cilium helm charts 包
wget https://github.com/cilium/charts/blob/master/cilium-1.18.4.tgz

# 安装 helm charts, k8sServiceHost 替换为真实的 APISEerver IP
helm install cilium cilium-1.18.4.tgz -n kube-system \
--set kubeProxyReplacement=true \
--set bpf.masquerade=true \
--set k8sServiceHost="x.x.x.x" \
--set k8sServicePort=6443 \
--set operator.replicas=1

Tips: 注意将 Charts 中 k8sServiceHost&k8sServicePort 设置为 APIServer 使用的 IP&Port,避免出现 Unable to contact k8s api-server 错误。
https://github.com/cilium/cilium/issues/20679

验证 cilium Pod 正常启动,

# kubectl -n kube-system get pods | grep cilium
cilium-5bkvp 1/1 Running 0 1m
cilium-envoy-rzcns 1/1 Running 0 1m
cilium-operator-7b95d7d76d-kp297 1/1 Running 0 1m

flannel

使用 flannel 0.26.2 作为集群的网络方案

# 下载 flannel 配置
wget https://github.com/flannel-io/flannel/releases/download/v0.26.2/kube-flannel.yml

# 提前下载 flannel 所需镜像,使用 daocloud 源
# 不同版本 flannel 采用的镜像版本不同,镜像版本查看 kube-flannel.yml 文件即可
crictl pull m.daocloud.io/docker.io/flannel/flannel:v0.26.2
crictl pull m.daocloud.io/docker.io/flannel/flannel-cni-plugin:v1.6.0-flannel1

# 替换镜像地址
sed -i 's|docker.io|m.daocloud.io/docker.io|' kube-flannel.yml

# 执行
kubectl apply -f kube-flannel.yml

Node节点加入集群(可选)

至此,一个单节点的集群已经部署完成了。如果需要往集群中添加别的节点,通过 kubeadm join 命令可以轻松实现。

kubeadm 创建集群完成后,会升成一条 join 命令用于节点加入集群,如果这条命令没保存也没有关系。让 master 重新生成一个 token 即可。

将 Node 节点加入集群前,参考上文的配置部分,安装必要软件,

  • 关闭 firewalld
  • 安装 containerd
  • 安装 kubernetes
  • 安装 crictl
  • 加载内核模块和修改内核配置

master 执行后会得到一个 join 命令,在 Node 节点执行即可

[root@k8s-master ~]# kubeadm token create --print-join-command
kubeadm join x.x.x.x:6443 --token jpqqsk.ion4kc134qm2z8zv --discovery-token-ca-cert-hash sha256:f40dadc8070ff0218bcfe8530974937a95e3cd1e2d25cd5f865669ac3b40bdb1

FAQ

如何 debug flannel 启动失败问题?

当集群 apiserver 正常时,通过查看 flannel pod 的 日志确认错误

kubectl logs kube-flannel-ds-xxxxx -n kube-flannel

Debug flannel with pod logs

登录到问题节点,通过 crictl logs [flannel-container] 查看 flannel 容器日志

Debug flannel with pod logs

参考

1、https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md

2、https://juejin.cn/post/7383894854152405043

3、https://docs.cilium.io/en/stable/installation/k8s-install-helm