1. 为什么在 Debian 11 上手动部署 K8s 不再是“硬核玩家专属”你点开这篇大概率不是为了看一句“已成功”就关掉——而是正卡在某个环节kubeadm init报错cgroup driver mismatchcontainerd启动后crictl ps一片空白或者apt update一跑就是十分钟镜像拉到一半超时失败。我试过三次重装 Debian 11前两次都栽在同一个地方系统默认配置、容器运行时与 Kubernetes 官方要求之间那几处看似微小、实则致命的错位。这不是环境问题是 Debian 11 的设计哲学和 K8s 生产级部署规范之间的“代际摩擦”。Debian 11bullseye自带的systemd默认启用unified cgroup hierarchycgroup v2而早期 containerd 和 kubelet 对 v2 的兼容性并不完善它默认的apt源走的是archive.debian.org延迟高、镜像少、GPG 密钥易过期它的内核虽然稳定但overlay2存储驱动需要显式确认启用否则containerd会静默降级到vfs——这会导致镜像层无法共享、磁盘暴涨、Pod 启动慢如蜗牛。这些都不是 bug是 Debian 坚守“稳定压倒一切”的代价而 K8s 要求的是“精确控制每一处底层行为”。所以“已成功”三个字背后其实是把 Debian 11 从一个通用服务器系统精准校准为 Kubernetes 的专用运行底座的过程。这个过程不需要你成为内核专家但必须理解每一步“为什么非得这样改”。比如为什么必须关闭swap不是因为 K8s 代码里写了if swap_enabled { die() }而是因为kubelet的内存驱逐逻辑依赖cgroup.memory的精确统计而swap会让这个统计失效导致 OOM Killer 在错误时间杀死关键组件。再比如为什么阿里云镜像源要分两层配置一层给apt系统包一层给containerd容器镜像因为它们根本不在同一个协议栈上运行——apt走 HTTP/HTTPScontainerd走 gRPC 镜像仓库 API混用会直接报failed to resolve reference。这些细节官方文档不会展开讲但你在生产环境重启一次 master 节点就会记住一辈子。这篇文章不讲“K8s 是什么”也不堆砌kubeadm init --pod-network-cidr10.244.0.0/16这种命令。我要带你走一遍从裸机 Debian 11 ISO 刷入到kubectl get nodes显示Ready状态的完整链路每一步都标注清楚这是在修复哪个默认偏差这个参数影响哪一层组件如果跳过会出什么具体现象我会用真实终端日志片段佐证而不是只给你结论。你照着做能跑通你跳过某步我能告诉你接下来三小时你会看到什么报错——这才是“已成功”背后真正值得复用的经验。2. 系统级预处理让 Debian 11 主动“卸下稳定包袱”Debian 11 的稳定体现在它拒绝自动更新内核、拒绝启用新特性、拒绝修改已有行为。但 K8s 要求它主动适配。这一步不是可选项是所有后续操作的前提。我把它拆成四个不可跳过的子任务每个都对应一个具体的、可验证的系统状态变更。2.1 关闭 swap 并永久禁用很多人执行sudo swapoff -a就以为完事了结果 reboot 之后kubectl get nodes卡在NotReadyjournalctl -u kubelet里刷屏failed to run Kubelet: unable to load bootstrap kubeconfig。其实问题早埋下了kubelet启动时会检查/proc/swaps只要发现任何 swap 分区或文件就会直接退出并留下一条极不友好的日志“cgroup memory controller not enabled”。它没说错但误导了所有人——真正的问题是 swap 本身。正确操作流程# 1. 查看当前 swap 使用情况 sudo swapon --show # 如果输出为空说明已关闭否则继续 # 2. 临时关闭所有 swap sudo swapoff -a # 3. 永久禁用注释掉 /etc/fstab 中所有 swap 行 # 先备份 sudo cp /etc/fstab /etc/fstab.bak # 再用 sed 批量注释比手动 vi 更可靠避免漏行 sudo sed -i /swap/d /etc/fstab # 注意这里用 /swap/d 而不是 /swap/ s/^/#/因为有些 swap 行可能写成 UUIDxxx none swap sw 0 0用 d 直接删除更彻底 # 4. 验证reboot 后执行 free -h | grep Swap # 输出应为Swap: 0B 0B 0B提示别信cat /proc/swaps输出为空就万事大吉。systemd可能在启动时根据/etc/crypttab或其他机制重新激活 swap。free -h是唯一可信指标。2.2 启用 iptables-legacy 并配置 sysctlDebian 11 默认使用nftables作为iptables的后端但kube-proxy的iptables模式目前仍是默认且最稳定模式与nftables存在兼容性问题典型表现是CoreDNSPod 一直ContainerCreatingkubectl logs -n kube-system coredns-xxx显示readiness probe failed而iptables -t nat -L KUBE-SERVICES却是空的。这是因为kube-proxy写入的是iptables-legacy规则而nftables不识别它们。解决方案是强制回退到iptables-legacy# 1. 切换默认 iptables 版本 sudo update-alternatives --set iptables /usr/sbin/iptables-legacy sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy sudo update-alternatives --set arptables /usr/sbin/arptables-legacy sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy # 2. 验证切换结果 sudo iptables -V # 输出应为iptables v1.8.7 (legacy) # 3. 加载必要内核模块Debian 11 默认不加载 sudo modprobe br_netfilter sudo modprobe overlay # 4. 永久化内核参数创建独立配置文件避免污染 /etc/sysctl.conf echo net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 vm.swappiness 0 | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf # 5. 应用配置 sudo sysctl --system注意sysctl --system会重新加载/etc/sysctl.d/*.conf下所有文件比sysctl -p更可靠。vm.swappiness 0是 K8s 官方强烈建议值防止内核在内存压力下过度交换影响 Pod 响应。2.3 配置阿里云 apt 源并更新系统Debian 官方源在国内访问缓慢且不稳定apt update经常卡在Reading package lists...。阿里云镜像站https://mirrors.aliyun.com/debian/针对国内网络做了深度优化CDN 节点多同步及时。但直接替换/etc/apt/sources.list有风险Debian 11 的bullseye-security和bullseye-updates源路径与主源不同必须严格匹配。安全替换步骤# 1. 备份原文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak # 2. 生成新的 sources.list注意bullseye-security 的路径是 security.debian.org不是 mirrors.aliyun.com sudo tee /etc/apt/sources.list EOF deb https://mirrors.aliyun.com/debian/ bullseye main non-free contrib deb https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib deb https://mirrors.aliyun.com/debian-security bullseye-security main non-free contrib EOF # 3. 更新并升级--fix-missing 强制修复损坏的依赖 sudo apt update sudo apt upgrade -y --fix-missing # 4. 清理无用包 sudo apt autoremove -y关键细节bullseye-security源必须指向https://mirrors.aliyun.com/debian-security这是阿里云专门维护的安全更新镜像而非mirrors.aliyun.com/debian/下的子目录。用错路径会导致安全补丁无法安装apt list --upgradable会永远显示debian-security相关包可升级却无法获取。2.4 验证并启用 overlay2 存储驱动containerd默认尝试使用overlay2但如果内核不支持或未启用它会无声降级到vfs。vfs驱动对每个容器都复制完整镜像层10 个 nginx Pod 就会占用 10 份 120MB 镜像空间磁盘迅速告急且ctr images pull速度极慢。我们必须确保overlay2真正生效。验证与启用方法# 1. 检查内核是否支持 overlay grep -o overlay /proc/filesystems # 输出应为overlay若为空则需升级内核 # 2. 检查当前挂载的 overlay 文件系统 findmnt -t overlay # 正常应有输出如/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs ... overlay ... # 3. 如果没有手动加载模块并验证 sudo modprobe overlay echo overlay | sudo tee -a /etc/modules # 4. 创建测试目录验证 overlay2 是否可用 sudo mkdir -p /tmp/overlay-test/{upper,work,merged} sudo mount -t overlay overlay -o lowerdir/,upperdir/tmp/overlay-test/upper,workdir/tmp/overlay-test/work /tmp/overlay-test/merged sudo umount /tmp/overlay-test/merged sudo rm -rf /tmp/overlay-test实操心得findmnt -t overlay是最直接的验证方式。很多教程让你看/proc/mounts但那里信息太杂容易误判。findmnt专为过滤挂载点设计结果干净明确。如果这一步失败containerd启动后ctr info里snapshotter字段会显示native而非overlayfs这就是vfs驱动的信号。3. Containerd 深度配置不只是安装而是定义其行为边界containerd不是 Docker 的精简版它是 CNCF 毕业项目是 K8s CRIContainer Runtime Interface的参考实现。它的配置文件/etc/containerd/config.toml是整个集群容器运行时的“宪法”。Debian 11 自带的containerd包1.4.x版本较老且配置文件是空的必须手动初始化并填充关键参数。跳过这一步kubeadm init会卡在waiting for the control plane to become ready因为kubelet根本连不上containerd的 socket。3.1 安装指定版本 containerd 并初始化配置Debian 11 仓库中的containerd是 1.4.12而 K8s 1.24 推荐使用 1.6.x。我们选择1.6.30截至 2023 年底最稳定的 LTS 版本从官方 GitHub Release 页面下载二进制包而非apt install——因为apt安装的包会把配置文件放在/usr/share/containerd/config.toml而containerd默认读取/etc/containerd/config.toml极易混淆。# 1. 下载并解压 containerd 1.6.30 cd /tmp curl -LO https://github.com/containerd/containerd/releases/download/v1.6.30/containerd-1.6.30-linux-amd64.tar.gz sudo tar Czxvf /usr/local/bin containerd-1.6.30-linux-amd64.tar.gz # 2. 创建 systemd service 文件Debian 11 默认没有 sudo tee /etc/systemd/system/containerd.service EOF [Unit] Descriptioncontainerd container runtime Documentationhttps://containerd.io Afternetwork.target [Service] ExecStartPre/sbin/modprobe overlay ExecStartPre/sbin/modprobe br_netfilter ExecStart/usr/local/bin/containerd KillModeprocess Delegateyes LimitNOFILE1048576 LimitNPROC1048576 LimitCOREinfinity TasksMaxinfinity Typenotify NotifyAccessall [Install] WantedBymulti-user.target EOF # 3. 初始化默认配置生成 /etc/containerd/config.toml sudo mkdir -p /etc/containerd sudo containerd config default | sudo tee /etc/containerd/config.toml # 4. 重载 systemd 并启动 sudo systemctl daemon-reload sudo systemctl enable containerd sudo systemctl start containerd为什么不用apt install containerd因为apt安装的containerd服务文件由deb包维护升级时可能被覆盖而手动安装的服务文件完全可控。containerd config default生成的配置是“最小可行”我们需要在此基础上修改而不是从零手写。3.2 配置阿里云镜像加速器与私有仓库containerd的镜像拉取不走apt源它直连 Docker Hub 或其他 OCI Registry。国内直连 Docker Hub 极慢且kubeadm init默认拉取k8s.gcr.io镜像已被墙。阿里云提供了registry.cn-hangzhou.aliyuncs.com/google_containers镜像代理但必须在config.toml中显式配置否则ctr images pull会超时。编辑/etc/containerd/config.toml重点修改以下三处# 1. 设置默认 runtime必须否则 kubeadm 会报错 no available runtime [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] base_runtime_type io.containerd.runtime.v1.linux runtime_type io.containerd.runc.v2 runtime_engine runtime_root privileged_without_host_devices false # 关键启用 systemd cgroup 驱动与 kubelet 保持一致 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true # 2. 配置镜像仓库核心 [plugins.io.containerd.grpc.v1.cri.registry] [plugins.io.containerd.grpc.v1.cri.registry.mirrors] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.docker.io] endpoint [https://registry.cn-hangzhou.aliyuncs.com/google_containers] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.k8s.gcr.io] endpoint [https://registry.cn-hangzhou.aliyuncs.com/google_containers] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.gcr.io] endpoint [https://registry.cn-hangzhou.aliyuncs.com/google_containers] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.quay.io] endpoint [https://registry.cn-hangzhou.aliyuncs.com/google_containers] # 3. 配置 sandbox 镜像kubeadm init 必需 [plugins.io.containerd.grpc.v1.cri.sandbox_image] # 使用阿里云镜像避免拉取失败 sandbox_image registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.9关键原理mirrors配置是“域名映射”当containerd尝试拉取k8s.gcr.io/kube-apiserver:v1.24.0时它会自动重定向到registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.24.0。sandbox_image是 Pod 的基础容器pause 容器kubeadm init会先拉取它如果失败整个初始化就终止。SystemdCgroup true是必须项它告诉containerd使用systemd而非cgroupfs来管理 cgroup这与kubelet的--cgroup-driversystemd参数严格对应否则会出现cgroup driver: systemd is different from docker类似错误。3.3 验证 containerd 配置有效性配置改完不能直接systemctl restart containerd必须先验证语法否则服务会启动失败journalctl -u containerd里全是toml: line X: invalid syntax。# 1. 语法检查关键 sudo containerd config validate # 2. 重启服务 sudo systemctl restart containerd # 3. 验证 socket 连通性 sudo ctr -n k8s.io info | grep -E (runtime|snapshotter) # 正常输出应包含runtime: io.containerd.runc.v2, snapshotter: overlayfs # 4. 测试拉取镜像用阿里云镜像 sudo ctr -n k8s.io images pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.9 # 成功后应显示unpacking linux/amd64 sha256:... done # 5. 查看镜像列表 sudo ctr -n k8s.io images ls # 应能看到 pause:3.9 镜像实操避坑sudo ctr -n k8s.io中的-n k8s.io是命名空间K8s 使用k8s.io命名空间不是default。如果用错命名空间ctr images ls会显示空但镜像其实已拉取到k8s.io下。ctr -n k8s.io info的输出是最终裁判它显示的runtime和snapshotter必须与我们配置的一致。4. Kubeadm 初始化从零构建控制平面的精确控制点kubeadm init不是黑盒命令它是 K8s 官方提供的“控制平面组装器”。它会生成证书、启动 etcd、部署kube-apiserver等组件但所有行为都受命令行参数和配置文件控制。Debian 11 上的常见失败90% 源于参数与系统实际状态不匹配。我们必须放弃“一键初始化”幻想用kubeadm config文件进行声明式配置。4.1 创建 kubeadm-config.yaml声明所有关键参数kubeadm init的默认行为如--pod-network-cidr10.244.0.0/16只是推荐值不是强制值。Flannel 网络插件要求--pod-network-cidr必须是10.244.0.0/16而 Calico 要求192.168.0.0/16。我们必须在配置文件中显式声明而不是依赖命令行参数因为配置文件可以版本化、可审计、可复现。# 保存为 /root/kubeadm-config.yaml apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration bootstrapTokens: - token: abcdef.0123456789abcdef description: kubeadm bootstrap token ttl: 24h nodeRegistration: criSocket: unix:///run/containerd/containerd.sock taints: - key: node-role.kubernetes.io/control-plane effect: NoSchedule --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.24.0 controlPlaneEndpoint: 192.168.1.100:6443 # 替换为你的 master 节点 IP networking: podSubnet: 10.244.0.0/16 # Flannel 要求 serviceSubnet: 10.96.0.0/12 certificatesDir: /etc/kubernetes/pki clusterName: kubernetes imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers --- apiVersion: kubeadm.k8s.io/v1beta3 kind: KubeProxyConfiguration mode: iptables参数详解与选择依据criSocket: 必须指向containerd的 Unix socket。Debian 11 上containerd默认 socket 是/run/containerd/containerd.sock不是/var/run/dockershim.sockDocker 时代。controlPlaneEndpoint: 这是集群的 VIP虚拟 IP用于高可用场景。单节点可设为本机 IP但必须确保该 IP 能被所有节点访问。6443是kube-apiserver默认端口不可更改。podSubnet:必须与后续网络插件严格一致。Flannel 的kube-flannel.yml文件里硬编码了10.244.0.0/16如果这里设成10.245.0.0/16Flannel DaemonSet 启动后会报错Failed to create SubnetManager: error retrieving pod spec for kube-system/kube-flannel-ds-xxx: pods kube-flannel-ds-xxx not found。imageRepository: 指定所有 K8s 系统镜像kube-apiserver,coredns等的拉取源。必须与containerd配置中的mirrors对应否则kubeadm init会尝试从k8s.gcr.io拉取并失败。KubeProxyConfiguration.mode: 显式指定iptables模式避免kube-proxy自动选择ipvs需要额外内核模块。为什么不用kubeadm init --config命令行因为配置文件可以清晰看到所有参数的依赖关系。例如podSubnet和imageRepository是强关联的写在 YAML 里一目了然而命令行参数是扁平的容易遗漏。4.2 执行初始化并处理常见故障配置文件准备好后执行初始化。这不是等待进度条结束而是全程监控日志预判并拦截失败。# 1. 执行初始化加 -v 5 输出详细日志 sudo kubeadm init --config /root/kubeadm-config.yaml -v 5 # 2. 如果失败立即查看日志定位不要盲目重试 sudo journalctl -u kubelet -n 100 --no-pager | grep -i error\|fail\|warn高频故障与精准修复故障现象根本原因精准修复命令[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]sysctl配置未生效sudo sysctl --system sudo systemctl restart kubelet[ERROR Port-10250]: Port 10250 is in usekubelet已在运行且占用了端口sudo systemctl stop kubelet sudo rm -rf /var/lib/kubelet/pki sudo kubeadm reset -ffailed to pull image k8s.gcr.io/coredns:v1.8.6imageRepository未生效或containerd配置错误sudo ctr -n k8s.io images pull registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:v1.8.6然后重试kubeadm inittimed out waiting for the conditioncontainerdsocket 不可达sudo ss -tulnp | grep containerd确认/run/containerd/containerd.sock存在且权限正确srw-rw---- 1 root containerd关键经验kubeadm init失败后不要直接kubeadm reset。先用journalctl看kubelet日志90% 的问题都能定位到具体组件。kubeadm reset会清理所有证书和配置重试成本极高。sudo ss -tulnp | grep containerd是终极诊断命令它能确认containerd进程是否真的在监听 socket比systemctl status containerd更底层、更可靠。4.3 初始化成功后的必要收尾操作kubeadm init成功输出Your Kubernetes control-plane has initialized successfully!后还有三步不可省略否则kubectl无法工作Node 无法加入。# 1. 配置 kubectl必须用 root 用户执行因为 kubeadm 生成的证书在 /etc/kubernetes/admin.conf mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config # 2. 部署 Flannel 网络插件必须在 kubectl 配置好后执行 kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml # 3. 验证集群状态耐心等待 2-3 分钟 watch -n 2 kubectl get nodes,po -A # 正常状态NODES 显示 STATUSReadyPODS 在 kube-system 命名空间下全部 Running注意kubectl apply -f的 URL 必须是raw.githubusercontent.com不是github.com。后者返回的是 HTML 页面kubectl会报错error: unable to parse https://github.com/...: couldnt get version/kind; json: unknown field site。watch -n 2每 2 秒刷新一次比手动kubectl get更高效能实时观察corednsPod 从Pending到ContainerCreating再到Running的全过程。5. 验证与排错用真实场景检验“已成功”的含金量“已成功”不是kubectl get nodes显示Ready就结束而是要通过一系列破坏性测试证明集群具备生产就绪的基础能力。我在某次部署后get nodes是Ready但kubectl run nginx --imagenginx却卡在ContainerCreatingkubectl describe po nginx显示FailedCreatePodSandBox。这说明containerd的sandbox_image配置或拉取失败表面成功底层脆弱。5.1 基础功能验证从 Pod 到 Service测试 1部署无状态应用# 1. 创建 nginx Pod kubectl run nginx --imagenginx:alpine --port80 # 2. 检查 Pod 状态 kubectl get po -o wide # 正常STATUSRunning, NODE你的节点名, IP非空 # 3. 进入容器执行 curl 测试 kubectl exec -it nginx -- sh -c curl -s http://127.0.0.1 | head -5 # 应输出 nginx 欢迎页 HTML 片段 # 4. 暴露为 ClusterIP Service kubectl expose pod nginx --port80 --target-port80 --typeClusterIP # 5. 从另一个 Pod 访问该 Service kubectl run test --rm -i --tty --imagebusybox:1.35 -- sh # 在 busybox 容器内执行 # wget -qO- http://nginx.default.svc.cluster.local # 应返回 nginx 欢迎页关键验证点wget -qO- http://nginx.default.svc.cluster.local。这测试了 K8s 的 DNS 服务CoreDNS和 Service 的 ClusterIP 功能。如果失败kubectl get po -n kube-system会发现corednsPod 处于CrashLoopBackOff原因通常是podSubnet配置错误或flannelDaemonSet 未正常运行。测试 2验证网络插件连通性Flannel 部署后会为每个 Node 分配一个/24子网如10.244.1.0/24Pod IP 必须属于该子网。我们手动检查路由表确认 Flannel 正确注入了跨节点路由。# 1. 查看本机路由表 ip route | grep 10.244 # 正常应有10.244.0.0/24 via 10.244.0.0 dev flannel.1 # 本机 Pod 网段 # 10.244.1.0/24 via 192.168.1.101 dev eth0 # 其他节点 Pod 网段下一跳是对方 Node IP # 2. 获取另一个 Node 的 IP如果是单节点此步跳过 kubectl get nodes -o wide # 3. 从本机 ping 对方 Node 的 Pod 网段网关flannel.1 接口 IP # 先查对方 flannel.1 IPkubectl get nodes -o wide | awk {print $6} | tail -n 2 # 假设是 10.244.1.0ping 其网关 10.244.1.0 ping -c 3 10.244.1.0原理Flannel 的host-gw后端模式会在每个 Node 上添加一条路由指向其他 Node 的flannel.1接口 IP。ip route | grep 10.244是最直接的验证方式比kubectl get ds -n kube-system更底层、更可靠。5.2 常见“伪成功”现象与根因定位很多部署者看到kubectl get nodes是Ready就认为成功但实际存在隐患。以下是三种典型的“伪成功”以及如何用一条命令快速识别现象根因诊断命令修复方向kubectl get nodes显示Ready但kubectl get po -A中coredns处于PendingflannelDaemonSet 的tolerations未匹配node-role.kubernetes.io/control-plane:NoSchedule污点kubectl describe ds kube-flannel-ds -n kube-system | grep Tolerations编辑kube-flannel.yml在spec.template.spec.tolerations下添加key: node-role.kubernetes.io/control-planekubectl get po -A全部Running但curl http://node-ip:30000无法访问 NodePort Serviceiptables-legacy未生效kube-proxy写入的规则被nftables忽略sudo iptables -t nat -L KUBE-NODEPORTS | wc -l应 0重新执行2.2节的update-alternatives和sysctl步骤kubectl run创建的 Pod IP 是10.244.0.2但ip a show flannel.1显示inet 10.244.0.0/32flannel配置的Network与kubeadm-config.yaml的podSubnet不一致kubectl get cm kube-flannel -n kube-system -o yaml | grep Network删除kube-flannelConfigMap 和 DaemonSet重新kubectl apply -f kube-flannel.yml实操技巧kubectl describe ds kube-flannel-ds -n kube-system | grep Tolerations这条命令能瞬间定位污点容忍问题。Tolerations是 DaemonSet 能在 Master 节点上运行的关键kubeadm init生成的kube-flannel.yml默认不包含对control-plane污点的容忍必须手动添加否则flannelPod 根本不会被调度到 Master 节点coredns就永远Pending。5.3 性能基线测试确认底层运行时健康最后用一个轻量级压力测试确认containerd和kubelet的协同是高效的。我们部署一个stress-ngPod模拟 CPU 和内存压力观察系统响应。# 1. 部署 stress-ng Pod限制资源避免压垮节点 cat EOF | kubectl apply -f - apiVersion: v1 kind: Pod