ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

kubeadm部署Kubernetes集群完整指南:从环境准备到应用验证

2026/10/8 8:54:35 拓冰建站 浏览量
kubeadm部署Kubernetes集群完整指南:从环境准备到应用验证 写这篇东西的初衷是最近又双叒有朋友来问我K8s到底怎么装网上教程要么太老、要么版本对不上、要么装到一半卡死在镜像拉取上一整天。我自己前前后后搭过不少次集群从单机到三节点到高可用都折腾过深知新手在kubeadm这条路线上能踩多少坑。所以这次干脆把整个流程完整梳理一遍从环境准备到节点加入、网络插件、Dashboard、再到应用部署验证按着一步一步来就能复现出一套能用的Kubernetes集群。这套内容围绕“Kubernetes 集群搭建与配置”展开会讲清楚每一步为什么这么做、参数怎么选、出了问题怎么排查适合完全没接触过K8s的小白也适合搭过但是总翻车的老手过来对一遍思路。全文基于kubeadm方式进行部署这是目前官方推荐的集群构建工具也是社区里用得最多、资料最全的方式。1. 部署前的核心决策与方案选型1.1 版本选择别当小白鼠也别用太旧的版本很多教程翻车第一步就栽在版本上。Kubernetes版本节奏很快一个版本的支持周期大概是一年左右新版本出来大家可以尝鲜但生产环境我建议选择当前已发布稳定版的前一个版本或者发行版官方明确标记为稳定支持的版本。以kubeadm方式部署时kubeadm、kubelet、kubectl三个组件的版本必须保持一致这是铁律。我自己用下来的推荐组合是控制平面节点2核4G起步工作节点2核4G系统盘40G以上操作系统选Ubuntu 22.04或者CentOS Stream 9均可。内存这块多说一句如果是单机All-in-One测试环境4G内存跑起来会有点紧张建议6G到8G会比较舒服。容器运行时我直接选了containerd而不是Docker。Kubernetes从1.24版本开始彻底移除了对Docker的默认支持虽然可以通过cri-dockerd适配但这个方案本身有点绕路生产环境没必要这么做。containerd是CNCF的毕业项目也是K8s原生支持的运行时性能更好、更轻量排查问题的时候日志也更直接。1.2 网络模型规划Pod网段和Service网段要提前想清楚Kubernetes集群内部有三个网段要区分开宿主机网络、Pod网段、Service网段。宿主机网络就是机器本身的IPPod网段是分配给Pod的IP池由CNI插件管理Service网段是集群内部虚拟服务的IP池由kube-apiserver分配。这三个网段必须互不重叠否则路由表会乱掉后面排查网络问题会非常头疼。我推荐一主二从或者三主三从的拓扑但教程里先用一主二从来演示后续扩展思路会简单写一下。Pod网段我习惯用10.244.0.0/16Flannel默认值就是这个网段Service网段用10.96.0.0/12kubeadm默认值。如果选Calico插件Pod网段通常用192.168.0.0/16这个后面会在CNI章节细说。网段规划决定了后面kubeadm init时--pod-network-cidr参数的取值所以一定要提前定好。最怕的情况是装完Flannel之后发现Pod CIDR和已有的物理网络冲突这时候就得把CNI插件卸载重装了。1.3 主机规划表给每台机器起好名字并固定IP正式部署前我强烈建议先画一张表格把主机角色、IP、系统版本、配置都列清楚。规划好之后就不用再动因为后面很多配置是基于主机名和IP做的中途改名字和改IP等于给自己挖坑。主机名角色节点IP配置系统k8s-master控制平面192.168.1.102C4GUbuntu 22.04k8s-worker1工作节点192.168.1.112C4GUbuntu 22.04k8s-worker2工作节点192.168.1.122C4GUbuntu 22.04这里注意一点主机名不要用默认的localhost或者带下划线推荐用短横线连接的命名方式比如k8s-master、k8s-node-01。带下划线的主机名在某些K8s组件的证书生成和解析过程中会报错虽然概率不算高但没必要在这种地方冒险。2. 基础环境准备系统配置与容器运行时2.1 操作系统初始化关闭交换分区、配置内核参数、设置时间同步所有节点都要做同样的一套基础配置这一步漏了后面会出各种奇怪问题。首先是关闭swapKubernetes从1.8版本开始强制要求关闭交换分区如果不关闭kubelet启动后会直接报错kubeadm init也会失败。关闭的方式是执行swapoff -a同时把/etc/fstab里swap那一行注释掉否则重启之后swap又回来了。然后是内核模块和网络桥接参数。K8s的Service转发依赖iptables和ipvs需要确保几个关键模块加载并启用。这里我把完整的一段内核参数配置贴出来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这段配置目的是让iptables能处理经过Linux网桥的流量同时开启IPv4转发容器访问外部网络的依赖就在这里。时间同步也要做集群内节点时间偏差过大会导致kubelet证书验证失败排查起来非常隐蔽。Ubuntu上装chrony或者systemd-timesyncd都行CentOS上装chrony确保集群内所有节点时间一致。2.2 安装并配置containerdcgroup驱动与镜像加速缺一不可containerd是K8s的容器运行时负责拉取镜像、管理容器生命周期。安装很简单直接用Docker的软件源即可因为containerd本来也是Docker体系下的产物。Ubuntu上执行以下命令sudo apt-get update sudo apt-get install -y containerd安装完成后先别急着启动要改配置文件。默认情况下containerd没有配置文件需要手动生成一个sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml然后需要修改两个关键地方。第一是SystemdCgroup参数必须设置为true因为Kubernetes默认使用systemd作为cgroup driver而containerd默认是cgroupfs如果不改成一致kubelet会报容器运行时错误。第二是沙箱镜像地址国内的网络环境下默认的registry.k8s.io拉不下来需要替换成国内可访问的镜像地址[plugins.io.containerd.grpc.v1.cri] sandbox_image registry.aliyuncs.com/google_containers/pause:3.9 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] runtime_type io.containerd.runc.v2 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true修改完后重启containerd并设置开机自启sudo systemctl daemon-reload sudo systemctl restart containerd sudo systemctl enable containerd里面有个小坑提示下老版本的containerd config.toml里路径字段跟新版本不一样如果你按照网上的老教程去改可能发现字段根本不存在。建议第一步就检查版本containerd --version新版用我上面给的字段格式。2.3 安装kubeadm、kubelet、kubectl版本锁定的正确姿势安装K8s三件套核心就一个字锁定版本。不要直接apt install kubeadm然后让它装最新版这样很容易装出个刚发布不到两周的版本后续跟kubelet版本对不上就麻烦了。先把源配上sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl gpg curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo deb [signed-by/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ / | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubelet1.28.2-1.1 kubeadm1.28.2-1.1 kubectl1.28.2-1.1三个组件版本号保持一致。安装后用apt-mark hold把版本锁住防止执行apt upgrade时意外升级sudo apt-mark hold kubelet kubeadm kubectl为什么lock版本这么重要因为K8s的API Server、Controller Manager和Scheduler三个控制平面组件是跟着kubeadm走的kubelet又是独立部署在每个节点上如果版本漂移集群里可能会出现API Server是1.28kubelet已经是1.30的情况这种集群表面上能跑但官方支持的版本偏移最多一个次要版本超过之后很多功能会异常。3. 控制平面初始化与工作节点加入3.1 kubeadm init前的必查清单镜像预拉取与参数核对在执行kubeadm init之前我建议先做三件准备工作能省掉一大半的返工时间。第一件是预拉取镜像。执行下面的命令把控制平面需要的所有容器镜像拉到本地sudo kubeadm config images pull因为前面配好了国内的镜像加速地址这一步正常情况下很快就能完成。如果这一步骤卡住不动大概率是containerd的sandbox_image没有改对回2.2重新检查一遍。预拉取的好处在于init的时候不会因为镜像拉取超时而中断你能区分出错误是发生在网络环节还是组件启动环节。第二件是确认本机IP和主机名。再啰嗦一句检查 /etc/hosts 里面有没有把当前主机名解析到正确的IP上有时候云主机默认hostname改了但自解析没更新init的时候用错IP去生成证书导致kubectl连不上API Server。第三件是核对初始化参数。我自己用的一主两从配置初始化命令长这样sudo kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --control-plane-endpoint192.168.1.10 \ --image-repositoryregistry.aliyuncs.com/google_containers \ --kubernetes-versionv1.28.2 \ --pod-network-cidr10.244.0.0/16 \ --service-cidr10.96.0.0/12各参数含义逐个说明一下--apiserver-advertise-address指定API Server对外通告的IP就是Master节点的IP--control-plane-endpoint用于搭建高可用集群时指向负载均衡器IP单机时跟前面保持一致--image-repository指定镜像仓库地址--pod-network-cidr后面要跟CNI插件的网段配置对应Flannel就填10.244.0.0/16--service-cidr用默认值就好。3.2 执行初始化从init到kubectl可用的完整流程初始化过程大约2到5分钟取决于机器性能。输出末尾会有两段关键信息一段是kubeconfig的配置命令另一段是让worker节点加入集群的kubeadm join命令。这两段一定要保存下来。先把kubeconfig配置好让kubectl能操作集群mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config然后验证集群状态kubectl get nodes输出中Master节点状态是NotReady这是正常的因为CNI网络插件还没装节点就绪检查还没法通过。别慌下一步装网络插件就解决了。如果你需要让其他普通用户也管理集群可以把admin.conf复制到对应用户的~/.kube/config目录下并修改文件归属权限。生产环境建议使用RBAC创建独立的管理员账号而不是直接分发admin.conf这里测试环境先不展开。3.3 worker节点加入集群token有效期与常见报错处理回到worker1和worker2节点上执行init时输出的join命令。正常情况下join命令长这样sudo kubeadm join 192.168.1.10:6443 --token xxxxxx.xxxxxxxxxxxx \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx执行完成后在master节点上执行kubectl get nodes应该能看到三个节点陆续Ready。新节点加入后kubelet会自动从API Server获取证书并启动Pod这个过程需要一点时间1到3分钟都算正常。token默认有效期是24小时如果你在配置过程中把join窗口错过了需要重新生成token。这算是新手最容易卡住的地方之一。重新生成token的命令如下kubeadm token create --print-join-command输出里会带新的token和hash复制给worker执行即可。还有个高频报错是[preflight] Some fatal errors occurred提示[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables contents are not set to 1这说明你的基础环境准备没做完整回到2.1重新检查内核参数配置。node节点这些基础配置必须全部完成不能直接跳过来join。3.4 控制平面节点扩副本第二台Master怎么加如果你的目标是搭建高可用集群控制平面至少要有3个节点。在上面构建好的基础上把Master的bind mounts和证书复制到第二个控制平面节点再执行kubeadm join加上--control-plane标志sudo kubeadm join 192.168.1.10:6443 --token xxxxxx.xxxxxxxxxxxx \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxx \ --control-plane不过这套流程就不展开了属于进阶用法核心是把第一台Master的/etc/kubernetes/pki下所有文件同步到其他控制平面节点上再用负载均衡器统一对外服务。新手建议先把单控制平面玩熟了再往高可用方向延展。4. CNI网络插件与核心组件验证4.1 Flannel还是Calico怎么选、怎么装、怎么验网络插件是整个Kubernetes里最容易出问题的环节也是最影响使用体验的。Flannel和Calico两选一。Flannel的特点是轻量、简单、性能够用适合大多数中小规模集群和测试环境。它的原理是用VXLAN或者host-gateway把Pod网段的路由信息广播到所有节点上每个节点维护一个路由表容器跨节点通信就走这个隧道。安装方式非常直接kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml执行完后等Pod运行起来检查状态kubectl get pods -n kube-flannel -o wide如果flannel Pod一直CrashLoopBackOff最常见的原因是Pod网段和实际容器网段冲突或者节点主机名解析失败。可以查看日志确认kubectl logs -n kube-flannel pod-name --tail50Calico则是功能更全的网络策略引擎支持NetworkPolicy适合对安全隔离有要求的生产环境。缺点是组件更多资源占用更高调试也复杂一些。安装方式也不复杂kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yamlCalico对Pod网段有自己的要求如果你用的默认配置Pod网段得是192.168.0.0/16这个在init的时候就要规划好。如果你要么选择Flannel要么选择Calico那就别两个都装装两个网络插件会导致路由规则互相冲突这是新手最常犯的错。4.2 验证CoreDNS、kube-proxy与集群自检网络插件就位后节点状态会从NotReady变为Ready此时建议做一轮系统自检。看所有核心组件Pod的状态kubectl get pods -n kube-system重点关注coredns是否Running。CoreDNS是集群内部DNS服务Pod之间通过服务名解析依赖它。如果它一直Pending多半是节点调度不下或者是CNI还没就绪导致没法分配IP。还有kube-proxy它负责实现Service的负载均衡和转发规则运行在每个节点上通常以DaemonSet形式部署。检查完Pod状态后再检查一下节点状态kubectl get nodes所有节点都Ready之后集群基础层面就算跑通了。接着可以部署一个测试应用来验证集群实际可用性最简单的就是nginx。4.3 快速验证集群可用性启动一个nginx工作负载创建一个deployment副本数设置3个让Pod分散在不同工作节点上kubectl create deployment nginx-test --imagenginx:alpine kubectl scale deployment nginx-test --replicas3 kubectl expose deployment nginx-test --typeNodePort --port80用kubectl get pods查看状态三个Pod都是Running以后用NodePort方式访问一下nginx的欢迎页。NodePort的端口范围默认是30000-32767expose之后用下面命令查到实际端口kubectl get svc nginx-test -o wide然后在浏览器里打开任意节点的IP加上这个NodePort端口看到nginx欢迎页就算集群完全可用。我实测下来这个流程从init到部署应用成功大约30分钟这批保姆级的操作都是这个速度。5. Kubernetes Dashboard部署与可视化管理5.1 Dashboard安装与token登录配置命令行玩得再熟有个可视化界面总归方便一点特别是看Pod日志、看集群资源占用Dashboard比kubectl直观得多。安装Dashboard其实就是一条apply命令的事kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml安装完成后Dashboard默认账号权限很低直接访问会告诉你没有权限。需要创建一个管理员账号cat EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard EOF然后获取登录用的tokenkubectl -n kubernetes-dbernetes create token admin-user注意新版这个命令是create token老教程里用describe secret的写法在1.24之后已经拿不到token了因为ServiceAccount默认不再自动创建Secret资源。5.2 通过API Server代理访问DashboardKubernetes的Service默认是ClusterIP外部访问Dashboard需要加一层代理最快速的方式是kubectl proxy。kubectl proxy 然后浏览器打开http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/把上一步生成的token粘贴进去就能进入Dashboard界面了。这方式只适合本机管理生产环境建议给Dashboard配Ingress暴露到内网域名加上HTTPS证书和RBAC权限控制。5.3 给集群装一个横向火箭Metrics Server没有Metrics Server之前kubectl top和Dashboard的资源监控图都用不了因为集群没有收集指标的能力。安装metrics-serverkubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml国内网络拉gcr.io的镜像容易失败如果遇到ImagePullBackOff可以把metrics-server的deployment镜像地址改成国内镜像源或者提前用containerd把镜像拉到所有节点上。这一步做完扩容缩容、HPA这些功能才真正能用起来。6. 常见问题与排查技巧实录6.1 问题速查表从NotReady到CrashLoopBackOff整理一张真实环境中最高频的排查表覆盖从搭建到使用的这段时间里最容易踩的坑现象可能原因排查/解决办法节点NotReadyCNI没有安装或安装失败检查内核参数、重新apply CNI插件CoreDNS Pending节点内存不足或CNI未就绪用top查看节点资源清理无用进程kubelet启动失败swap未关闭或cgroup驱动不一致执行swapoff -a检查containerd配置镜像拉取失败默认源无法访问看2.2节替换sandbox_image和仓库地址node join失败token过期或CA hash不对用kubeadm token create命令重新生成flannel报错Pod网段与物理网络冲突确认init时的CIDR与flannel配置一致kube-proxy CrashLoop节点内核模块未加载检查br_netfilter模块是否已加载6.2 节点清理与重来kubeadm reset的正确使用方式集群搭到一半搞坏了与其在坏集群上不断修不如回到干净状态重来。很多新手不知道kubeadm reset就是干这个的sudo kubeadm reset -f sudo rm -rf /etc/cni/net.d ~/.kube systemctl restart containerdreset会把你当前节点的kubelet配置、证书、CNI配置全部清掉但不清理容器运行时和数据目录。如果想连容器一起清理用crictl rm -a清掉container再用crictl rmi --all清掉镜像。这套做法在测试环境反复验证很管用切换CNI插件的时候也需要这样走一遍。6.3 证书过期场景与节点重新加入如果集群吃灰几个月后再回来用大概率碰到证书过期问题。K8s控制平面的证书有效期默认是一年过期后kube-apiserver无法启动。最快的方式是死亡重来但如果你想把集群救回来用kubeadm的renew命令sudo kubeadm certs renew all sudo kubeadm init --phase kubeconfig systemctl restart kubelet证书续期之后原有的kubeconfig也需要重新生成才能连上API Server。步骤上是先renew再重启kubelet再拷贝admin.conf到本地使用。证书续期操作结束后务必确认各组件状态正常再离开现场不然很容易出现只续了一半证书的情况后续排查更痛苦。6.4 实用的调试三板斧事件、日志、describe其实排查K8s问题翻来覆去就是三板斧。第一板斧是看事件kubectl describe pod pod-name -n namespace第二板斧是看日志kubectl logs pod-name -n namespace --tail100第三板斧是看节点状态kubectl describe node node-namedescribe里最能暴露问题的往往是Events这一栏Pod调度失败、镜像拉取失败、探针失败都会在这里留下记录。比如调度失败会写Insufficient memory或者node.kubernetes.io/not-ready看到关键字基本就能定位问题方向。6.5 网络链路排查从Service到Pod的连通性验证集群搭好后应用之间互相通信也可能碰到问题特别是首次接通的时候。有一个很标准的排查思路先验证Pod层通不通再验证Service层通不通最后验证跨节点通不通。Pod层的验证方法是进入一个Pod去ping另一个Pod的IP。Service层的验证方法是进入Pod去访问Service的ClusterIP和端口。跨节点验证则要看观察flannel的隧道接口或者Calico的BGP路由是否正常。通常Pod之间通、Service不同多半是kube-proxy的iptables规则没刷新Pod之间都不通问题就在CNI插件上。7. 集群扩展与日常运维建议7.1 如何扩展工作节点新增节点的完整步骤后续需要扩展集群能力时新增工作节点的流程比较简单跟搭第一台worker完全一样把环境准备阶段的全部配置再做一遍安装kubeadm、kubelet、kubectl然后执行join命令即可。注意新增节点也要执行2.1到2.3的所有系统配置不能跳步骤直接join。我也建议新节点加入后用之前提到的方法验证一下kubectl get nodes确认Ready状态然后在集群里跑一个临时Pod调度到这个节点上确认实际跨节点容器通信正常。别等上了生产流量才发现新增节点连不上存储或者网络不通。7.2 集群升级的最小路径先升级kubeadm到目标版本在控制平面节点执行kubeadm upgrade plan检查可升级版本和升级路径然后逐节点升级kubelet和kubectl。升级顺序不能乱先控制平面后工作节点每个节点要执行kubeadm upgrade node再升级kubelet二进制版本。升级前务必把etcd快照备份一份这个动作在关键操作时能救命。7.3 日常运维备份清单最后整理一份我自己的备份清单供参考。etcd是K8s集群的数据库所有集群状态都在里面是需要第一个备份的对象。其次是PV存储里的数据由各存储后端决定备份策略。更重要的是把集群的部署清单纳入版本管理所有deployment、service、configmap都放在Git仓库里出了问题可以复盘版本变更记录。etcd备份可以用一条命令完成ETCDCTL_API3 etcdctl --endpointshttps://127.0.0.1:2379 \ --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/server.crt \ --key/etc/kubernetes/pki/etcd/server.key \ snapshot save /backup/etcd-snapshot-$(date %Y%m%d).db就我个人实际搭建和运维的经验来说K8s集群的复杂度不在某个单点上而是组件之间环环相扣版本、网络、存储、证书、DNS任何一个环节出问题都能让集群状态变得不可用。但如果从底层容器运行时到上层应用一步步验证过来这套体系其实非常适合小团队维护。最后再分享一个技巧碰到所有Pod都调度不了的场景先别急着看各种配置去检查资源余额和污点多半是这两个里有个坑等着你。