kubeadm+Containerd+Calico 搭建K8s集群避坑指南
2026/9/9 9:43:04 网站建设 项目流程

1. 大多数人搭 K8s 集群失败,不是因为命令敲错

先说个反直觉的现象:kubeadm init跑完报错,九成以上不是网络问题,就是镜像拉不下来,但真正让新手心态崩掉的,往往是“明明照着教程敲了,怎么结果不一样”。原因就一个——Kubernetes 的版本迭代太快,教程之间相差三个月,行为就可能完全不同,而你很可能拿了一篇老教程配新版本,或者反过来。

这篇文章存在的意义很简单:我把自己从零搭建一套可用 K8s 集群的完整过程、每一步背后的原理、以及踩过的坑,全部摊开来讲。无论你是刚接触容器编排的运维新人,还是想在公司内部落地一套测试环境的后端开发,都可以照着这份指南一步步操作。文章会覆盖环境规划、系统初始化、容器运行时安装、控制平面初始化、工作节点接入、网络插件部署、配置验证、以及后续日常管理中最容易翻车的几个环节。

整份指南基于Ubuntu 22.04 LTS + Containerd + kubeadm + Calico这套组合,是目前社区最主流、资料最全、坑相对最少的搭配。如果你用的是 CentOS 7 或别的发行版,原理完全一样,只是个别包管理器命令和内核参数略有差异,我会在对应位置做补充说明。

2. 动手之前,先把集群拓扑和版本策略定死

2.1 我的环境规划(3 节点最小可用集群)

K8s 最少可以跑单节点,但生产或测试至少要 3 个节点才有意义——1 个控制平面 + 2 个工作节点。因为控制平面挂了,集群还能撑一阵,但连控制平面都只剩一个的话,整个集群实际上处于“能跑但不可管”的状态。

我这次用的是一套 3 节点虚拟机:

角色主机名配置IP
控制平面k8s-master4C / 8G / 50G192.168.1.10
工作节点k8s-node14C / 8G / 50G192.168.1.11
工作节点k8s-node24C / 8G / 50G192.168.1.12

关于配置我要多说两句。网上很多教程说 2C2G 也能跑,确实能跑,但你会非常痛苦——etcd 本身就吃内存,控制平面的几个组件(kube-apiserver、kube-controller-manager、kube-scheduler)加在一起轻松吃掉 2~3G,再跑几个业务 Pod 内存基本就告急。如果你是拿自己电脑开虚拟机练手,建议至少 4G 内存起步,磁盘 50G 是最低配置,因为镜像、容器日志、 etcd 数据都会持续增长。

2.2 版本选择:不要一味求新,要选“稳定且互相兼容”的组合

这一步我单独拎出来讲,因为它决定了你后面 90% 的坑会不会出现。

Kubernetes 的版本号规则是 v1.xx.y,其中 xx 是次要版本。官方支持最近三个次要版本,也就是说 v1.28 发布后,v1.25 就停止维护了。但“支持”和“推荐”是两回事,我个人的建议是:选择比最新版本落后 1~2 个次要版本,比如最新是 v1.31,你就选 v1.29 或 v1.30。为什么?因为新版本发布后,生态组件(CNI、CSI、ingress-controller)的兼容性需要一段时间才能跟上,你等老鸟们先把坑踩完,再上不迟。

更关键的是,控制平面和工作节点的版本不能差太多,最多允许一个次要版本的偏差。比如 master 是 v1.29,node 最高只能到 v1.30,否则 kubelet 和 kube-apiserver 之间的 API 协商会出问题。

我这次使用的版本组合:

  • Kubernetes:v1.29.x
  • Containerd:1.7.x
  • Calico:v3.28.x
  • 操作系统:Ubuntu 22.04(内核 5.15)

为什么选 Containerd 而不是 Docker?K8s 在 v1.24 版本之后彻底移除了对 Docker 作为运行时(dockershim)的支持,虽然 Docker 仍然可以通过 cri-dockerd 这个适配层来用,但官方推荐的默认运行时就是 Containerd。你如果坚持用 Docker,等于多引入了一层转换,性能损耗且不说,排错链路也变长了。听我一句劝,新集群直接上 Containerd,别纠结。

