☰
使用kubeadm从零搭建Kubernetes集群:关键步骤与排错指南
2026/10/13 23:03:32 网站建设 项目流程

1. 动手前的整体认知与环境决策

1.1 先搞清楚Kubernetes到底解决了什么问题

Kubernetes这个项目从诞生到现在,基本已经成了容器编排的事实标准。但很多人在第一次接触它的时候,都会被一大堆抽象概念吓住:节点、Pod、Deployment、Service、Namespace、etcd、CRI…… 我记得自己第一次装Kubernetes的时候,纯粹是照着网上的命令脚本复制粘贴,装完之后集群显示Ready了,我却完全不知道这些命令背后的逻辑是什么,后面出了问题也不知道从哪里排查。

所以在写安装步骤之前,我想先帮大家建立一个整体认知。Kubernetes的核心工作其实很简单:帮助你把一堆容器管起来,包括部署在哪里、挂掉怎么重启、如何扩容缩容、如何暴露给外部访问。你可以把它理解成一个“自动化的容器酒店前台”,每个节点是房间,Pod是住进去的客人,kubelet是楼层的管家,而控制平面就是酒店的管理系统。

这篇博文不讨论Kubernetes的所有功能,只聚焦一件事:怎么从一个全新的Linux环境,一步一步搭建出一个可用的Kubernetes集群。我会把每个关键步骤背后的原理讲清楚,而不是只给命令。

1.2 安装方式怎么选:kubeadm、二进制、minikube还是kind

第一次安装Kubernetes的人通常会卡在第一个问题上:用哪种方式装?网上教程五花八门,有说用minikube的、有说用kind的、有说直接上kubeadm的,甚至有人直接从GitHub拉二进制包手工配置。我个人的建议是:学习阶段用kubeadm,测试快速体验用minikube或者kind,生产环境用kubeadm加自动化运维工具,而不是手工二进制部署。

可能有人会觉得手工二进制部署更“底层”、更厉害,但实际上Kubernetes组件之间的配置关系非常复杂,手工方式需要自己管理证书、token、服务文件、etcd集群,任何一个环节失误都会导致组件间通信失败,排查起来非常痛苦。kubeadm最大的价值在于它把这些复杂的初始化工作自动化了,包括证书生成、token创建、组件配置文件生成、健康检查等。它不是一个黑盒子,你完全可以通过kubeadm init --dry-run查看它将要执行的内容,学习成本低,可控性也高。

如果你只是想在笔记本电脑上跑一个单机集群来玩,minikube会更合适;如果是在CI流程里临时起一个集群做测试,kind更轻量。但论最贴近生产环境、最能帮你理解组件关系的安装方式,kubeadm是第一选择。下面所有内容都基于kubeadm展开。

1.3 版本选型与组件兼容性

Kubernetes的安装有一个让新手很头疼的特点:版本兼容性非常严格。kubelet版本不能高于控制平面版本太多,kubectl也因为兼容性做了矩阵限制,CNI插件、容器运行时也各有适配版本。如果不先看兼容矩阵就直接装,经常会出现装完以后组件报奇怪的错。

我的建议是选一个相对新的稳定版本,比如1.28或者1.29这条线。不要追最新版本,因为最新版刚发布时配套的教程、镜像、插件适配往往还没完全跟上;也不要选太老的版本,因为老版本在容器运行时接口上跟新版本差异很大,排查问题时参考文档也少。选稳定版本后,把kubeadm、kubelet、kubectl三个组件锁定到同一个小版本,然后在你的环境里一次性装好。

这里还要注意一个容易踩的坑:容器运行时和Kubernetes的CRI版本适配。Kubernetes 1.24之后默认就没法直接用Docker作为运行时了,需要走containerd或者其他符合CRI标准的运行时。我这次选择containerd,原因很简单:它比Docker轻,和Kubernetes的集成是原生级别的,而且网上主流资料都在用,遇到问题解决起来容易。

2. 环境准备:网络、内核与容器运行时

2.1 节点规划与最低硬件

我这次搭建的是一套两节点集群:一个控制平面节点加一个工作节点。从纯学习角度来说,单节点集群也能跑,但那样你看不到调度、Pod分配到节点这些核心逻辑,所以有条件的话还是至少两个节点比较舒服。

