首页 / 资讯中心 / 文章详情

Kubernetes v1.35.2极速安装与排障实战:从kubeadm到Calico的完整指南

Kubernetes v1.35.2极速安装与排障实战:从kubeadm到Calico的完整指南 ★ FEATURED ARTICLE
“Kubernetes 装起来不难装明白难”——这句话我从 v1.20 时代一路用到现在到了 v1.35.2 依然成立。哪怕你已经装过二十遍集群换一个新版本、换一台新机器依然会遇到千奇百怪的问题。kubeadm init 一把过的场景当然存在但更多时候你会碰见 kubelet 疯狂重启、coredns 一直 Pending、节点状态 NotReady 这些老熟人。这篇就以 v1.35.2 为目标版本从极速安装到故障排查把我实际踩过的坑和最后沉淀下来的流程一起写出来。适合正在搭测试环境的人也适合准备把集群交付到生产环境前想系统过一遍细节的同学。我不会只贴命令然后说“照着敲就行”。有些选择如果你不知道为什么出问题的时候连排查方向都没有。比如为什么用 kubeadm 而不是二进制手搓为什么运行时选 containerd 而不是 Docker为什么网络插件推荐 Calico 而不是 Flannel这些决策会直接影响你后面几个小时是顺利还是折腾。下面我们一关一关过。1. 安装前的整体设计思路1.1 组件选型为什么选 kubeadm containerd装 Kubernetes 主流有三条路二进制手动部署、发行版自带的部署工具如 kubeadm、第三方全家桶比如各种离线交付平台。我的选择一直是 kubeadm理由很简单它足够底层但又帮你把流程自动化了。二进制部署能让你从证书、etcd、apiserver 到 kubelet 全部亲手配置学习价值确实很好但每次升级都要重来一遍维护成本太高。全自动交付平台省事可出了问题你很难搞清楚它到底做了什么对集群失控是很危险的。kubeadm 恰好卡在中间它把 apiserver、controller-manager、scheduler、etcd、kubelet 都用静态 Pod 或者 systemd 管理起来初始化、加入节点、证书续期都有标准命令但只要你有需求依然可以手动改/etc/kubernetes下的配置。上手速度、可维护性、可解释性三方面都说得过去。运行时方面Docker 早就不再是 Kubernetes 默认的 CRI 了。v1.35.2 里最省心的选择就是 containerd。你可能听过“containerd 是 Docker 的一部分抽出来的”这种说法对它既轻量又专精本来就是做容器运行的。很多人从 Docker 迁移过来不习惯的一点是之前docker ps的命令全部要换成crictl我后面会专门提到这个。如果你坚持用 Docker 做运行时需要额外安装 cri-dockerd 这样的垫片架构上多一层踩坑概率高不少没必要。1.2 网络方案怎么选Kubernetes 本身不实现 Pod 间网络它只要求你装的 CNI 插件满足几个条件Pod 之间能互通、所有节点能访问所有 Pod、不需要 NAT 就能访问。没有网络插件集群就是一个半残废状态——控制面起来了但 Pod 调度过去后网络是断的coredns 会一直 Pending这是新手最容易困惑的现象之一。目前主流的 CNI 有这三类Flannel走 VXLAN 封装配置最简单测试环境首选性能一般。Calico基于 BGP 路由 iptables 策略性能好支持 NetworkPolicy生产环境最常选。Cilium基于 eBPF功能最强网络策略、可观测性都做得漂亮但对内核版本有要求调试门槛也高。我的选择是如果只是本地或单节点测试用 Flannel 能少折腾几条命令如果一开始就是按生产标准搭直接上 Calico。这篇后面就以 Calico 为例展开因为多数读者用这篇的流程是要搭正经环境的。还有 Pod CIDR 网段的选择这里务必认真。kubeadm init --pod-network-cidr10.244.0.0/16需要和网络插件默认网段匹配。Calico 默认是192.168.0.0/16Flannel 默认是10.244.0.0/16。如果你 pod CIDR 写的是10.244.0.0/16然后装 Calico 不想调整配置文件就会发现 Calico 内部的网段和你给 kube-apiserver 声明的网段对不上Pod 网络永远不会正常。我一般固定用 Calico所以--pod-network-cidr192.168.0.0/16这样 Calico 的默认 manifest 可以直接用不用改任何东西。1.3 资源规划与前置条件集群节点建议控制面 2C4G 起步工作节点 2C4G 起步磁盘至少 20G 可用。如果只是在笔记本上用 kind 或者 minikube 玩可以忽略这篇的节点规划但真要用 kubeadm 装完整集群资源太少会出现各种诡异的超时问题别在这个环节省。操作系统层面我一般用 Ubuntu 系列或者 Debian 系列systemd 作为 init 系统内核版本 5.x 以上。v1.35.2 对 containerd 的版本要求不算苛刻用官方源装最新稳定版基本不会出错。但有几个前置条件必须逐项确认主机名有意义且唯一。集群里的主机名不能重复且不能带下划线之类的特殊字符我见过主机名带下划线导致的证书 CN 匹配问题。swap 必须关掉。kubelet 默认要求 swap 关闭如果不关kubelet 会直接启动失败。虽然高版本支持配置 swap 启用但我强烈建议所有节点swapoff -a并注释掉/etc/fstab里的 swap 行。服务器时间必须同步。Kubernetes 的证书校验对时间非常敏感偏差超过 5 分钟就会频繁出现证书相关报错。节点之间网络连通性。尤其要确认 6443、2379、2380、10250、10259、10257 这些端口没有被防火墙莫名其妙挡掉。这些看似不起眼实际上我排障时有相当一部分问题都出在“忘了关 swap”或者“主机名带前缀重复”。把这些前置条件整理成一个检查清单装完之后你会感谢自己。2. 极速安装实战从零到集群就绪2.1 基础系统配置要点这里建议直接用一段脚本把这些配置操作统一处理掉避免手工漏项。我在每台节点上都会依次做下面四类操作。首先关闭 swapswapoff -a sed -i /swap/s/^/#/ /etc/fstab然后加载内核模块并配置系统参数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 --systemoverlay是容器运行时做镜像分层用的文件系统模块br_netfilter让 iptables 规则能作用于 Linux 网桥上的流量。这两个如果不加载后面 kubelet 和 CNI 的行为会非常怪异。net.ipv4.ip_forward不开启Pod 之间的流量转发会出现问题。做完这套配置之后最好reboot一次重启用时也就一分钟比后面排查莫名其妙的问题省时间。时间同步我直接用chrony或systemd-timesyncd取决于系统默认带的是哪个。检查方式很简单timedatectl status只要看到System clock synchronized: yes就说明时间同步正常。2.2 安装 containerd 并完成关键配置我习惯先装 containerd因为 kubeadm init 时会去拉 pause 镜像运行时不装好init 必失败。安装部分用 apt 装apt-get update apt-get install -y containerd装完第一件事是生成默认配置并修改SystemdCgroupmkdir -p /etc/containerd containerd config default | tee /etc/containerd/config.toml然后在/etc/containerd/config.toml里找到SystemdCgroup这个字段默认是false必须改成true。这个字段的意思是让 containerd 用 systemd cgroup 驱动来管理容器的资源限制。kubelet 这边一般也配置成 systemd两边驱动不一致后患无穷——最典型的故障是“kubelet 报 cgroup 相关的错误导致 Pod 无法启动”这种错误日志藏得很深新手几乎无从下手。所以在这里一步到位。另外要注意sandbox_image它决定 pause 镜像从哪里拉。默认配置里写的是registry.k8s.io/pause:3.10之类这个不是随便填的Kubernetes 版本不同对应的 pause 版本也不同。我在离线环境或拉取困难的情况下会把这里指向公司内部的镜像仓库或者提前把 pause 镜像导入到节点再用ctr images import加载。这个细节在生产环境里极其重要——如果卡在 ImagePullBackOff第一个就要查 pause 镜像。改完配置重启 containerdsystemctl restart containerd systemctl enable containerd顺便装一个crictl它是 CRI 兼容的容器命令行工具后面排查容器状态基本靠它apt-get install -y cri-toolscrictl ps -a能看到节点上所有运行中的容器crictl logs id能直接查看某个容器日志。排查效率远超 kubectl 一层层绕。2.3 安装 kubeadm、kubelet、kubectlKubernetes 官方在pkgs.k8s.io提供了软件源按系统版本添加好源之后直接安装即可。这里不说具体厂商源了以官方 DEB 源为例curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35.2/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.35.2/deb/ / | sudo tee /etc/apt/sources.list.d/kubernetes.list apt-get update apt-get install -y kubelet kubeadm kubectl apt-mark hold kubelet kubeadm kubectl最后一行apt-mark hold很重要。如果不 hold 住apt-get upgrade时 kubeadm、kubelet、kubectl 会被系统自动升级。而 Kubernetes 的版本升级是有流程的不是随便apt upgrade就能完成的。自动升级会导致 kubelet 和 apiserver 版本不一致然后集群直接失控。安装工具后先 hold 住是很多老手都会默默做但很少写出来的技巧。装完后确认一下版本kubeadm version kubelet --version kubectl version --client三个版本都要是 v1.35.2保持一致。此时 kubelet 可能因为缺少配置文件而处于启动失败状态这是正常的不要慌。系统里还没有/etc/kubernetes/kubelet.conf它当然起不来。等 kubeadm init 或 join 完成之后kubelet 才会有配置。2.4 kubeadm init 初始化控制面在控制面节点上执行初始化。我把常用参数拆开解释一下方便你按自己的环境改kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --control-plane-endpoint192.168.1.10 \ --kubernetes-versionv1.35.2 \ --pod-network-cidr192.168.0.0/16--apiserver-advertise-address本机 IP也就是 apiserver 对外广播的地址。--control-plane-endpoint如果后面要扩展多个控制面节点这里应该填负载均衡器的地址单控制面时可以直接填本机 IP。--kubernetes-version指定目标版本不要省略避免它默认拉一个你没想到的版本。--pod-network-cidr前面说过要和 CNI 默认网段一致。init 过程一般两三分钟。它会自动完成证书生成、etcd 启动、apiserver 等静态 Pod 启动最后输出一大段信息。成功之后它明确提示你需要保存的信息有三样/etc/kubernetes/admin.conf的使用方式、kubeadm join 命令、kubeadm token。千万别关完终端就把 join 命令丢了我见过多次因为 token 丢失然后kubeadm token create重新生成的情况虽然不麻烦但没必要。然后把 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应该能看到控制面节点处于NotReady状态这是正常的。原因就是网络插件还没装。接下来装 Calicocurl -L https://raw.githubusercontent.com/projectcalico/calico/v3.29.1/manifests/calico.yaml -o calico.yaml如果你不能访问这个地址也可以先把 calico.yaml 文件放到内网从另一个能联网的机器下载后传进来。kubectl apply -f calico.yaml之后所有 Calico 相关组件会在kube-system命名空间里以 DaemonSet 的方式跑起来。等待一两分钟之后kubectl get pods -n kube-system kubectl get nodes看到控制面节点Readycoredns 也是Running说明网络部分已经通了。2.5 工作节点加入集群工作节点上需要安装好 containerd、kubeadm、kubelet、kubectl 这些基础组件配置好系统参数不需要执行kubeadm init。然后执行 init 完成后打印出来的 join 命令kubeadm join 192.168.1.10:6443 --token token \ --discovery-token-ca-cert-hash sha256:hashjoin 命令执行时如果 kubelet 无法启动可以先查一下 token 是否还在有效期。默认 token 有效期是 24 小时如果超过这个时间去控制面重新生成kubeadm token create --print-join-command--print-join-command会直接把完整命令打出来复制粘贴到工作节点上就能用省得自己拼参数。这是我用下来最顺手的命令。工作节点加入之后在控制面执行kubectl get nodes能看到两个节点都是Ready集群搭建就算基本完成了。然后用一个测试应用验证调度是否正常比如起一个nginxDeployment扩容到 3 个副本确认副本能打散到不同节点上跑起来。如果调度、网络、DNS 都正常这套环境就可以交付使用了。3. 生产环境要素补充3.1 控制面高可用与证书续期单控制面节点适合测试生产环境建议至少三个控制面节点做 HA。做法是先把--control-plane-endpoint指向一个负载均衡地址然后第一个节点 init 成功后用kubeadm join --control-plane把其他控制面节点加进来。etcd 会自动组成集群apiserver 也会注册到负载均衡后面。这个过程需要注意负载均衡器必须支持 TCP 443 端口转发健康检查指向 6443 端口此外控制面节点的时间同步要求会更高etcd 对时间一致性极其敏感三节点里有一个时间漂移选举就会乱。证书续期是容易被忽略的长线问题。kubeadm 生成的证书有效期一般是一年组件之间的通信证书到期后节点会呈现一种“连接被拒绝”的状态。用以下命令可以一键续期所有证书kubeadm certs renew all systemctl restart kubelet续期完成后还需要手动更新 kubeconfigkubeadm init phase kubeconfig admin --config/etc/kubernetes/kubeadm-config.yaml不过更规范的姿势是在集群里部署 cert-manager 这类证书自动续期工具或者用外部 PKI 体系管理。如果只是一个测试集群可以写个 cron 脚本每个月跑一次证书检查和续期。证书过期导致的问题在现网上排起来非常隐蔽因为一开始报错都是“超时”“拒绝连接”很难直接想到是证书建议从第一天就养成定期检查证书的习惯。3.2 节点标签、污点与资源规划集群搭建完功能通了但不等于生产可用了。工作节点往往有不同的用途比如有的节点挂着 GPU有的节点网卡性能更高有的节点专门跑数据库。此时需要给节点打标签kubectl label node worker-01 node-typestorage kubectl label node worker-02 node-typegpu然后部署应用时在 Pod 的 spec 里加上nodeSelector就能让定向负载落到指定节点上。污点的作用正好相反它是“排斥”而不是“吸引”。所谓污点就是让调度器默认不要往这个节点上调度 Pod除非 Pod 显式容忍这个污点。典型场景是控制面节点kubeadm 初始化时会给它打上node-role.kubernetes.io/control-plane:NoSchedule所以普通业务 Pod 不会跑到控制面上去。如果你想在专用节点上跑一些特殊负载比如监控、日志采集这类系统组件可以给这些节点打相似污点避免其他业务“蹭”资源。节点层面的资源规划我建议提前给命名空间配置ResourceQuota和LimitRange。前者限制命名空间总资源量后者给每个 Pod 设置默认的 request 和 limit。没限制的研发环境是很容易被一个失控的测试脚本打满集群资源的这种坑不用踩配置一下才一页 yaml 的事。3.3 版本升级与回滚思路集群搭好之后迟早面临升级。v1.35.2 到 v1.36.x 的升级流程大概是先升级 kubeadm再升级 kubelet最后执行kubeadm upgrade plan和kubeadm upgrade apply。顺序反了会出现 kubelet 和 apiserver 协议不匹配的问题。Kubernetes 官方支持跨一个次要版本的升级比如 1.34 可以直接升 1.35但不能直接从 1.33 跳到 1.35。升级前务必先备份/etc/kubernetes如果你的 etcd 是外部部署的etcd 数据也要单独做快照。命令也很简单etcdctl snapshot save /backup/etcd-snapshot.db升级完如果发现核心组件异常回滚思路是降级 kubeadm、kubelet 到原版本用备份的/etc/kubernetes恢复配置重启 kubelet再恢复 etcd 快照。整个过程最好在变更窗口里做并且在测试环境先完整演练一遍。我见过太多人直接在生产环境升级然后因为一个特性开关差异导致长期处于“半坏不坏”状态非常尴尬。4. 排障实战我自己踩过的坑4.1 问题速查表直接把最常见的问题做成了一张速查表用的时候先对号入座省去大量搜索时间。以下问题我全都亲自遇到过。现象常见原因排查命令 / 处理方法kubelet 启动失败swap 未关闭、cgroup 驱动不一致journalctl -u kubelet -f看日志swapoff -acoredns 一直 Pending网络插件没装或安装失败kubectl describe pod -n kube-system查看调度失败原因节点 NotReadyCNI 没起来、kubelet 异常kubectl describe node看 condition查 kubelet 日志Pod 一直 ContainerCreating镜像拉取失败、卷挂载失败kubectl describe pod看事件crictl ps -ajoin 后节点 Ready 但 Pod 无法互相访问CNI 网段冲突或防火墙规则检查 pod CIDR 与 CNI 默认网段是否一致apiserver 频繁重启etcd 异常或证书失效kubectl logs -n kube-system kube-apiserver调度器把 Pod 都堆到一个节点缺少亲和性配置或所有节点无差异kubectl get nodes --show-labels检查标签ImagePullBackOff镜像地址错误或镜像仓库鉴权失败kubectl describe pod查事件crictl images确认本地镜像KubeAPI 端口连接超时防火墙或安全组没放行nc -vz ip 6443测试端口连通性token 已过期token 默认 24h 有效期kubeadm token create --print-join-command重新生成这张表能解决大部分“装完连不通”的问题。注意我这里的重点是让你知道“现象 → 原因 → 动作”是连贯的不要一看到报错就重装集群。重装只能解决不会排查的问题但真正到了出问题频率高的生产阶段重装一次的成本你也承受不起。4.2 典型故障排查实录分享一个我印象很深的案例。某次部署时工作节点安装完成后kubectl get nodes发现节点是 NotReady。基础检查做了一遍swap 已关、iptables 没问题、主机名不冲突。然后我journalctl -u kubelet -f看日志才发现 kubelet 不断报错说“Failed to run kubelet: failed to run Kubelet: misconfiguration: kubelet cgroup driver: systemd but systemd is not the container runtime cgroup driver”。这个报错本质上就是我前面提到的 cgroup 驱动不一致。我节点上 containerd 的SystemdCgroup忘记改成true结果 kubelet 用的是 systemd 驱动运行时用的是cgroupfs两边对不上。修改 containerd 配置、重启 containerd、删除旧的 kubelet 相关状态、重启 kubelet 后节点才恢复 Ready。这类问题的特点是日志里没有任何“致命错误”字样但节点就是起不来。排查顺序极其重要先看 kubelet 的日志再看容器运行时状态。很多人一上来就kubectl describe node其实 node 层面的描述信息里不会告诉你底层 cgroup 驱动不匹配你还是得回到节点上查日志。4.3 常用排查命令集把命令整理成一个顺手集遇到问题照着跑一遍基本能覆盖 90% 的情况# 查看 kubelet 实时日志最常用的第一条 journalctl -u kubelet -f # 查看 kubelet 服务状态 systemctl status kubelet # 查看节点条件和事件 kubectl describe node node-name # 按命名空间查看所有 Pod kubectl get pods -n kube-system -o wide # 查看 Pod 详细事件 kubectl describe pod pod-name -n namespace # 查看容器日志 kubectl logs pod-name -n namespace kubectl logs pod-name -n namespace --previous # CRI 视角查看容器 crictl ps -a crictl logs container-id # 查看 CNI 相关 Pod kubectl get pods -n kube-system | grep calico # 查看 CNI 日志 kubectl logs -n kube-system calico-pod-name有人说排障就是“看日志”这没错但要学会分层看。我的习惯路径是先kubectl get nodes看大面再kubectl get pods -A -o wide找到异常 Pod然后kubectl describe看事件最后落到 kubelet 或容器运行时日志。不要从一坨日志直接开盲盒。另外kubeadm reset是个双刃剑。它可以在节点上把 kubeadm 装的组件全部重置相当于“卸载干净再装”。这个命令确实是排障时快速恢复环境的好帮手先kubeadm reset -f再手动清理/etc/kubernetes、/var/lib/kubelet、/var/lib/etcd这些目录然后重新 init。但请记住kubeadm reset不是修 bug 的办法它是“站点重建”级别的操作。如果连 bug 原因都没搞清楚就 reset下次大概率还会踩同一个坑。5. 实操心得与避坑清单5.1 从多次安装中沉淀的几点体会第一整个安装过程最容易出错的环节并不是kubeadm init本身而是 init 之前的系统准备。我复盘过多次安装失败几乎都是“忘记关 swap”“忘记加载 br_netfilter”“containerd 的 SystemdCgroup 没改成 true”这类低级问题。所以我的习惯是先写一个自动化脚本把系统配置做完脚本执行完检查一遍再开始 init五分钟的系统准备永远比三小时的排障便宜。第二网络插件一定要第一时间装。很多人 init 完成后看到节点没有 Ready第一反应是重启 kubelet 或者检查防火墙其实节点 NotReady 的常见原因很简单——网络插件没装。你想想apiserver 都启动起来了kubelet 也知道自己有配置了但 kubelet 要和 CNI 一起干活才能上报节点状态CNI 不在场节点当然起不来。所以 init 成功后立刻装网络插件能避免很多无用功。第三不要害怕使用crictl系列命令。它和 Docker 的命令几乎一一对应不会也不会很复杂。你只需要记住crictl ps -a看所有容器、crictl logs看容器日志、crictl images看本地镜像排障时带来的信息量比 kubectl 直查 Pod 还要多一层容器的视角。调过几次底层问题之后你就会爱上它。第四文档和注释一定要边做边留。kubeadm 的 join 命令、admin.conf 的备份位置、证书到期时间、节点标签规划这些信息看似小事但你半年后再来维护集群的时候会发现当年的随手记录比记忆可靠一百倍。5.2 核心检查项对照表最后附上一张我在每次交付前都会逐项打勾的检查表你可以直接拿去当团队验收清单用检查项完成标准备注节点系统配置swap 已关闭、内核参数生效、时间同步正常所有节点统一执行containerd 配置SystemdCgrouptrue、sandbox_image 可拉取修改后必须重启基础组件版本kubeadm/kubelet/kubectl 均为 v1.35.2安装后执行apt-mark hold控制面初始化kubeadm init 成功admin.conf 可用保存 join 命令网络插件Calico 或对应 CNI 的 Pod 全部 Running节点状态必须是 Ready工作节点加入kubeadm join 成功节点 Ready检查 kubectl get nodes功能验证示例 Deployment 正常调度、DNS 解析正常Pod 间互通用 busybox 测试证书与 token证书有效期检查是干净的kubeadm certs check-expiration资源配额命名空间配置了 Quota 和 LimitRange防止测试环境资源失控备份机制etcd 快照备份任务已配置定期执行才能救命这份检查表看起来很长但实际上每项对应的系统命令也就一两条。把检查表固化到自己的部署流程里比临时翻阅排障手册更有价值。毕竟“极速安装”的重点不是快在敲命令上而是快在“一遍就通”上。我当初反复踩坑之后才意识到这一点现在你如果能直接带走这张表至少能帮你省掉一两天的折腾时间。
阅读完成 · 觉得有帮助?
咨询建站