2.3 先想清楚你的网络模型

这是搭建之前最容易被忽略、但影响最深远的一个决策。K8s 本身只定义了一套网络模型(CNI,Container Network Interface),但具体实现要你自己选。

常见的 CNI 方案有 Flannel、Calico、Cilium、Weave Net,它们的核心区别在于网络策略(NetworkPolicy)的支持程度转发性能。Flannel 只做连通性,不支持策略;Calico 基于 BGP,天然支持网络策略,性能也不错;Cilium 基于 eBPF,性能最好,但学习曲线陡。

我这个系列用 Calico,原因很简单:它既支持 NetworkPolicy,又不依赖特定的内核版本(Cilium 要求内核 5.8+,Ubuntu 22.04 默认 5.15 没问题,但如果你想在 CentOS 7 上跑,内核 3.10 就尴尬了),而且 BGP 模式在中小规模集群里性能完全够用。

3. 系统初始化:把所有节点的环境“拉齐”

3.1 主机名、hosts、以及关闭 swap 的真相

这一步看起来基础,但很多人就是在这一步偷懒,导致后面 kubeadm init 时各种莫名其妙的问题。

首先,给每个节点设置唯一的主机名:

# master 节点 sudo hostnamectl set-hostname k8s-master # node1 节点 sudo hostnamectl set-hostname k8s-node1 # node2 节点 sudo hostnamectl set-hostname k8s-node2

然后,修改每个节点的 /etc/hosts,让所有节点能通过主机名互通:

sudo tee -a /etc/hosts <<EOF 192.168.1.10 k8s-master 192.168.1.11 k8s-node1 192.168.1.12 k8s-node2 EOF

接着是关闭 swap。这一步不是“建议”,而是“必须”。K8s 要求禁用 swap 的原因是:当节点内存不足时,如果 swap 还在,kubelet 会认为内存还有余量,不会及时触发 Pod 驱逐(eviction),结果就是整个节点卡死。v1.22 之后 K8s 引入了对 swap 的实验性支持,但默认仍然要求关闭,别去踩这个坑。

sudo swapoff -a sudo sed -i '/ swap / s/^/#/' /etc/fstab

注意swapoff -a只是临时关闭,重启就失效了,所以必须同时修改 /etc/fstab 用注释方式永久关闭。

3.2 内核模块与系统参数:iptables 的桥接流量是关键

K8s 的 Service 和 Pod 之间的通信依赖 iptables(或 IPVS)来做转发,而 iptables 处理桥接流量需要特殊的配置。这里有两项:内核模块 br_netfilter 必须加载,net.bridge.bridge-nf-call-iptables 必须设为 1。

# 加载 br_netfilter 模块 cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter # 设置必要的 sysctl 参数 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

如果不做这一步,最典型的报错是 kubeadm init 时提示 “WARNING: bridge-nf-call-iptables is disabled”,或者 Pod 间网络时通时不通。我见过太多人卡在这里——明明容器都起来了,但 Service 就是访问不了,结果一查是 bridge-nf-call-iptables 没开。

3.3 同步时间:比你想的更重要

这个很容易被忽略,但重要程度不亚于关闭 swap。K8s 集群里证书的签发与校验、日志的时序分析、etcd 的 raft 选举,全都依赖节点时间的一致性。节点间时钟偏差超过几秒,轻则证书校验失败,重则 etcd 集群脑裂

sudo apt install -y chrony sudo systemctl enable chrony sudo systemctl start chrony # 验证时间同步状态 chronyc sources -v

如果你用的是虚拟机,建议同时关闭 time sync 相关的选项,以避免宿主机的时间同步和客户机冲突。VMware 里可以在 VM Options 里关掉 “Time synchronization”,VirtualBox 则在设置里关闭 “Guest Additions” 的时间同步。

4. 安装 Containerd:别直接 apt install,要配置 systemd cgroup 驱动

4.1 从 Docker 官方源安装,或者用发行版自带源

Containerd 的安装有两种常见方式:一种是从 Docker 官方 apt 源装,另一种是用发行版自带的源。我推荐用 Docker 官方 apt 源,原因很简单:版本更新快,而且和 K8s 社区的兼容性测试同步。

sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install -y containerd.io

4.2 关键配置:cgroup 驱动必须是 systemd

这是新手翻车率最高的一个环节。K8s 在 v1.24 之后默认使用 systemd 作为 kubelet 的 cgroup 驱动,而 Containerd 默认配置是 cgroupfs,两者不一致就会导致 kubelet 无法启动,报错信息是 kubelet cgroup driver 不匹配。

安装完 Containerd 后,需要先导出默认配置,再修改:

mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml

然后编辑 /etc/containerd/config.toml,找到[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]这一段,把SystemdCgroupfalse改为true

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true

顺手还要处理镜像加速的问题。由于众所周知的网络原因,直接拉取registry.k8s.io的镜像大概率会失败。有两种加速方式:一种是通过 systemd 配置镜像加速器,让 Containerd 在拉取镜像时自动替换 registry 地址;另一种是使用国内镜像站手动拉取镜像后重新 tag。我使用的是前者,在 config.toml 中配置 mirror,把registry.k8s.io指向一个可用的加速器地址,这样 kubeadm init 时的镜像检查就能顺利通过。

改完配置后重启 Containerd:

sudo systemctl restart containerd systemctl status containerd

确认服务状态是 running 且没有报错,再进行下一步。

5. kubeadm 安装与集群初始化:成功的人各有各的顺利,失败的人卡在同一处

5.1 kubeadm、kubelet、kubectl 的安装

这里有一个版本锁定的问题。如果你直接用apt install kubelet kubeadm kubectl,大概率装的是最新版。对于学习和测试来说没问题,但如果你想复现我这份指南,建议明确锁定版本:

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.29/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.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubelet=1.29.* kubeadm=1.29.* kubectl=1.29.* sudo apt-mark hold kubelet kubeadm kubectl

apt-mark hold非常重要,它防止apt upgrade时把 K8s 组件静默升级到更高版本,导致集群版本不一致。我在生产环境里见过不止一次,因为没 hold 版本,一次系统更新后 kubelet 和 apiserver 版本差了两个次要版本,整个集群直接失控。

5.2 提前解决镜像问题:kubeadm config images pull 检查

在正式执行kubeadm init之前,先手动拉一遍镜像,确认网络和镜像源都没问题:

kubeadm config images list

这一步会列出所有需要拉取的镜像清单,包括 kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy、pause、etcd、coredns。

确认清单无误后,执行:

sudo kubeadm config images pull

如果你看到所有的 image 都显示 pulled successfully,说明基础镜像这一关已经过了。如果这里报错,千万别继续往后走——回去检查 Containerd 的 mirror 配置,或者用 crictl 手动拉镜像后再重新打 tag 的方式解决。

5.3 kubeadm init:最重要的几个参数

执行如下命令(注意替换为你自己的 IP 和 Pod 网段):

sudo kubeadm init \ --apiserver-advertise-address=192.168.1.10 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12 \ --kubernetes-version=v1.29.0 \ --control-plane-endpoint=k8s-master

参数含义:

  • --apiserver-advertise-address:APIServer 对外宣告的 IP,通常是控制平面节点的 IP。如果节点有多网卡,必须显式指定,否则 kubeadm 可能选错网卡。
  • --pod-network-cidr:Pod 网段,这个网段必须和后续 CNI 插件配置一致。我用 10.244.0.0/16 是因为 Calico 的默认配置里包含这个网段,如果你用 Flannel,默认也是 10.244.0.0/16。如果你用了其他网段,必须调整 CNI 配置。
  • --service-cidr:Service 网段,默认 10.96.0.0/12 即可。
  • --kubernetes-version:显式指定版本,避免 kubeadm 拉取默认版本的镜像。
  • --control-plane-endpoint:控制平面统一入口。单控制平面可以填主机名或 IP,但在搭建高可用(HA)集群时,这个值是负载均衡器的地址,非常重要。我在这一步直接写主机名,可以让 kubeconfig 里记录的地址是主机名,在某些场景下比裸 IP 更方便。