从硬件角度看,控制平面节点至少需要2核CPU和4GB内存,工作节点最好也是2核起步。资源如果再低,集群能跑起来,但碰到稍大的容器镜像或并发操作时,各种超时和OOM会频繁发生,你很难判断是配置问题还是资源问题。我的建议是两台虚拟机,每台分配2核4GB内存,磁盘40GB以上,操作系统选择任意的Debian系Linux发行版即可。

节点规划时可以做个简单的表格:

节点角色主机名建议配置参考用途
控制平面节点master-node2核4GB,40GB磁盘运行kube-apiserver、kube-controller-manager、kube-scheduler、etcd
工作节点worker-node2核4GB,40GB磁盘运行kubelet、kube-proxy、实际工作负载

这里要提前说一句:kubeadm支持把控制平面和工作负载同时跑在一个节点上,但前提是在kubeadm init时给控制平面节点去掉污点,或者把单节点初始化配置写清楚。生产环境不要这么干,学习环境为了省资源可以。

2.2 操作系统基础配置

在安装Kubernetes之前,系统层面有几项配置必须提前做好,否则后面会连环报错。

第一项是关闭swap。Kubernetes的kubelet从设计上就不希望在启用swap的环境里工作,因为kubelet需要通过内存请求和限制来管理Pod的内存使用,如果swap存在,容器可以逃逸到swap里,内存配额就形同虚设。关闭swap使用swapoff -a,同时编辑分区表文件把swap行注释掉,保证重启后依然生效。

第二项是配置主机名和hosts解析。集群内的节点之间通信非常依赖主机名解析,最好不要写死IP。控制平面节点和执行节点都要修改hosts文件,把各节点的IP和主机名对应关系写进去。很多初学的人忽略这一步,结果控制平面初始化以后、工作节点加入时,频繁出现token校验通过但节点间连接失败的问题。

第三项是加载内核模块和系统参数。Kubernetes依赖iptables做流量转发,还依赖br_netfilter模块来保证桥接流量能够被iptables处理。没有这个模块,Pod之间的通信和Service的转发都会出问题。常见的做法是创建/etc/modules-load.d/k8s.conf,写入br_netfilter和overlay,再通过sysctl设置net.bridge.bridge-nf-call-iptables=1和net.ipv4.ip_forward=1。这些参数最好一开机就生效,而不是每次手动执行。

第四项是时间同步。Kubernetes组件之间基于证书通信,证书校验依赖系统时间,时间偏移过大会直接导致认证失败。多数云主机默认带时间同步服务,但虚拟机自己装的话很容易忽略,推荐安装chrony或systemd-timesyncd,确保时钟一致。

2.3 容器运行时:为什么选containerd而不是Docker

在Kubernetes早期版本里,Docker是默认的容器运行时,kubelet通过一个叫dockershim的中间层来对接Docker。但Docker本身的设计并不是为了服务Kubernetes这种编排系统的,它多了一层守护进程,还额外占用系统资源。从Kubernetes 1.24开始,dockershim被正式移除,Kubernetes统一通过CRI(Container Runtime Interface)来对接各种符合标准的容器运行时。

CRI你可以理解成一个标准化插座,kubelet只负责按这个插座的协议发命令,至于底层的容器怎么创建、怎么隔离,都由运行时来管。containerd是目前最主流的CRI运行时,因为它轻量、稳定,而且Docker本身底层的容器创建能力也是通过containerd实现的。你在使用kubectl exec进入容器、查看日志、收集指标的时候,实际上都是在和containerd打交道。

所以现在装Kubernetes,我不建议大家再去装Docker,或者装完Docker再装containerd。直接用containerd就可以,省去一层多余的依赖,排查问题也更容易。

2.4 安装并初始化containerd

containerd的安装分两步:安装二进制包和生成默认配置。不同Linux发行版的包管理器不大一样,但思路相同。装好之后,必须先执行containerd config default生成一份默认配置文件,然后把它放到指定路径。如果你不初始化配置直接启动containerd,它可能用内置的默认参数运行,最后出现cgroup驱动和Pod镜像源不匹配的问题。

拿到默认配置后,有两个地方一定要改。第一个是systemd的cgroup驱动,把SystemdCgroup设置为true。为什么要改?因为Kubernetes的kubelet默认使用systemd作为cgroup驱动,如果容器运行时的cgroup驱动不一致,两个组件之间无法共同管理Pod的资源限制,kubelet会把节点标记为NotReady,并且报failed to run kubelet之类的错。

