资讯动态

使用kubeadm从零搭建Kubernetes集群:完整实操指南

发布时间:2026/10/14 0:28:17 来源:尧图企业网站定制
折腾Kubernetes集群这件事说难也难说简单也简单。我自己第一次从一台空机器到kubectl get nodes能看到所有节点 Ready整整花了一个周末回看大部分时间都耗在“不知道为什么要这么配”上而不是配置文件本身。这篇文章是 Kubernetes 详解系列的第二篇专门聊从零搭建集群用 kubeadm 把一套多节点集群完整拉起来覆盖版本选型、环境准备、初始化参数、Pod 网络、节点加入和常见故障排查。适合手里有几台 Linux 机器、对容器和基础命令有概念、但还没完整搭过集群的人也适合被各种玄学报错折磨过的运维同学拿来对照复盘。我个人一直认可一条经验搭建过程本身不难难的是每一步背后的为什么。所以这篇文章不会只丢一串命令让你抄所有关键参数都会解释清楚包括它影响什么、写错了会出什么问题。1. 动手之前集群方案与版本选型1.1 为什么用 kubeadm而不是二进制部署Kubernetes 集群搭建方式有很多最常见的是 kubeadm、二进制部署、minikube 和 kind。我的建议是正式学习或搭建测试、生产环境首选 kubeadm想深入理解组件原理再考虑二进制本地纯开发调试才用 minikube 或者 kind。kubeadm 是官方主推的集群引导工具它解决的核心问题是“靠一条命令完成控制平面组件的握手”。你只需要关心几个配置参数证书签发、kubeconfig 生成、组件静态 Pod 编排、etcd 集群引导这些脏活累活kubeadm 全包了。二进制部署虽然可控性最强但需要自己处理的东西非常多每个组件的启动参数、证书分发、RBAC 文件、静态 Pod 路径、etcd 集群成员关系……一套搞下来少说折腾几天。这个方案的优点不是效率而是能帮你建立底层认知。如果你已经跑通了一遍二进制部署再用 kubeadm 就会觉得它在帮你做决策而不是黑箱。用个生活类比kubeadm 像装修公司帮你把毛坯房做出硬装但软装CNI、Ingress、监控、存储你得自己配二进制部署则是从搬砖开始自己盖房工程量完全不是一个级别。1.2 节点规划控制平面与工作节点怎么分Kubernetes 集群节点分两类控制平面节点Control Plane和工作节点Worker Node。控制平面跑的是集群的“大脑组件”——API Server、Controller Manager、Scheduler 和 etcd工作节点跑的是实际业务负载由 kubelet 统一管理。我的建议是测试环境也把角色分开不要图省事把所有组件塞一台机器里。因为混跑最容易出现的问题是资源抢占业务 Pod 把 CPU 吃满etcd 响应变慢整个集群的控制面都跟着抖。这里给出一个常见规划参考节点角色主要组件最低配置建议备注控制平面节点kube-apiserver、etcd、kube-controller-manager、kube-scheduler2C / 4G生产环境建议独立规格更高工作节点kubelet、kube-proxy、容器运行时、CNI2C / 4G业务负载的实际承载者关键点高可用集群至少 3 个控制平面节点—etcd 需要多数派才能写入数据etcd 是集群所有状态的唯一来源它内部用 Raft 协议保证一致性。Raft 要求多数派存活才能继续写入三个副本最多挂一个五个副本最多挂两个。这也是为什么生产集群至少三台控制平面节点。1.3 版本选型与镜像源策略版本选型是新手最容易被忽视的一步。很多人拿到文档就直接装最新版结果遇到插件不兼容、镜像源没同步、社区资料对不上号等一系列问题。我的建议是生产环境不要追求最新选择“上一个次要版本的最近补丁”。比如当前社区最新到了 1.30就选 1.28 或 1.29 的较新补丁版本。原因是 Kubernetes 每个版本会声明支持的 API 版本旧资源的弃用和移除有周期用次新版本能避免生态组件还没适配完的尴尬。测试环境则可以用最新版提前感受新特性。还需要注意kubeadm、kubelet、kubectl 三个工具版本最好保持一致主版本差一位以内可以工作但我遇到过小版本不一致导致kubeadm join时证书校验失败的情况所以别在这点省事。另一个容易被网络环境卡住的点是镜像拉取。kubeadm 初始化时会从默认仓库拉取控制平面组件镜像如果网络访问不稳定初始化可能直接超时。常见做法是在kubeadm init时通过--image-repository参数指定一个可用的镜像仓库地址比如云厂商提供的镜像加速服务。这个参数改变了所有控制平面镜像的拉取地址注意仓库目录结构要和官方保持一致否则同样会拉取失败。2. 基础环境准备把系统调整成 Kubernetes 喜欢的模样2.1 主机名、hosts 与 SSH 免密集群搭建前第一件小事是定主机名。主机名不能乱起我见过因为主机名带大写字母和下划线导致 kubelet 证书申请失败的案例。约定一个标准风格比较好全小写、短横线分隔例如k8s-master01、k8s-worker01。接着修改所有节点的/etc/hosts把所有节点的 IP 和主机名映射写进去。这一步看起来多余其实很关键。Kubernetes 组件之间大量通过主机名互相访问包括 apiserver 和 kubelet 的通信。如果不做解析你会发现集群状态正常但kubectl logs偶尔连接不上节点。SSH 免密不是必须的但我强烈建议配好。后面你会在主节点上反复 SSH 到工作节点执行命令有免密能省很多时间。用ssh-keygen生成密钥后再用ssh-copy-id分发到各节点实测最稳。2.2 内核模块与系统参数Kubernetes 依赖 Linux 内核的 iptables 和网络桥接能力。开启这些模块和参数直接决定 Pod 网络转发是否正常。先加载br_netfilter模块并写入/etc/modules-load.d/k8s.conf保证重启后依然生效cat EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter接着配置内核参数。最核心的是让 iptables 能看到桥接流量否则集群内部服务间通信会出现间歇性故障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这里的net.ipv4.ip_forward是用来让容器流量能跨节点转发的。如果不开节点间 Pod 通信会直接不通表现是跨节点 ping 有去无回。2.3 容器运行时 containerd 安装与配置从 Kubernetes 1.24 开始dockershim 被移除了kubelet 直接通过 CRIContainer Runtime Interface对接容器运行时。现在默认的运行时是 containerd这也是生产环境里最主流的方案。安装 containerd 可以直接用系统包管理器装也可以拿官方二进制包解压。安装后重点在配置因为默认配置在 CRI 这块往往不完整。生成默认配置文件sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml生成后必须改两个地方。第一个是SystemdCgroup。Kubernetes 的 kubelet 默认使用 systemd 作为 cgroup 驱动如果 containerd 还是 cgroupfs两者对资源管理的视图不一致kubelet 起来后会报 cgroup 相关的错误节点状态直接 NotReady。所以找到 CRI 插件配置区把[plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true第二个是沙箱镜像sandbox_image。这个是每个 Pod 里最先启动的 pause 容器镜像负责持有网络命名空间。默认值在部分网络环境下拉取会超时我一般直接改成配置好的加速仓库地址sandbox_image 镜像加速仓库地址/pause:3.9改完后重启 containerd确认状态sudo systemctl restart containerd sudo systemctl status containerd注意containerd 配好后不要急着往下走可以先用ctr images list或crictl pull测试一下拉取镜像是否正常。这一步排查成本最低。2.4 关闭 swap 与 SELinuxKubernetes 有一个设计约束节点必须关闭 swap。原因是 kubelet 对 Pod 的资源配额做的是“硬隔离”如果存在 swap 空间内存回收的语义会被打乱Pod 的 QoS 保障就失去了意义。kubeadm init 时检测到 swap 未关闭会直接报错。关闭操作是临时的还要从 fstab 注释掉保证重启后不自动挂载sudo swapoff -a sudo sed -i / swap / s/^/#/ /etc/fstab如果系统带 SELinux面向 RHEL 系发行版还要把它设为 permissive 或直接关闭。SELinux 和容器文件挂载会起冲突典型现象是容器突然被拒绝访问某些文件路径。这是安全模块策略问题和 Kubernetes 配置八竿子打不着查起来会想骂人。3. 安装核心组件并完成集群初始化3.1 安装 kubelet / kubeadm / kubectl三个核心工具的安装建议通过系统的软件源完成。源配置这里不展开重点说一下版本固定。用包管理器安装完成后Linux 不会自动升级软件包但我仍建议把版本 hold 住sudo apt-mark hold kubelet kubeadm kubectl版本固定的原因是 Kubernetes 集群内部组件耦合紧无意中升级某一个很容易引入和现有集群不匹配的兼容问题。生产环境里因为“别人顺手升级了一下”导致的集群故障我见过不止一次。安装完成后验证kubeadm version kubelet --version kubectl version --client经验补充kubectl 只需要在主节点管理端安装即可工作节点只需要 kubelet 和 kubeadm省去不必要的组件暴露面。3.2 kubeadm init 初始化时这些参数千万别写错初始化命令是全流程最核心的一步。我的标准命令大概是这样的sudo kubeadm init \ --apiserver-advertise-address192.168.31.10 \ --control-plane-endpoint192.168.31.10 \ --kubernetes-version1.28.2 \ --pod-network-cidr10.244.0.0/16逐参数解释--apiserver-advertise-addressAPI Server 对外通告的 IP就是其他节点通过哪个地址访问它。建议用静态内网 IP不要写 DHCP 动态分配的地址。--control-plane-endpoint控制平面的统一入口地址。单机实验环境直接填同一个 IP 就行高可用场景这里应该填 VIP 或者负载均衡器地址这是给 kubelet 连接 apiserver 用的。--kubernetes-version指定安装的版本比如 1.28.2。不写的话 kubeadm 会去查最新稳定版和实际安装可能对不上。--pod-network-cidr分配给 Pod 的网段必须和 CNI 插件要求的网段一致。Flannel 默认要求10.244.0.0/16Calico 通常用192.168.0.0/16。这一项可以说是最影响后续幸福感的值。初始化成功后终端会打出三块内容第一[init] Using Kubernetes version之类的日志确认版本和镜像拉取成功。第二一段“You can now join any number of worker nodes”提示里面带kubeadm join完整命令包含 token。第三生成kubeconfig的操作指引。拿到输出后一定先保存 join 命令后面加入工作节点直接复用。忘了也不要紧后面讲怎么重新生成。3.3 部署 Pod 网络插件Calico 和 Flannel 怎么选集群初始化的结果控制面是起来了但集群内部 Pod 还处于一个“不通网”的状态。因为 Kubernetes 本身不实现网络方案需要你选一个 CNI 插件。这一步不做CoreDNS 会一直 Pending节点也不会变成 Ready。主流选择是 Calico 和 Flannel。我对这两个方案的建议很直接对比项FlannelCalico网络模型纯 OverlayVXLAN 等Overlay BGP也支持 IPIP功能范围只做网络连通网络 NetworkPolicy 有限服务网格能力性能一般高层级场景更好学习成本低中等适用场景测试、轻量组网生产、需要网络策略的场景如果你只是想快速把集群搞通选 Flannel配置最简单。如果你要模拟生产环境选 Calico它的网络策略能力是生产集群的刚需。以 Flannel 为例部署只需要一步kubectl apply -f kube-flannel.yml这个清单从 Flannel 官方仓库下载。部署完成后通过下面的命令观察状态kubectl get pods -n kube-flannel -o wide kubectl get nodes这里最容易踩的坑Flannel 默认要求 Pod 网段是10.244.0.0/16。如果你在kubeadm init阶段填了别的网段Flannel 的 DaemonSet 就会陷入不断 CrashLoop 的状态。解决方式有两种一是初始化时就用 Flannel 要求的网段二是改 Flannel 的 ConfigMap 里的网段设置。我建议用第一种别为了“我想用这个网段”去徒增网络排障成本。3.4 工作节点加入集群的正确姿势控制平面 Ready 之后剩下的就是让工作节点加入集群。在每台工作节点上执行主节点打印的 join 命令类似sudo kubeadm join 192.168.31.10:6443 \ --token xxxxxx.xxxxxxxxxxxxxxxx \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxx这个命令做了三件事第一工作节点的 kubelet 拿到引导令牌向 apiserver 发起 TLS 引导请求第二通过证书哈希完成对主节点的身份校验防止连到冒牌控制面第三注册这个节点并请求加入集群的名额。如果 join 命令丢了可以到主节点重新查看或生成 token。查看当前 tokenkubeadm token list如果 token 过期就重新创建一个kubeadm token create --print-join-commandtoken 默认 24 小时过期这其实是个安全设计。节点加入完成后记得验证kubectl get nodes等一两分钟所有节点应该能变成 Ready。如果卡在 NotReady直接跳到下一章的排查清单。4. 初始化后的自检与常见问题排查4.1 集群自检清单5 个检查项一次过集群初始化成功不等于万事大吉。我每次搭建后都会走一遍自检清单按顺序排除问题检查项命令预期状态节点状态kubectl get nodes所有节点 Ready核心组件 Podkubectl get pods -n kube-system除网络插件外全部 RunningCoreDNSkubectl get pods -n kube-system -l k8s-appkube-dnsRunning/Ready网络连通性创建临时 Pod 跨节点 ping 测试正常返回控制面健康kubectl get componentstatusescontroller-manager、scheduler 均 Healthy实际经验里网络插件正常、CoreDNS 起不来是最常见的组合。如果你看到 CoreDNS 一直 Pending十有八九是 Pod 网段和 CNI 网段不一致或者 CNI 的 DaemonSet 本身没跑起来。4.2 kubeadm init 失败的典型场景与定位思路初始化失败是新手最容易崩溃的时刻。别慌所有信息都在日志里。我先列几个高频场景。第一个是 swap 未关闭。报错里会出现running with swap on is not supported直接把 swap 关掉重跑即可。第二个是 CRI 未就绪。报错提示CRI v1 runtime API is not implemented for endpoint或容器运行时 socket 连接失败。检查 containerd 是否在运行crictl info能不能正常输出。多半是 containerd 未重启或者配置改了没生效。第三个是镜像拉取超时。这个报错会具体到某个镜像名比如failed to pull image registry.k8s.io/etcd:3.5.x。解决方法是配置--image-repository或者手动ctr image pull把镜像预先拉到本机。定位问题的核心思路是查 kubelet 日志journalctl -u kubelet -fkubelet 是集群底层的执行者很多初始化问题都会在这里留下真实原因。看日志时不要只看第一行要看到最后的error关键字那里往往是真正的原因。4.3 节点 NotReady 的排查路径节点加入后一直 NotReady优先级最高的排查路径是先看节点状态描述再看 kubelet 日志最后看 CNI 组件日志。kubectl describe node 节点名 journalctl -u kubelet -f kubectl get pods -A | grep -v Running我遇到过最隐蔽的一个问题是时间不同步。Kubernetes 组件之间使用证书和 Token 通信对时间偏差很敏感偏差超过 5 分钟就会出现认证失败。节点上时间漂了kubelet 和 apiserver 之间的双向 TLS 握手直接失败节点永远 NotReady。解决方式是配置 NTP 服务让所有节点时间保持一致。这一步在协议上不对齐重装集群都没用。另外一个常见坑是主机名和之前注册过的节点重名。比如你重装了系统主机名还叫worker01但这个节点名已经被 etcd 记住了。处理方式是从集群中先删掉旧节点记录kubectl delete node worker01然后在新的工作节点上重新 join。4.4 网络、镜像与资源限制的常见问题速查这部分是日常运维最高频的问题整理成速查表现象可能原因处理建议Pod 一直 ImagePullBackOff镜像地址错误或拉取受限检查镜像地址配置加速仓库手动 crictl 拉取验证跨节点 Pod 不通CNI 网段冲突或 IP 转发未开检查 init 的 CIDR 与 CNI 配置是否一致CoreDNS CrashLoopBackOffCNI 未就绪导致 DNS 请求异常先解决网络再重建 CoreDNS节点重启后 K8s 服务异常容器运行时未设置开机自启systemctl enable containerd kubelet证书过期报错集群运行超过 1 年使用kubeadm certs renew续期注意镜像加速仓库是一种公共基础设施很多云厂商和社区都提供。配置时要确保仓库目录结构与官方镜像保持兼容不要改路径里的组织名目录。5. 可选增强部署 Metrics Server 与 Dashboard5.1 Metrics Server让 kubectl top 有数据可用集群搭好后直接跑kubectl top nodes会报metrics not available。这不是故障而是 Metrics Server 还没部署。这个组件负责采集节点和 Pod 的资源使用情况是 Dashboard、HPA 自动扩缩容的数据来源。部署方式同样是用清单文件kubectl apply -f metrics-server.yaml部署完成后验证kubectl top nodes kubectl top pods -AMetrics Server 有一个常见坑它默认使用 HTTPS 连接 kubelet自签证书如果不加--kubelet-insecure-tls参数会握手失败。测试环境可以直接加这个启动参数生产环境建议走正规证书不推荐在生产环境关闭证书校验。5.2 Kubernetes Dashboard可视化界面解决 80% 的“快速看眼”命令行固然强大但团队协作时可视化界面能降低认知成本。Dashboard 部署需要两步先部署服务本身再创建访问账号。部署服务kubectl apply -f dashboard.yaml创建访问用的 ServiceAccountkubectl create serviceaccount admin-user -n kubernetes-dashboard kubectl create clusterrolebinding admin-user --clusterrolecluster-admin --serviceaccountkubernetes-dashboard:admin-user获取登录 Tokenkubectl -n kubernetes-dashboard create token admin-user平时我用kubectl proxy方式访问比较省事kubectl proxy然后打开http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/粘贴 Token 登录。这里有一个安全建议Dashboard 服务不要直接用 NodePort 暴露到公网。它拥有集群管理员的完全权限一旦泄露等于集群大门被撬开。内网测试环境走kubectl proxy就够了生产环境如果要暴露前面至少还要叠加一层认证和审计。6. 写在最后的一点经验这套流程我反复执行过很多次每次踩的坑基本都集中在网络和镜像上组件的配置反而是最稳定的。最后分享一个小技巧搭建前把所有节点的系统时间先同步好然后把kubeadm init那条命令、token 和 CNI 清单保存下来放在一个固定的笔记里。看起来是小事但重装集群时能省下大量搜索的记忆成本。搭建只是万里长征第一步之后还有网络策略、存储、Ingress、可观测性这些内容等着填充。希望这份实操手册能帮你少走几趟弯路把集群的地基打好。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