kubeadm init执行成功后,末尾会输出三块关键信息:

  1. kubectl 的配置方法(就是把 admin.conf 拷到 ~/.kube/config)
  2. 工作节点加入集群的完整命令(kubeadm join 加上 token)
  3. token 过期时间(默认 24 小时,过期后需要重新生成)

先按提示配置 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 网络插件还没部署呢。

5.4 Pod 网段冲突与调试思路

在实际操作中,最容易忽略的一个坑是:Pod 网段和现有网络冲突。比如你的公司内网是 10.0.0.0/8,你再把 Pod 网段设成 10.244.0.0/16,这里的 10.244 网段虽然不冲突,但如果你用了 10.10.0.0/16 这种,内网设备很可能会访问不到集群里的 Pod。这个在设计初期就得想清楚,网络规划不平衡,集群搭建完了再改 Pod 网段是非常痛苦的事。

另外补充一个调试技巧:等到 Pod 一直处于 ContainerCreating,不要只盯着 kubectl get pods 看,用kubectl describe pod xxx -n kube-system来看事件(Events),大部分情况下 Event 里会直接把真正原因写清楚(镜像拉取失败、挂载失败、CNI 冲突等)。会看 describe 出来的 Events,比会敲命令重要得多。

6. 部署 Calico 网络插件:Pod 间通信的“高速公路”

6.1 下载并修改 Calico 清单

Calico 的安装很简单,官方提供了一份完整的 YAML 清单:

curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/calico.yaml

默认配置里已经包含了很多内容,包括 CRD、RBAC、DaemonSet、Service 等。我们需要关注的是 CALICO_IPV4POOL_CIDR 这个环境变量:

grep -n "CALICO_IPV4POOL_CIDR" calico.yaml

默认值通常是192.168.0.0/16,如果你的--pod-network-cidr用的不是这个网段,必须改掉,否则 Calico 分配的 Pod IP 和 apiserver 规划的网段不匹配,CNI 会一直报错。

kubectl apply -f calico.yaml

然后观察状态:

kubectl get pods -n kube-system

等所有 pod 都是 Running 后,再看节点状态:

kubectl get nodes

这时候 master 应该已经是 Ready 状态了。

6.2 为什么选 BGP 模式而不是 VXLAN 模式

Calico 支持两种主要的数据面模式:BGP 和 VXLAN。BGP 模式直接通过节点的三层网络交换路由,性能最好,延迟低,适合网络环境简单、所有节点在同一个二层域的场景;VXLAN 是基于 UDP 的隧道封装,适合跨子网、跨机房的场景,但会有额外的封装开销和延迟。

如果是同机房、同网段的节点,直接用默认的 BGP 模式,不用改。如果你的节点跨网段,才需要考虑 VXLAN。怎么改?

在 calico.yaml 中,找到环境变量CALICO_IPV4POOL_VXLAN,设置为AlwaysCrossSubnet。这个配置不当容易导致跨节点 Pod 通信不通,排查起来最耗费时间。

6.3 部署后验证网络

我常用的验证方式,是启动一个 busybox Pod,然后从它去 ping 任意节点的 Pod IP:

kubectl run test-pod --image=busybox --restart=Never -- sleep 3600 kubectl exec -it test-pod -- ping <某个Pod的IP>

能通说明 CNI 转发这条链路是完好的。这里补充一句:ping通只是最基础的网络连通性验证,但 K8s 集群中持续在用的核心通信对象是 Service 的 ClusterIP。

7. 工作节点加入集群:这个环节最容易出的问题

7.1 执行 kubeadm join

master 初始化完成后,工作节点上需要执行kubeadm join命令。如果 token 过期(24小时),或者你忘记保存 join 命令了,可以通过如下方式重新生成:

# 在 master 上重新生成 token kubeadm token create --print-join-command

然后在 node1 和 node2 上执行(注意替换成你自己的 token 和 hash):

sudo kubeadm join 192.168.1.10:6443 \ --token <token> \ --discovery-token-ca-cert-hash sha256:<hash>

执行成功后会看到输出:This node has joined the cluster

回 master 执行:

kubectl get nodes