第二个是sandbox_image,这个参数决定了每个Pod启动时使用的pause镜像地址。默认地址在部分网络环境下拉不下来,所以要改成你实际能访问的镜像源地址。这里多说一句:很多人改完以后没有重启containerd,导致配置一直没有生效,排查了半天才发现是旧配置还在跑。每次改完配置文件,一定记得systemctl restart containerd。

3. kubeadm安装控制平面与工作节点

3.1 安装kubeadm、kubelet、kubectl

容器运行时准备好之后,接下来安装Kubernetes的三个核心工具。kubeadm负责初始化集群和管理token,kubelet是在每个节点上运行的核心代理组件,负责跟控制平面通信并管理本节点的Pod,kubectl是给管理员使用的命令行客户端。

这部分有两个注意事项。第一是安装源,建议使用Kubernetes官方维护的软件源,而不是从第三方源直接下载。官方源里能拿到与版本对应的完整依赖,第三方源虽然方便,但偶尔会出现包版本混乱、依赖缺失的问题。第二是版本锁定,安装完成后要执行一个锁版本的命令,防止后续系统在更新软件包时把kubelet或kubectl升级到不兼容的版本。生产环境或者长期学习环境都应养成这个习惯。

安装完成以后,可以通过kubeadm version和kubelet --version检查当前版本。这里我还想强调一点:kubelet和kubeadm的版本要尽量保持一致,如果kubelet版本比控制平面的版本落后太多,注册节点时会出现版本不匹配的报错,这个问题在排查阶段非常常见。

3.2 初始化控制平面节点

控制平面节点是集群的大脑,所有组件的核心都在这里运行。kubeadm init命令就是用来完成初始化的,它做的事情很多:生成证书、创建etcd、启动kube-apiserver、生成kubeconfig文件、创建token等。你不需要手工做这些事,但必须知道它生成的哪些文件在哪个位置,因为它们之后会用于节点接入和日常管理。

在初始化之前,建议先想好两个参数:--apiserver-advertise-address和--pod-network-cidr。第一个参数是控制平面API Server对外暴露的IP地址,一般来说就是你控制平面节点的IP。如果你有多个网卡,一定要手动指定,否则kubeadm可能选了错误的IP,工作节点永远连不上控制平面。第二个参数是Pod的网段,它给集群内的每个Pod分配一个虚拟IP。这个网段不能和你的物理网络网段重叠,否则数据包路由会混乱。

我这次选择的是10.244.0.0/16,因为后续的CNI插件我准备使用Flannel,这个网段是Flannel的默认规划。如果你打算用Calico,则可以选择10.20.0.0/16或者自定义的其他网段。关键是,这个网段一旦定下来,后面尽量不要改,改起来非常麻烦。

初始化命令执行成功后,控制台会输出一段提示,包括如何配置kubectl、如何把工作节点加入集群、以及join命令中需要的token和证书哈希。很多人第一次装的时候没有保存这段输出,后面需要用token找回命令时非常被动。我的建议是:把关键输出直接复制保存到本地文件里,之后再慢慢研究。

3.3 配置kubectl

初始化完成后,kubectl还不能立刻使用,因为当前用户还没有集群的访问权限。kubeadm在初始化过程中生成了/etc/kubernetes/admin.conf,这个文件包含管理员的所有权限信息,你的任务就是把它放到用户目录下让kubectl能识别。

具体流程很简单:创建~/.kube目录,把admin.conf复制成~/.kube/config,然后设置好文件权限。接下来你可以执行kubectl get nodes,这时候会看到控制平面节点处于NotReady状态,这是正常的,因为网络插件还没装。不要看到NotReady就觉得失败,继续往下走。

这里我还想多说一个点:如果你用root用户操作,把config文件放到root家目录没问题;如果你用普通用户操作,记得把用户名和组名对应修改。很多人用普通用户执行kubectl时一直提示无权限,查到最后发现是config文件权限不对,或者配置文件里的用户信息对不上。

3.4 给集群装上网络插件

网络插件是很多入门者的噩梦,因为Pod网段规划、CNI插件选择、防火墙策略这些因素混在一起,稍不留神就出现Pod一直处于ContainerCreating或者节点报路由错误的情况。

从原理上讲,Kubernetes集群里的每个Pod都有一个集群内唯一的IP,但Pod可能部署在任何节点上,不同节点上的Pod之间如何通信,这本身是个复杂的网络工程问题。CNI插件就是负责解决这个问题的。Flannel和Calico是两种常见方案,Flannel更轻、配置更简单,适合学习和中小规模集群;Calico功能更强、支持网络策略,适合对安全隔离有要求的环境。

