恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
用kubeadm快速搭建Kubernetes集群:从初始化到生产实践
首页
资讯中心
/
用kubeadm快速搭建Kubernetes集群:从初始化到生产实践
用kubeadm快速搭建Kubernetes集群:从初始化到生产实践
发布时间:2026/10/16 6:12:36
很多朋友问我到底怎么把一套 kubernetes 集群在最短时间内搭起来既不是那种只能在笔记本上跑的单机玩具也不是需要手动维护几十个二进制服务的硬核模式。我的答案一直是同一个kubeadm。它是 Kubernetes 官方提供的集群初始化工具也是我这些年搭测试环境、给团队做学习平台、甚至在正式环境做基础验证时用得最多的方式。用 kubeadm 快速部署一个 kubernetes 集群从一台裸机到 master 节点就绪大概十几分钟再加上 worker 节点、网络插件、验证应用一个小时内你就能拥有一套标准、可用、能继续扩展的 k8s 集群。读这篇博文的人我猜大概有三类第一类是刚接触 k8s想把官方工具链完整走一遍的新手第二类是手头有虚拟机或内网服务器需要快速搭一套用于开发和测试的环境第三类是准备考证或者在生产环境做小范围验证的工程师。不管你是哪类都不需要预先掌握太多原理。照着步骤操作一遍再回头理解设计思路会比死记命令快很多。1. 为什么我推荐 kubeadm而不是 minikube 或二进制部署1.1 kubeadm 到底替你做了什么很多人第一次接触 kubeadm 时容易把它理解成“一键安装脚本”。实际上它做的事情比脚本更克制也更巧妙。kubeadm init主要负责两件事一是生成控制平面组件所需的一整套证书、私钥、kubeconfig 配置文件二是把 etcd、kube-apiserver、kube-controller-manager、kube-scheduler 这些控制平面组件以静态 Pod 的方式放到/etc/kubernetes/manifests目录下交给 kubelet 来拉起和维护。这个设计非常关键。控制面组件不再需要各自注册成 systemd 服务而是统一用 Pod 清单来描述。任何组件的配置、日志、重启行为都变成了 Pod 级别你可以用kubectl get pods -n kube-system查看状态也可以借助容器运行时直接看日志。这种“用 kubelet 管控制面”的思路从根源上降低了排障复杂度。kubeadm join则负责把工作节点接入集群它会验证 token 和证书指纹生成该节点单独的 kubelet 证书和引导配置让节点上的 kubelet 去访问 apiserver 完成注册。1.2 几种部署方式到底该选哪个我一直建议初学者用一张表格把常见方式放在一起比比单独理解一个工具更清楚。这里是我自己的对比结论部署方式适合场景控制面组件形态网络插件生产适用性学习价值minikube本地单机学习单节点通常不关注控制面细节内置不适合中kind本地或 CI 跑测试容器化的单/多节点内置或自装不适合中kubeadm测试环境、生产基础静态 Pod由 kubelet 托管自选适合高Kubespray大规模生产、批量部署以容器方式运行控制面自选适合中二进制部署深度定制、信创环境systemd 服务自选适合但维护重很高从这张表能看出来kubeadm 的定位非常像“折腾和生产的折中点”它保留了官方组件编排方式没有引入太多额外抽象生产环境中多控制面高可用方案就是基于它扩展的。如果你用二进制部署确实能深入理解每一个组件的启动参数但时间成本高很多也不容易迁移到自动化的运维体系里。minikube 和 kind 则更适合个人电脑上做功能验证它们对网络插件、多节点通信的模拟并不完全真实。1.3 kubeadm 作为生产起点的三个理由第一升级路径清晰。Kubernetes 每三个月发一个小版本安全更新很重要。kubeadm 提供kubeadm upgrade plan和kubeadm upgrade apply官方会提前验证升级路径你只需要按顺序处理控制面和节点。第二证书管理内置。kubeadm 会自动生成 CA 和各组件证书并提供kubeadm certs renew续期命令。第三配置可查看、可审计。kubeadm config view能把集群初始化配置导出成 YAML方便你保存到 Git 仓库里做变更管理。我见过不少团队用 kubeadm 初始化后再配合 Terraform、Ansible 或者裸机平台来自动化效果相当好。它的配置结构简单、依赖少不管上层用什么编排底层始终是同一套标准目录和清单。2. 部署前那些关键准备漏一个都要回头补2.1 节点规划多大机器才够用先说结论如果你只是学习和验证一台 master 加两台 worker 是最舒服的配置保证能观察到 Pod 调度到不同节点的真实效果。单节点也可以但你需要容忍 Master 和 Worker 混跑带来的 taint 处理而且很多网络插件在单节点下容易出现与预期不符的情况。硬件方面控制面节点建议至少 2 核 4G 内存工作节点建议 2 核 2G 起步。内存低于 2G 时etcd 会频繁触发 OOM哪怕集群起来了也会非常不稳。磁盘最好是 SSD尤其 etcd 的数据目录/var/lib/etcd对 IO 延迟敏感。操作系统我建议选 Debian 系的长期支持版本比如 Ubuntu 22.04 或 Debian 12内核版本够新对 overlay 网络和 iptables 的支持也友好。所有节点的主机名不要重复比如k8s-master-01、k8s-node-01并且建议在/etc/hosts里写好互相解析避免有些组件反向解析出问题。2.2 系统初始化四件套每件都有原因第一件事是关闭 swap。kubelet 在资源管理上假设节点没有 swap如果开着它统计内存水位时会出错节点也会经常处于 Ready 但调度不稳定的状态。执行sudo swapoff -a sudo sed -i / swap / s/^/#/ /etc/fstab第二件事是加载内核模块overlay和br_netfilter。前者是容器分层文件系统的底层依赖后者让网桥流量能通过 iptables/netfilter 规则进行处理这是 kube-proxy 和网络插件工作的前提。cat EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter第三件事是设置 sysctl 参数。有两个参数非常关键net.bridge.bridge-nf-call-iptables1确保经过 Linux 网桥的流量也受 iptables 规则管控net.ipv4.ip_forward1开启内核转发Pod 之间的跨节点通信、Service 的转发都依赖它。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第四件事是时间同步。Kubernetes 的证书校验、日志时间戳、etcd 的一致性都依赖各节点时间接近。生产环境里节点时间漂移超过几百毫秒就可能引发奇怪问题。建议所有节点统一配置 NTP 时间同步服务如果你用的是云主机一般默认就带裸机的话需要自己确认一下。2.3 容器运行时现在默认选 containerd从 Kubernetes 1.24 开始内置的 dockershim 被移除官方默认推荐使用 containerd 作为容器运行时。你当然也可以用 CRI-O但 containerd 生态成熟、兼容性最好也是绝大多数发行版的默认选择。安装 containerd 的方式很多Debian/Ubuntu 上直接sudo apt-get update sudo apt-get install -y containerd安装后需要生成默认配置并做一处关键修改sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml打开/etc/containerd/config.toml找到SystemdCgroup这个配置。默认值是false需要改成true[plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] ... [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true这一步太容易踩坑了。kubelet 默认使用 systemd 作为 cgroup 驱动containerd 如果还在用 cgroupfs两边就不一致节点注册后会一直处于 NotReady 状态而日志里只会报一些含糊的 cgroup 错误。改完配置后重启 containerd 并设置开机自启sudo systemctl restart containerd sudo systemctl enable containerd2.4 安装 kubeadm、kubelet、kubectl这三个工具建议在所有节点都装上版本必须保持一致。官方提供了软件源以 v1.30 为例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.30/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.30/deb/ | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl安装后一定记得锁定版本sudo apt-mark hold kubelet kubeadm kubectl不锁定版本的后果很直接下次你执行apt-get upgradekubeadm 可能自动升到新版kubelet 还在旧版两边不兼容集群直接罢工。安装完成后可以检查版本kubeadm version kubelet --version kubectl version --client这里有个需要留意的细节无论是否使用官方源你都要确认当前节点能访问你选择的软件源。如果是内网环境提前把 deb 包镜像好统一分发比所有节点各自访问外网要稳定得多。3. 初始化 master 节点关键参数一次说明白3.1 先看懂这条 init 命令再执行在 master 节点上最重要的就是一条命令。我建议你不要直接复制网上看到的命令而是先理解每个参数的含义sudo kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --pod-network-cidr10.244.0.0/16 \ --service-cidr10.96.0.0/12 \ --image-repositoryregistry.k8s.io \ --kubernetes-versionv1.30.2参数逐个说。--apiserver-advertise-address是 master 节点上 kube-apiserver 对外通告的 IP 地址。kubectl、worker 节点、外部负载均衡器都会连这个地址。如果节点有多块网卡必须明确指定否则可能出现 APIServer 监听在 0.0.0.0但证书和负载均衡连接的 IP 不对的情况。--pod-network-cidr是 Pod 网段。你之后安装网络插件时插件默认的 CIDR 必须和它一致否则 Pod 之间跨节点通信会断掉。这里我写10.244.0.0/16是 Flannel 插件默认使用的网段如果你计划用 Calico它的默认网段是192.168.0.0/16那 init 参数就要改成--pod-network-cidr192.168.0.0/16。选哪个插件提前想好避免事后返工。--service-cidr是 Service 的虚拟网段默认10.96.0.0/12一般不需要改。但要注意一点这个网段一旦确定后续很难变更因为 kube-proxy 的 iptables 规则、DNS 的 ClusterIP 都会基于它生成。--image-repository是控制面组件镜像的仓库地址。默认是registry.k8s.io如果你的网络访问它不稳定就换成一个本地可达的镜像同步仓库。第一次初始化建议先执行kubeadm config images pull --image-repository你的仓库确认镜像能拉下来再真正 init能省很多等待时间。--kubernetes-version建议明确写上不要省略。省略时 kubeadm 会用最新稳定版而你本地的 kubectl、kubelet 可能锁定在另一个版本版本不匹配会引起很多奇怪问题。3.2 执行 init留意输出里的三块信息执行 init 后kubeadm 会做一系列预检包括端口占用、swap 状态、内核参数等。如果预检失败它会明确告诉你哪一项没过。预检通过后开始拉镜像、生成证书、启动静态 Pod这一步可能需要几分钟。init 成功时最后一段输出会非常显眼Your Kubernetes control-plane has been initialized successfully!然后会给出三块你马上要用的信息。第一块是配置 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 不知道集群在哪里。第二块是一整条kubeadm join命令它包含 token 和--discovery-token-ca-cert-hash是 worker 节点加入集群的钥匙。建议先存到本地文本文件里后边要用。第三块是说明Pod 网络尚未就绪之前master 节点会一直显示 NotReady这是正常现象不用慌。3.3 接入 Calico 网络插件Pod 网络不装节点永远无法 Ready核心 DNS 服务也会一直 CrashLoopBackOff。网络插件我优先推荐 Calico它性能不错功能也多。安装 Calico 的方式通常是这样kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/calico.yaml如果你在 init 时指定的--pod-network-cidr不是 Calico 默认的192.168.0.0/16就需要先下载清单文件找到环境变量CALICO_IPV4POOL_CIDR改成你实际使用的网段再 apply。这也是为什么我建议先把 CIDR 规划好再初始化。Calico 的清单里包含了一个 DaemonSet会在每个节点上启动 calico-node Pod同时安装 CNI 插件、生成/etc/cni/net.d/配置。这一步顺利完成后等所有 calico 相关 Pod 进入 Running再执行kubectl get nodes节点应该会变成 Ready 状态。网络插件安装过程中偶尔会出现 calico-node 反复重启的情况最常见原因是CALICO_IPV4POOL_CIDR和 init 参数不一致或者节点时间不同步导致的证书问题。3.4 控制平面组件都健康了吗初始化完成、网络插件装好后第一件事就是看核心组件状态kubectl get nodes kubectl get pods -Akubectl get nodes应该能看到 master 节点状态为 Readykubectl get pods -A能看到 kube-system 命名空间下的 etcd、kube-apiserver、kube-controller-manager、kube-scheduler、coredns、calico-node 等 Pod 都处于 Running 状态。这里我想特别提醒一下很多人习惯用kubectl get componentstatus来看控制面健康状态但从很多版本开始这个命令输出的结果已经不再反映真实情况了它可能显示 etcd 是 healthy但实际上 etcd Pod 早就坏了。不要依赖它直接看 Pod 状态才是准确的。4. 把 worker 节点加进来让集群真正“集”起来4.1 join 命令从哪儿来worker 节点加入集群最标准的方式就是执行一条kubeadm join命令。这条命令在 init 成功输出里会直接打印出来长这样kubeadm join 192.168.1.10:6443 --token token --discovery-token-ca-cert-hash sha256:hash如果你当时没保存可以在 master 节点上重新生成kubeadm token create --print-join-command这个命令的简介之处在于它会自动生成 token同时算出 CA 证书的 hash 并拼成完整命令。token 默认有效期是 24 小时过期后重新跑一次就行。有个细节值得展开--discovery-token-ca-cert-hash的作用是让节点验证 master 的 CA 证书是否是可信的那张。简单说它能防止你加入一个伪装成 master 的中间人。如果你从别处抄来的命令省略了这个参数kubeadm 会进入交互式确认流程不安全也不方便。4.2 在 worker 节点上执行 join在每个 worker 节点上用 root 或者 sudo 执行上面的 join 命令。执行过程中kubelet 会启动节点会自动向 master 发起注册。执行完回到 master 节点kubectl get nodes你就能看到新的 worker 节点出现在列表里。刚加入时它的状态大概率是 NotReady因为 Calico 的 Pod 还没在这台机器上启动网络插件还没有就绪。等几十秒到几分钟再执行一次状态就会变成 Ready。这里还要提一个常见误区有人会想“我能不能在 master 节点上 join 一次让这台机器同时成为 worker 节点”理论上可以但默认 init 会给 master 打上node-role.kubernetes.io/control-plane的污点普通工作负载不会调度上去。如果你确实想跑测试负载需要单独去掉污点而不是把一个节点既当 master 又当 worker 去 join。4.3 跑个 nginx 验证集群是真的能用节点全部 Ready 后别急着收工跑一个真实工作负载验证。我习惯用一个简单的 Deploymentkubectl create deployment nginx --imagenginx:1.25 kubectl scale deployment nginx --replicas3 kubectl get pods -o wide这时候你能看到三个 nginx Pod 分布在不同的节点上这就是集群调度能力的直接体现。接着创建一个 Service 暴露它kubectl expose deployment nginx --port80 --typeNodePort kubectl get svc nginx能看到 Service 分配了一个 NodePort 端口可能是 30000 到 32767 之间的某个值。然后你从集群外部访问任意节点的这个端口比如http://192.168.1.10:30080如果 Nginx 页面正常返回说明 Pod 网络、Service 转发、节点到容器的链路全部通畅。这一步的验证价值非常大因为它同时验证了 kube-proxy 的 iptables 规则、CNI 的跨节点网络以及 DNS 转发能力。5. 实操中最常见的坑我全部帮你踩过5.1 卡在等待 API server镜像跟不上现象是kubeadm init执行后一直停在“waiting for the Kubernetes API server to start”日志里能看到一堆拉镜像失败的记录。最常见原因就是镜像仓库访问不稳定。解决办法有两个第一个是在 init 前先执行kubeadm config images pull --image-repository你的仓库确认所有镜像都能拉下来第二个是 init 时直接指定--image-repository参数换成你本机可访问的镜像同步仓库。如果已经卡住了不用无限等待。先kubeadm reset -f清理现场重新换镜像源再 init。很多人喜欢反复在同一台机器上试残留的 etcd 数据和证书会干扰下一次初始化所以 reset 之后最好再手动清理残留目录下一小节我会展开。5.2 节点 NotReady按顺序查三处节点状态一直是 NotReady是出现频率最高的问题。我的排查顺序固定为三个层次。第一层查容器运行时systemctl status containerd确保 containerd 在运行且没频繁重启。第二层查 kubeletsudo systemctl status kubelet sudo journalctl -u kubelet -fkubelet 日志是定位问题最直接的信息源。最常见的报错有两个一个是 cgroup 驱动不匹配提示failed to run Kubelet: misconfiguration: kubelet cgroup driver: systemd but is not a valid systemd cgroup driver这种就是 containerd 配置里的SystemdCgroup没有改成true另一个是 CNI 网络插件没就绪报错network plugin is not ready: cni config uninitialized对应 Calico Pod 没起来或者 CIDR 不一致。第三层查 CNI 状态kubectl get pods -A -o wide | grep calico如果 calico-node Pod 一直 CrashLoopBackOff去容器日志里找具体原因。实际遇到较多的是节点时间偏移导致证书验证失败或者CALICO_IPV4POOL_CIDR与--pod-network-cidr不一致。我记忆里有个真实案例一台节点重启后containerd 虽然安装了但没配置开机自启结果重启后 containerd 没起来kubelet 一直拉不到容器。排查日志才发现根本不是网络问题而是运行时没活着。所以第三层确认完之后再回来看系统服务状态往往能找到问题根源。5.3 token 过期或 hash 校验失败现象是执行 join 命令时提示 token 无效或者--discovery-token-ca-cert-hash校验失败。原因通常是 token 超过 24 小时有效期或者你从旧文档里抄了一条早就失效的命令。解决办法很简单在 master 节点上执行kubeadm token create --print-join-command它会返回一条完整可用的新命令。如果你手里的 join 命令是从别人那里抄来的只有 token 没有 hash也可以用下面的方式算出当前 CA 证书的 hashopenssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2/dev/null | openssl dgst -sha256 -hex | sed s/^.* //把输出拼到 join 命令里就行。这个技巧在调试高可用集群时尤其有用因为多控制面节点加入时也需要这个 hash。5.4 重复初始化前一定要彻底清理很多新手在部署失败后直接再跑一次kubeadm init结果报端口被占用、证书已存在等错误。原因很简单上一次失败留下的痕迹没有清理干净。标准操作是sudo kubeadm reset -f sudo rm -rf /etc/kubernetes /var/lib/etcd ~/.kube /etc/cni/net.d sudo systemctl restart containerdkubeadm reset会尝试停止 kubelet 和清理容器但某些残留文件可能不会被自动删除。手动删掉/etc/kubernetes证书、静态 Pod 清单、/var/lib/etcdetcd 数据、~/.kube客户端配置、/etc/cni/net.dCNI 配置这几处基本能恢复到干净状态。这里提醒一下如果你已经给某个节点执行了 join再对 master 执行 reset 前最好先在 master 上kubectl delete node 对应节点名避免残留对象。5.5 证书只有一年躺平不管会付出代价Kubernetes 用 kubeadm 生成的集群默认各组件证书有效期是一年。很多测试环境跑着跑着突然 apiserver 连不上了一看日志才发现证书过期。平时养成习惯定期检查kubeadm certs check-expiration如果发现快到期在证书过期前执行kubeadm certs renew all然后重启控制面组件。重启方式因为控制面是静态 Pod最简单的方法是删除对应的 manifest 目录下文件让 kubelet 重建或者直接重启 kubelet。证书续期本身不影响 etcd 数据和已有的 Pod但建议操作前看一遍官方文档。如果你管理的集群已经过了证书有效期apiserver 起不来了处理起来更麻烦需要先重置时间窗口或者手动恢复证书。所以我的习惯是设置定期任务检查证书有效期避免被动。这一点在生产环境里尤其重要。6. 从测试环境到生产环境还差这几步6.1 高可用多 master 和负载均衡单 master 集群不适合作为生产环境因为控制面一旦宕机整个集群的调度和 API 无法工作。kubeadm 官方支持部署多控制面高可用集群核心思路是在 kubeadm init 时加参数--control-plane-endpoint负载均衡地址这个地址通常是集群外部的一个负载均衡器比如 keepalived haproxy 的组合或者是云平台提供的负载均衡服务。它会把多个 master 节点的 6443 端口统一暴露成一个地址。之后每个 master 节点用相同参数初始化其余 master 节点通过kubeadm join并加上--control-plane标志加入。高可用还需要考虑 etcd 的部署方式。kubeadm 默认把 etcd 和控制面放在一起三个 master 节点就组成一个三节点 etcd 集群。如果对数据安全要求高也可以使用外部 etcd但这属于进阶用法官方文档里有单独的说明。我会先建议学习阶段不必上高可用但规划生产时一定要把它列入第一优先级。6.2 版本升级用好 kubeadm 自带的能力Kubernetes 的版本迭代很快安全更新也频繁。kubeadm 提供了相对清晰的升级路径。大致流程是先升级 kubeadm 和 kubelet再执行kubeadm upgrade plan查看可升级的版本然后运行kubeadm upgrade apply升级控制面最后到每个 worker 节点执行kubeadm upgrade node。升级有两个容易踩的坑。第一不要跨大版本跳级建议从小版本到小版本稳步升级。第二升级前重新检查证书有效期kubeadm upgrade apply会自动更新相关证书但最好先备份/etc/kubernetes目录。升级过程中控制面组件会依次重启短时间内的 API 不可用是正常的生产环境升级要选维护窗口。6.3 生产化补充监控、日志与网络规划集群能跑起来只是开始真正要到生产环境还需要考虑几个方面。监控方面部署 Metrics Server 拿资源指标是基础再配合一套完整的监控告警系统才能放心。日志方面需要一套统一的日志采集链路把所有节点容器 stdout 和文件日志集中到一起否则日志分散在各节点排查问题非常痛苦。镜像方面如果团队里多人使用最好搭建私有镜像仓库并把集群的拉取策略配置好避免每次都去公网拉取。最后还想再强调一遍网络规划。Pod CIDR 和 Service CIDR 一旦确定后续几乎无法修改因为它们被写进了很多组件的证书、配置和 iptables 规则里。我在生产环境见过因为 CIDR 设计不合理导致 Pod 数量不足最后不得不整个集群重新搭建的案例。提前规划好网段预留足够空间是成本最低的“保险”。我个人在实际操作中的体会是kubeadm 这套工具链最大的价值是让你能够按标准方式快速搭建集群同时又不掩盖 Kubernetes 的运行机制。无论踩了多少坑只要你理解静态 Pod 的托管逻辑、cgroup 驱动的一致性、网络插件的 CIDR 对齐这三点大部分问题都能快速定位。最后再分享一个小技巧每次用 kubeadm 初始化前先手动执行一次kubeadm config images pull确认镜像链路通畅这一个小小的动作能帮你省下好几次 reset 的时间。