最尴尬的场景出现了:节点状态是 NotReady。怎么办?

7.2 节点 NotReady 的完整排查链路

先别急着到处搜答案,按这个顺序一步步查:

第一步,确认 kubelet 状态

systemctl status kubelet # 或 journalctl -u kubelet -f

如果 kubelet 没起来,大概率是配置文件有问题或 cgroup 驱动不匹配,需要重点观察启动日志中是否出现failed to run Kubeletcgroup driver等字样。

第二步,查看 kubelet 日志里的关键错误

journalctl -u kubelet --no-pager | grep -i error | tail -20

如果看到Failed to connect to apiserver,检查节点到 master 的 6443 端口是否通:nc -vz 192.168.1.10 6443。如果不通,先解决网络连通性。

第三步,检查 node 的注册信息与 CNI 是否报错

kubectl describe node k8s-node1

看 Conditions 字段,重点看Ready是 True 还是 False,以及报错信息里提到 Ready=False 的原因。如果报CNI plugin not initialized,则是 CNI 相关的问题,去节点上查看 kubelet 日志。

这一套链路排查下来,95% 的问题都能定位到。

7.3 如果 join 后怎么都加不上:从节点上彻底重置

当你试了很多办法还是不行,或者你改了配置想重新加入节点时,最干净的方式是在节点上执行:

sudo kubeadm reset sudo rm -rf $HOME/.kube /etc/cni/net.d

然后在 master 上删除旧节点(如果是同一个节点重新加入,通常 master 端会自动清理,但保险起见先 delete 一次):

kubectl delete node k8s-node1

再重新执行 join。这个方法对“节点死活加不上”有奇效,但属于“最后手段”,先按 7.2 的链路排查完再用。

8. 集群验证与第一份工作负载:验证 Pod、Service、Ingress

到这里,恭喜你,你的集群已经可以正常工作了。但“能跑”和“能用”是两回事,我习惯把 K8s 集群的验证动作做完整,确认这套集群不只是表面 Ready,而是真正可以承载业务。

8.1 部署一个 Nginx 应用并暴露为 NodePort

先创建一个简单的 Deployment:

kubectl create deployment nginx-demo --image=nginx:1.25 kubectl scale deployment nginx-demo --replicas=3

查看 Pod 分布:

kubectl get pods -o wide

你会看到 3 个 Pod 被调度到不同节点上,IP 是 Calico 分配的 10.244.x.x 网段。这时候用curl 10.244.x.x可以直接访问 Nginx 首页(如果通了,说明 CNI 正常)。

接着创建 Service:

kubectl expose deployment nginx-demo --port=80 --type=NodePort kubectl get svc

Service 会分配一个 ClusterIP(10.96.x.x)和一个 NodePort(30000~32767 之间随机)。这时候从任意节点执行curl 10.96.x.x能通,从外部用curl http://任意节点IP:NodePort也能通。

8.2 验证 DNS 解析与负载均衡

K8s 内置的 CoreDNS 负责集群内域名解析。在一个 Pod 里测试 Service 的域名解析:

kubectl run curl-test --image=curlimages/curl --rm -it --restart=Never -- sh # 在容器内 curl nginx-demo.default.svc.cluster.local

能通就说明 Service 的 DNS 解析、kube-proxy 转发链路都正常。

小集群下,kube-proxy 默认走 iptables 模式,IPVS 模式需要额外在 kube-proxy 的 ConfigMap 中显式开启并确保节点上安装了 ipvsadm。但即便用默认的 iptables 模式,也能做到多副本随机轮询,你多发几次 curl,观察几个 Pod 的访问日志,能看出请求基本要轮流分配,这就算负载均衡验证过了。

8.3 crictl vs docker:容器运行时排错命令

既然用的是 Containerd,日常排错就不再是docker ps了,而是 crictl:

crictl ps crictl images crictl logs <container-id>

前面我提到拉取 K8s 组件镜像时遇到问题,也可以用 crictl 手动 pull 镜像:

crictl pull registry.k8s.io/kube-apiserver:v1.29.0

crictl 和 kubelet 共用同一个 containerd.sock,所以在节点上观察容器状态,它比 docker 命令更贴近 K8s 的真实视角。习惯用 docker 的同学,建议尽早切换到 crictl,否则后面排错会走弯路。