我这次选择Flannel,因为学习阶段它最直观,部署方式就是一个YAML文件。执行kubectl apply -f kube-flannel.yml后,Flannel会在集群里创建DaemonSet,每个节点上都会运行一个Flannel Pod,负责维护这个节点的Pod网络。安装完成后,过一两分钟再执行kubectl get nodes,节点状态应该会从NotReady变成Ready。如果长时间没有变化,多半是Pod网段规划冲突、或者防火墙拦截了UDP/TCP端口。

如果你选择了Calico,安装过程类似,但Calico对环境的要求更高,比如需要开启IP_FORWARD、有时候需要调整mtu参数。还有一点,Calico的默认数据面会把Pod流量封装成IPIP模式,如果底层网络不允许这种封装,则需要切换到BGP模式或者VXLAN模式。相比之下Flannel默认使用VXLAN或者host-gw模式,改动更少,适合初学者。

3.5 工作节点加入集群

控制平面Ready之后,接下来把工作节点纳入集群。这一步本质上是让工作节点上的kubelet以一个可信身份去连接API Server,并且接收API Server下发的Pod调度任务。kubeadm把整个认证过程封装成了kubeadm join命令,你需要提供API Server地址、token、以及CA证书的哈希值。

token的默认有效期是24小时,如果你是在初始化当天就加入节点,直接用初始化输出保存的join命令就可以。如果过了有效期或者命令丢了,可以在控制平面节点上重新创建token,用kubeadm token create --print-join-command生成新的join命令。证书哈希值也可以用openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex类似的方式自行校验,但我个人建议优先用kubeadm生成好的完整命令,省得手动拼装出错。

在工作节点执行join命令时,需要确认三件事:第一是工作节点的kubelet和kubeadm已经安装完成,并且版本一致;第二是系统基础配置已经OK,尤其是swap关闭、内核模块加载;第三是工作节点和控制平面节点之间的网络是通的,比如通过ping确认能够访问API Server的6443端口。

加入完成后,回到控制平面节点执行kubectl get nodes,你会看到两个节点,但工作节点大概率还是NotReady。不要慌,观察一段时间,Flannel的Pod会被调度到新节点上,等网络插件在这个节点上也运行成功后,节点状态就会变成Ready。

3.6 验证集群是否真的可用

节点显示Ready并不代表一切都完美,有一种常见的假象是:节点状态正常,但实际调度Pod时才发现问题。所以节点全部就绪后,建议立刻部署一个测试应用来验证整个链路。

最省事的做法是创建一个Nginx的Deployment,并给它设置一个明确的副本数,比如3个。执行之后观察Pod的调度和运行状态,正常情况下三个副本会被分散到不同的节点上。然后再创建一个Service把这些Pod暴露出来,并尝试从节点上访问Service的ClusterIP和端口,确认流量能到达后端的某个Pod。

这个验证过程虽然简单,但能发现很多问题。比如,如果Pod一直处于ContainerCreating,通常说明镜像拉不下来或者CNI网络配置异常,通过kubectl describe pod能看到具体报错;如果Service创建后访问不通,可能是kube-proxy没运行或者iptables规则出了问题,排查思路跟普通网络排查类似。做完这一步,你的集群才算真正可用。

4. 实测高频问题和排错锦囊

4.1 镜像拉取失败是最常见的问题

我在多次安装中发现,新手遇到最多的一个问题就是镜像拉取失败。具体表现是kubectl get pods -A时一堆Pod处于ImagePullBackOff,错误信息通常包含Failed to pull image或者registry.k8s.io连接超时。

原因是Kubernetes的核心组件镜像托管在官方的镜像仓库里,这个仓库在某些网络环境下的访问速度很不稳定。解决办法分两类:一类是给containerd配置镜像加速或白名单代理;另一类是直接修改sandbox_image和组件容器里的镜像地址,替换成可访问的第三方镜像源。

这里有一个细节:替换镜像地址不能只改前面的一级域名,还要保持镜像的版本标签不变。你可以先用kubeadm config images list查看kubeadm认为需要哪些镜像,然后逐一替换成第三方源里的对应镜像版本。改完之后,再执行kubeadm init时就不会因为镜像问题卡住了。

4.2 token过期或join命令丢失怎么办

token有效期问题很典型。如果你初始化完集群,第二天才想加入工作节点,立刻就会遇到token过期的问题。别着急,重置token非常容易,在控制平面节点上执行kubeadm token create --print-join-command,它会直接输出一条可以直接复制到工作节点执行的join命令。

