首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
k8s集群安装实战:kubeadm初始化、containerd配置与CNI网络插件排障
📅 2026/10/19 5:06:32
✍️ 爱科研究院
👁 阅读 3,247
k8sKubernetes的安装说实话难度不大但坑非常稳定地集中在几个固定位置容器运行时配置、网络插件、版本不一致、镜像拉不下来。前几年我搭第一套集群时光是在这三个坑里就反复折腾了好几天。这篇文章把我最近一次从头搭建集群的完整过程整理成文从环境规划、基础初始化、containerd配置、kubeadm初始化到工作节点加入、CNI网络插件部署以及最后的人间真实排查记录全部理顺一遍。适合正在准备自己搭一套k8s环境、又不想只在文档里云体验的读者照着走基本可以一步到位。1. 动手安装前先把三件事定明白版本、节点、网络很多人拿到安装文档就急着敲命令结果装到一半发现某个组件版本不对或者两个节点配置不一致回头排查非常痛苦。我现在的习惯是先在纸上把架构写清楚再动手。1.1 安装路线选择为什么一直用kubeadmk8s集群的安装路线大致有四条Minikube单机玩具、kubeadm标准集群、二进制手工部署、自动化平台部署某发行版方案。日常学习和搭建生产可用的小集群我首选kubeadm。理由很简单kubeadm是官方维护的标准集群引导工具它会自动帮你处理控制平面的证书、kubeconfig、etcd部署等一大串脏活。二进制手工部署能让你对每个组件理解得更深但是手动维护一堆systemd服务和证书第一套环境大概率会踩到组件之间握手失败的坑。Minikube适合体验功能但它只是一台虚拟机不是真正的多节点集群。我需要说清楚一个观念kubeadm是引导工具不是运维工具。它只管把集群拉起来后续的升级、证书续签、备份恢复这些事仍然要自己操心。1.2 节点角色与规模的最小方案我这次规划的是最经典的3节点结构1个控制平面节点加2个工作节点。如果你的机器资源紧张也可以把控制平面和工作负载混在一起但生产环境强烈不建议这么干。控制平面节点一旦被业务Pod挤爆内存apiserver会非常不稳定。节点角色主机名建议推荐配置control-planek8s-master2C4G起步worker-1k8s-worker14C8G根据负载调整worker-2k8s-worker24C8G根据负载调整这里的主机名不是随便起的后面kubelet注册节点、日志定位、证书组织名称都会用到。建议安装前就让主机名规范下来而不是装完了再改。1.3 版本对齐k8s组件版本一致性原则k8s集群里需要版本对齐的有三件套kubeadm、kubelet、kubectl。这三个组件的版本必须保持在同一Minor版本。比如你都用v1.28.x系列那么kubeadm是v1.28.3kubelet也必须是v1.28.3kubectl可以略微放宽但最好一致。容器运行时尽量选择稳定版本的新版本。containerd当前主流是1.7.x至少要大于1.6.x否则和kubelet的CRI交互可能出现兼容问题。提示系统内核版本建议在3.10以上实际测试中5.x内核在性能上明显更好特别是网络和文件系统相关的场景。装系统的时候直接选择较新发布版本通常不会错。2. 每台机器都要过的初始化关卡网络、内核参数、系统服务这个阶段最容易被人忽略但恰恰是后面很多诡异问题的根源。所有节点包括控制平面和工作节点都需要做同样的操作。2.1 主机名、hosts解析和关键内核模块先给每台机器设置主机名以控制平面节点为例hostnamectl set-hostname k8s-master然后修改每台机器的/etc/hosts把三个节点的IP和主机名对应关系写进去。这一步的目的是让集群内部组件之间可以通过主机名互访避免之后kubelet或etcd因为解析问题导致通信失败。192.0.2.10 k8s-master 192.0.2.11 k8s-worker1 192.0.2.12 k8s-worker2随后需要加载两个内核模块。overlay负责容器镜像的分层存储br_netfilter负责桥接网络的iptables规则穿透缺少它会导致Service的ClusterIP转发失效。modprobe overlay modprobe br_netfilter为了让这两个模块在重启后依然生效写入模块加载配置我习惯直接创建一个.conf文件放在/etc/modules-load.d/下面。2.2 sysctl内核参数IPv4转发和iptables桥接接下来是内核参数这一步直接关系到Pod网络和Service转发的正常工作。创建文件/etc/sysctl.d/k8s.conf内容如下net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1执行 sysctl --system 让参数立即生效。这三个参数不用背只需要理解逻辑容器网络通过bridge转发时iptables规则必须对桥接流量生效否则Service对应的DNAT规则永远匹配不到容器流量。2.3 关闭swap和防火墙策略swap在k8s中是被默认禁止的。kubelet在资源分配时如果检测到swap开启在旧版本会直接拒绝启动。虽然新版本在一定程度上容忍swap但为了稳定性我依然选择关闭它swapoff -a sed -i / swap / s/^/#/ /etc/fstab注意两行都要执行否则重启后swap又回来了。防火墙部分要分场景看待。我在干净的内网测试环境里会直接关闭firewalld减少干扰变量。但是生产环境建议保留防火墙只放行必要端口6443apiserver、2379/2380etcd、10250kubelet、30000-32767NodePort服务段。systemctl stop firewalld systemctl disable firewalld3. 容器运行时containerd是第一个大坑集中地容器运行时是整个集群里最容易出错的一层。我在早期版本里习惯装Docker然后让k8s通过dockershim通信。自从k8s移除了dockershim后新的环境中直接用containerd才是正道没有必要再多套一层Docker。3.1 安装containerd及基础配置文件安装containerd相对简单通过发行版软件源安装即可yum install -y containerd但安装出来只是开始。系统自带的默认配置通常不满足k8s运行需求需要先导出一份默认配置再修改。mkdir -p /etc/containerd containerd config default /etc/containerd/config.toml很多人省略了这一步导致之后Pod反复进入ContainerCreating状态。3.2 最关键的两处配置修改修改config.toml时有两个关键点缺一不可。第一处是SystemdCgroup参数。k8s的kubelet默认使用systemd作为cgroup驱动containerd的默认配置却是cgroupfs。两者不一致会导致Pod里进程的资源统计错乱、偶发杀进程。必须把这段配置改为true[plugins.io.containerd.grpc.v1.cri] systemd_cgroup true第二处是pause镜像地址。containerd在创建Pod时会先拉取一个sandbox镜像pause这个镜像的默认地址指向公网仓库。在很多网络环境下从公网仓库拉取镜像可能不稳定。我的一般做法是提前在能连通目标仓库的环境上把所需镜像导出来打包带到各节点或者把配置里的sandbox_image指向团队内网已有的镜像仓库地址。sandbox_image registry.example.local/k8s/pause:3.9这里registry.example.local是示例域名实际使用中你需要替换为自己内网仓库的地址。保存配置后重启containerdsystemctl restart containerd注意每次修改config.toml后都要通过 systemctl restart containerd 重启并且建议用 crictl pull 提前测试一次镜像拉取是否正常别等到kubeadm初始化了才发现运行时有问题。3.3 用crictl验证运行时状态安装完containerd后我习惯验证一遍crictl version crictl pull nginx:latestcrictl是CRI命令行工具用来和容器运行时直接交互。如果pull能够成功说明containerd的运行环境基本没问题。这个工具后续排查Pod状态时也会经常用到。4. kubeadm初始化控制平面参数一旦定下后面不好改容器运行时就绪后开始在控制平面节点安装k8s三件套并执行初始化。这一节我把需要装的组件、命令参数的含义和后续配置全部展开。4.1 软件源配置与三件套安装kubeadm、kubelet、kubectl三件套通过软件源安装。我这里不给具体的源配置细节只说一个原则把对应发行版的软件源地址配置为团队内维护的稳定源或者直接使用发行版官方源然后安装指定版本。yum install -y kubeadm-1.28.3 kubectl-1.28.3 kubelet-1.28.3这里有一个容易忽略的细节需要确认kubelet开机自启但暂不启动。因为kubelet要等kubeadm生成相关配置后才能正常工作提前启动会报一堆错误虽然不影响后续但会让你的错误日志看得心烦。systemctl enable kubelet先enable不start。等init完成后kubelet自然会被kubeadm拉起。4.2 kubeadm init 完整参数与含义在控制平面节点执行初始化前我最后确认一次参数。生产上常用这样一套kubeadm init \ --kubernetes-versionv1.28.3 \ --apiserver-advertise-address192.0.2.10 \ --control-plane-endpoint192.0.2.10 \ --pod-network-cidr10.244.0.0/16 \ --service-cidr10.96.0.0/12逐个解释参数的意义apiserver-advertise-addressapiserver对外广播的IP地址通常就是本机内网IP。control-plane-endpoint高可用集群时是负载均衡器的地址单控制平面直接填本机IP。pod-network-cidrPod网段。这个网段必须和你后面要装的CNI插件保持一致。如果用的网络方案是flannel默认匹配10.244.0.0/16如果用的方案是calico默认使用10.10.0.0/16或102.168.0.0/16一定要提前查清楚再填。service-cidrService网段用于ClusterIP分配。Pod网段和Service网段绝对不能重叠否则一旦IP冲突网络表现会非常诡异。4.3 初始化成功后的三个配置步骤初始化成功后会输出一大段提示。重点有三件事要做。第一配置本用户访问集群的kubeconfigmkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config第二保存好join命令。kubeadm init的输出末尾会给出一个kubeadm join命令包含token和ca证书hash这个命令是工作节点入集群的关键复制保存下来后面要用。第三如果你需要多控制平面高可用还需要复制证书到其他控制平面节点如果没有这个需求可以忽略。执行完以上步骤用kubectl get nodes看状态。这时的节点大概率为NotReady状态不要慌这是正常的因为还没有部署网络插件。5. 工作节点加入集群从token到证书的全流程工作节点的前缀步骤和前面2、3节完全一样需要把基础设施初始化、containerd配置全部做完然后再执行join。很多踩坑都是因为工作节点上的containerd配置没改直接join进来之后Pod无法创建。5.1 工作节点执行join在控制平面节点用如下命令查看当前的tokenkubeadm token list如果token过期或者你压根没保存之前的join命令可以用如下命令重新生成kubeadm token create --print-join-command生成的结果就是一条完整的join命令直接在工作节点上以root身份执行即可。它内部做的事情是下载集群CA证书、生成该节点的kubelet配置、向apiserver发起注册请求。kubeadm join 192.0.2.10:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx5.2 确认节点健康状态回到控制平面节点执行kubectl get nodes正常情况会看到新节点以NotReady状态加入等待网络插件部署完成后转为Ready。如果节点状态是Unknown通常说明kubelet没有正常启动或网络不通如果是NotReady并伴随MemoryPressure等提示需要进一步查看kubelet日志。5.3 节点token过期与重新申请的注意点token默认有效期是24小时如果你隔了一段时间再添加新节点大概率会碰到token过期的问题。重新用kubeadm token create --print-join-command生成即可不需要重新初始化整个集群。这个命令在每次扩容时几乎都会用到值得记牢。6. CNI网络插件部署时机和Pending的排查思路网络插件决定Pod之间、Pod和Service之间的连通性。它必须在集群初始化后立即部署越早越省心。如果拖太久即使节点状态表现正常DNS和网络功能也是残缺的。6.1 为什么集群初始化后要立刻部署网络插件kubeadm在初始化阶段不会帮你部署任何CNI插件。CNI必须由用户额外安装。没有CNI时节点的condition会处于NotReady。原因是kubelet启动时有一个网络准备检查它要求节点上存在可用网络接口给Pod分配没有CNI就完不成这个检查。CNI插件的选择直接影响网络转发模型。我目前的测试环境用的是基于IPIP或VXLAN封装方案的CNI它能覆盖大多数跨节点通信场景无需额外依赖底层网络设施。如果你追求极致的性能可以选择基于BGP或eBPF的方案但它们的部署复杂度更高第一次搭建不建议使用。6.2 部署步骤先下载manifest再apply从CNI项目的官方仓库下载对应的yaml文件然后执行kubectl apply -f calico.yaml下载的yaml文件会直接创建DaemonSet、Deployment等一系列资源。执行后观察资源状态kubectl get pods -n kube-system -o wide正常情况下calico和coredns的Pod会陆续变成Running。coredns依赖网络插件所以网络插件工作之前它会一直Pending这是正常现象。这里有必要提醒一个坑某些CNI版本的manifest里默认指定了网段如果你在kubeadm init时指定的pod-network-cidr和它不一致需要修改yaml中的对应字段后再apply否则Pod会陷入一直创建、一直失败的循环。6.3 网络Pod一直Pending的排查链路遇到Pod一直Pending我一般按下面的顺序查先看Pod的Events详情kubectl describe pod -n kube-system如果是ImagePullBackOff说明镜像是根本原因需要回到containerd配置镜像源或者手动导入镜像。如果是FailedCreatePodSandBox多半是CNI冲突或网卡问题检查kubelet日志。如果状态是CrashLoopBackOff去查看Pod日志最常见原因是etcd或apiserver的证书问题。网络插件是很诚实的报错多数都能直接定位到某个组件上。怕的是你不断重启网络插件但不能静下心看日志白折腾一圈。7. 验证与高频故障现场实操时最容易碰到的三类问题全套部署完之后最忌马上宣称“装好了”先做一轮完整验证。7.1 验证命令清单我习惯按顺序执行以下命令kubectl get nodes kubectl get pods -n kube-system kubectl run test-pod --imagenginx:1.25 kubectl get pod test-pod -o wide kubectl expose pod test-pod --port80 --typeNodePort kubectl get svc到这一步如果test-pod的状态是Running且通过NodePort可以访问nginx页面说明集群的基本链路已经通了节点调度、镜像拉取、Pod网络、Service网络、NodePort映射全部正常。7.2 三个高频故障的根因排查第一类节点NotReady。先看节点上是哪个Pod异常再看kubelet日志。运行kubelet日志查看命令后最常看到的是CNI配置未找到。如果你确实已经安装CNI检查/opt/cni/bin目录下是否有对应的可执行文件。有时候是软件包没装全重装cni-plugins即可。第二类镜像拉取失败。公网镜像仓库拉取不稳定是常见问题。解决方案分两层在生产环境搭建内网镜像仓库同步所需镜像在测试环境提前通过crictl pull把常用镜像拉到本地Pod创建时直接复用。永远不要在每个节点上各自和公网仓库较劲收效甚微。第三类证书类错误。k8s内部组件间通信全部靠TLS证书。最常见的报错是x509 certificate has expired或unknown authority。前者基本都是集群时间不同步导致ntp同步服务必须全集群覆盖。后者多数是kubeconfig里的证书和集群实际证书不匹配重新从主节点拷贝admin.conf即可。7.3 给自己的时间沉淀建议最后分享一点个人习惯。每次部署完一套集群后我会把当时的kubeadm init原始命令、join命令、CNI版本和yaml文件改动点全部记录到一套部署文档里下次遇到类似环境直接拿来对照差异。不要依赖记忆那点记录存的不是字是当时的排查思路。以我的经验k8s安装本身最多花半天真正花时间的是安装完之后的那几轮验证和排障。只要环境初始化、containerd配置、网络插件选择这三关稳住了整套集群基本不会出大幺蛾子。以后想扩展节点按住第5节重新生成token的方法走一遍就行这条路我已经反复走过很多次了稳定性是有保证的。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/19 5:06:32
open-code-review:基于AST+规则引擎的可编程代码审查系统
2026/10/19 5:06:32
鸿蒙BLE蓝牙接入全流程解析:从扫描到数据传输的实战指南
2026/10/19 5:01:32
叉积的本质:从行列式到对偶向量,彻底理解叉积公式
2026/10/19 6:51:38
AI智能排版实战:从杂乱文本到规范文档的自动化流程
2026/10/19 6:51:38
从Load Average到根因定位:Linux性能排查三板斧
2026/10/19 6:51:38
Mono-InternVL-2B-S1-1图片预处理全攻略:动态分辨率与448x448分块实操详解
2026/10/19 6:51:38
Linux系统变慢?从负载到CPU/内存/IO的精准排查实战
2026/10/19 6:51:38
AI应用开发工程师学习路线:从Python基础到RAG与Agent实战
2026/10/19 6:46:38
STM32F1+AD9834波形发生器:带触摸交互的DDS教学验证系统
2026/10/19 0:01:13
频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现
2026/10/19 0:01:13
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道
2026/10/19 0:01:13
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统
2026/10/18 0:02:43
OpenResearch实战:Claude Code、Codex、OpenCode、Cursor 工作流搭建与故障排查
2026/10/19 2:04:59
知识管理核弹:用Obsidian构建第二大脑的工程化方案(TaoToken 统一 Key 接入版)
2026/10/18 0:02:43
金融AI落地指南:从调研报告到技术选型与工程实践
2026/10/17 10:15:50
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/16 18:46:48
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/16 18:46:46
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)