9. 踩坑实录与运维提示:我能帮你省下的每一小时

9.1 三个反复出现的经典问题

问题一:Pod 一直 ContainerCreating,卡在 ContainerCreating

排查命令:

kubectl describe pod <pod-name> -n <namespace> kubectl logs <pod-name> -n <namespace> --previous

最常见原因是镜像拉取失败、存储卷挂载失败、或者 CNI 没有就绪。我见过一个典型场景是用了 hostPath 卷但没有提前创建宿主机目录,导致 Pod 一直 ContainerCreating 并在 Event 里直接给出挂载报错。解决方法是先建目录,或者换用 PV/PVC。

问题二:节点 Ready 但 Pod 之间跨节点不通

这大概率是 Calico BGP peer 没有建立成功。在节点上执行:

calicoctl node status

如果没有输出 BGP peer 信息,检查节点防火墙(ufw)是否放行了 BGP 端口 179。另外还要确认 Calico 的 IP 池网段和你 kubeadm init 时配置的 pod-network-cidr 保持一致。

问题三:kubelet 起不来,日志提示 kubelet cgroup driver: "cgroupfs" is different from kubeadm cgroup driver: "systemd"

这个错误信息非常精准,说明你的容器运行时(Containerd)配置的还是 cgroupfs,回到第 4 节做修改,然后重启 Containerd,再重启 kubelet,这个问题就没了。

9.2 关于 CoreDNS 一直 Pending(或 CrashLoopBackOff)

如果你是严格按照我的步骤来做的,CoreDNS 大概率不会出问题。但如果你用的是某些特殊网络或汇总配置,CoreDNS 可能会一直 Pending 或 CrashLoopBackOff。Pending 通常是节点资源不足或调度约束导致,确认一下节点有没有污点即可;CrashLoopBackOff 则和 CoreDNS 的配置文件有关——如果你改过 ClusterIP 网段但没有同步调 CoreDNS 的上游 DNS 配置,CoreDNS 就会反复重启。

排查的时候,先看日志:

kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50

9.3 集群日常管理里的几个实用技巧

隔三差五看看事件与资源用量,别等告警才知道

kubectl get events --sort-by=.lastTimestamp | tail -20 kubectl top node kubectl top pod -A

在 master 上拿命令控全局

我强烈建议日常只在 master 节点上使用 kubectl,不要随意去 node 操作。master 上的 kubeconfig 默认是 admin 权限,别随手让人拿去用了。

知识库组件升级时,先读 release notes

升级集群不是一件小事。每次 K8s 的次版本升级都可能有破坏性的变更,比如 v1.24 移除 dockershim、v1.25 开始不再默认启用 PodSecurityPolicy 等。不管在什么环境,升级前都要先备份 etcd,并对关键配置做 snapshot。

10. 生产集群还远远不止这一步

到这里,你已经拥有了一套可以运行、可以调度 Pod 的 Kubernetes 集群。但这套集群离生产环境要求还很远——控制平面是单点、etcd 没有独立部署、没有日志监控体系、没有 ingress 控制器、没有持久化存储方案、没有命名空间隔离策略。作为起步,这个状态足够你学习和验证核心概念;作为学习路线图,你下一步很自然地会去研究高可用控制平面(kubeadm 支持多 master + 外部负载均衡)、ingress-nginx、metrics-server + Prometheus、以及基于 NFS 或云盘的 CSI 存储方案。

我最初搭第一套 K8s 集群的时候,前后折腾接近两周,大量时间花在版本不匹配和网络插件选型上。现在是2025年,社区资料比我那时丰富太多了,照着这份流程,配合耐心读日志,一套测试集群配下来三四个小时是比较正常的节奏。真踩到坑了,不要慌,先用 describe 和 journalctl 把日志完整看一遍,再动手改东西,很多“玄学”问题到最后都会发现是自己某个配置细节没对。

希望这份指南对你有实质性的帮助。练手过程中遇到任何问题,欢迎在评论区一起讨论,我看到都会回复。

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

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

立即咨询