有时候你会看到输出里的token有效时间还是24小时,这也是正常的,你可以通过--ttl=0让token不过期,不过生产环境不建议这么干。另外,如果你需要手动拼接join命令,还要知道CA证书的哈希值,但在绝大多数情况下没必要手动拼,直接让kubeadm帮你生成完整命令是最稳的。

4.3 节点NotReady的排查路径

节点从NotReady变成Ready是安装过程中最让人焦虑的阶段。不要一上来就重启服务,而是按照下面这个顺序排查。

第一步,执行kubectl describe node <节点名>,看节点状态里有没有类似KubeletNotReady的提示,以及底层原因。第二步,登录对应节点执行journalctl -u kubelet -f,看kubelet日志里是否持续报错。第三步,检查容器运行时状态,执行crictl ps看能否正常获取容器列表,如果不能,说明kubelet和containerd的cgroup驱动或者socket通信出了问题。

我遇到最多的情况是cgroup驱动不一致:kubelet使用systemd,containerd使用cgroupfs,两边的管理方式对不上,节点就永远NotReady。解决办法是把containerd配置里的SystemdCgroup改成true,重启containerd后,再重启kubelet。这种问题在日志里不会直接说“cgroup不一致”,而是报failed to run Kubelet或者misconfiguration,所以新手很容易被绕进去。

4.4 节点重启后集群组件没起来

集群搭建完成以后,你可能会把虚拟机重启一次来验证开机自启。如果重启后kubectl get nodes显示节点报错或者Pod起不来,通常是两个原因:一个是containerd和kubelet没有设置开机自启,另一个是网络插件在启动顺序上有问题。

第一个原因最容易解决,执行systemctl enable containerd和systemctl enable kubelet就行。第二个原因稍微复杂一些,因为kubelet本身不会在启动时自动创建Flannel或者Calico的Pod,这些Pod是由API Server负责调度的,而API Server又依赖etcd和kubelet。如果系统的服务启动顺序错乱,可能会出现“先启动的kubelet等不到控制平面”的情况,但大多数情况下,只要底层服务都是开启状态,等几分钟就能恢复正常。

如果你发现重启后节点依然NotReady,最直接的排查方式是挨个查看集群Pod的状态。比如用kubectl get pods -n kube-system查看核心组件,再看kubectl logs -n kube-system <pod名称>。通常日志会告诉你到底是哪个组件起不来,是数据库文件损坏、还是证书过期、还是端口被占用。这里特别提醒:不要随便执行kubeadm reset,它的作用是清空整个集群状态,一旦执行,所有配置和etcd数据都会丢失,只能重新初始化。

4.5 常见问题速查表

我把上面提到的问题整理成速查表,方便排查时对照:

现象可能原因排查命令解决办法
Pod一直ImagePullBackOff镜像拉取失败kubelet相关日志替换镜像源或配置加速
节点NotReadycgroup驱动不一致kubectl describe nodecontainerd启用SystemdCgroup
网络插件无法启动Pod网段冲突或端口被占用kubectl logs网络Pod调整网段或防火墙规则
join时报token过期token超出有效期kubeadm token create重新生成join命令
kubectl无法访问集群kubeconfig配置错误kubectl config view检查admin.conf路径和权限
节点重启后无法恢复containerd或kubelet未自启systemctl status开启enable自启动

4.6 证书过期问题

Kubernetes集群里的组件间通信大量依赖TLS证书,kubeadm生成的证书有效期通常是一年。如果你长时间使用一套集群,某一天突然发现apiserver的体积日志中出现证书过期的报错,那就需要处理了。

处理证书并不难,执行kubeadm certs renew all可以统一续期所有证书,然后重启相关组件让新证书生效。但有一点容易忽略:如果你用的是kubeadm管理的kubeconfig文件,可能也需要同步更新,否则你通过kubectl访问集群时依然会报证书错误。学习环境可以这样做,生产环境应该把证书有效期纳入监控,提前续期。

我个人的经验是:不管你用哪种方式搭建Kubernetes,都不要只把它当成一锤子买卖的安装过程。装完以后多花点时间观察日志、理解组件关系,后面再遇到类似问题时,你的排查速度会比直接搜报错快很多。如果时间允许,建议再去玩一下存储卷、Ingress、RBAC这些功能,它们会帮助你更全面地理解整个系统。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询