本文介绍如何使用 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
sed -i 's|registry.k8s.io/pause|registry.aliyuncs.com/google_containers/pause|' /etc/containerd/config.toml
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,
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 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 源),
通过 helm 安装 cilium,
wget https://github.com/cilium/charts/blob/master/cilium-1.18.4.tgz
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 正常启动,
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 作为集群的网络方案
wget https://github.com/flannel-io/flannel/releases/download/v0.26.2/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

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

参考
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