尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
一条Pod启动流程,彻底讲清K8s容器编排的核心原理
最近有两位朋友不约而同地问我同一个问题K8s学起来怎么这么碎一位是从数据库运维转过来的另一位是做Java后端开发的。他们的共同感受是——单看概念都能懂什么Pod、Deployment、Service、Node每个名词解释背得滚瓜烂熟但合到一起就不知道这些东西到底是怎么协作的更不知道一条命令敲下去之后系统内部发生了什么。我给的回答也很统一别急着背概念先盯住一条“单节点容器启动流程”走一遍。这条链路串完之后你再回头画K8s思维导图每个组件在哪个环节出场、负责什么事自然就立起来了。这篇文章就干这件事我把自测和学习的过程中沉淀下来的思路完整记录下来从整体认知到单节点部署、再到一条Pod启动的全链路拆解最后附上我踩过的坑和排查套路希望对正在入门K8s的人有用。1. 学K8s先别急着敲命令一张思维导图的核心骨架1.1 先分清“容器运行时”和“容器编排平台”很多人在第一关就被绕晕了因为Docker和K8s都在“玩容器”热搜词里也常年挂着“k8s和docker区别”“k8s和docker的关系与区别”。我的理解是Docker解决的是“怎么把容器跑起来”K8s解决的是“怎么让容器按期望的状态活着、互相协作、随时替换”。打个比方Docker是发电机K8s是电力调度中心。发电机解决“电从哪里来”调度中心解决“哪台发电机供电、电送给谁、某台发电机坏了怎么切换”。单台发电机自己转没问题但几十台上百台一起转就需要一个大脑来统一管理这就是K8s存在的理由。这里还有一个版本演进的关键背景K8s很早就通过CRIContainer Runtime Interface对接容器运行时早期因为有dockershim这个中间层所以可以直接用Docker。后来K8s在1.24版本正式移除了dockershim现在主流的做法是直接使用containerd作为运行时。你不需要在这个问题上纠结太久只需记住K8s自己不启动容器真正启动容器的是符合CRI标准的运行时比如containerd、CRI-ODocker也仍然可以通过cri-dockerd来接入只是没必要了。1.2 控制面的四个组件各自管什么K8s集群分为控制面Control Plane和工作节点Worker Node。控制面是大脑工作节点是手脚。单节点环境下其实也是这个架构只是所有角色挤在同一台机器上。四个核心组件我用一张表把职责和调用关系说清楚组件进程名职责谁会调用它API Serverkube-apiserver所有请求的唯一入口负责认证、授权、校验资源定义kubectl、其他组件、外部系统etcdetcd保存集群所有状态也就是“期望状态”和“实际状态”API ServerSchedulerkube-scheduler决定新Pod调度到哪个节点API Server创建Pod后触发Controller Managerkube-controller-manager不断对比“期望状态”和“实际状态”执行调谐逻辑API Server你注意到没有组件之间不是互相直接说话而是全部通过API Server中转。API Server把状态写到etcd其他组件通过Watch机制感知变化然后各司其职。这个设计的意义在于控制面是一个整体任何一个组件挂了不会导致整个集群失控因为状态在etcd里重新拉起组件后它会自动追上最新状态。1.3 思维导图不要按组件抄要按数据流画我看过很多人画的K8s思维导图基本都是“控制面API Server、etcd、Scheduler、Controller Manager工作节点kubelet、kube-proxy、容器运行时……”最后变成一张组件名词表看了等于没看。我的建议是按数据流画只画两条主线请求路径kubectl → API Server → etcd期望状态落地执行路径API Server → Scheduler调度决策→ kubelet执行者→ 容器运行时 → 具体容器进程所有组件、概念、扩展功能都挂在这两条主线上。后面第2章拆解容器启动流程时你会发现这两条路径刚好把每个组件串起来了。我自己就是先画了这样一张极简图再逐步把Service、Ingress、存储、配置等概念往里挂整个知识体系才真正长成树而不是散成一地名词。2. 单节点容器启动全链路kubectl run 之后发生了什么这一章是全文的硬核核心。我们直接把场景限定在单节点环境执行一条命令kubectl run nginx --imagenginx:latest这条命令到容器真正跑起来中间到底经过了多少步我用一个调用链把全貌列出来然后逐步拆解kubectl run → API Server认证、授权、校验Pod定义 → etcd保存Pod期望状态 → Scheduler调度绑定nodeName → API Server更新Pod状态写入调度结果 → kubeletWatch到自己节点上的新Pod → containerdCRI接口拉镜像、创建sandbox和业务容器 → runc创建并启动容器进程 → CNI插件分配Pod IP、配置网络 → kubelet上报Pod状态进入Running2.1 从用户命令到API Serverkubeconfig与第一道校验你输入kubectl run之后kubectl做的第一件事是读取kubeconfig文件默认在~/.kube/config。这个文件里写明了要访问哪个API Server地址、用什么凭证客户端证书或token、对应哪个集群上下文。这就是为什么你搭完集群后kubeadm会提示你把生成的admin.conf拷到~/.kube/config——没有这个文件kubectl连不上任何东西。接下来kubectl把资源定义发送给API Server的6443端口。API Server做三件事认证、授权、准入校验。认证确认“你是谁”授权确认“你能做什么”准入控制器还会做一些额外检查比如Namespace是否存在、资源名是否符合规范。这一阶段最容易出的问题就是证书过期或token失效症状通常是kubectl命令报Forbidden或者证书过期错误。单节点环境下kubeadm生成的admin证书有效期是一年学习机长期不用再回来会遇到这个坑。2.2 状态落地etcd里多了一条期望状态API Server校验通过后会把Pod对象写入etcd。注意这一步只是写了一条“期望状态”——用户想要一个名为nginx、镜像是nginx:latest的Pod。至于这个Pod现在在哪里、有没有跑起来此时都还不知道。etcd在单节点环境里就是本地的一个键值数据库默认监听2379端口。在真正的生产环境etcd通常是三个或五个节点组成集群保证控制面状态的高可用。我接触过的不少初学者会疑惑“为什么K8s要单独搞一个etcd直接用数据库存不行吗”关键原因在于etcd天生支持Watch机制还支持租约Lease、事务等特性K8s的Controller和kubelet都是依赖Watch去感知变化而不是不断地轮询数据库。2.3 Scheduler单节点也不是摆设Pod状态写入etcd后API Server会通知Scheduler有一个新Pod需要分配节点。Scheduler的职责是从所有可用节点里挑一个最合适的规则包括资源是否充足、是否有匹配的nodeSelector、是否有污点容忍等。单节点环境下调度器依然会执行完整的调度流程只是选择只有一个。但这里有一个很关键的坑kubeadm默认会给控制面节点打上污点node-role.kubernetes.io/control-plane:NoSchedule意思是“业务Pod不要调度到我这里来”。单节点学习环境中你如果不去掉这个污点执行kubectl run之后Pod会一直Pending。解决办法就一条命令kubectl taint nodes --all node-role.kubernetes.io/control-plane-这行的逻辑是去掉所有节点上名为node-role.kubernetes.io/control-plane的污点。Polling结束之后Scheduler才能把Pod绑定到当前这个节点绑定结果会通过API Server写回etcdPod对象上多了一个字段spec.nodeName。2.4 kubelet调用CRI真正的容器启动发生在这一层Pod绑定到节点后节点上的kubelet通过Watch机制发现“这上面有一个我管理的Pod”于是开始干活。这是整条链路里最核心的部分。kubelet自己并不启动容器它是通过CRI接口向容器运行时发请求。以containerd为例调用过程是kubelet → containerd的CRI插件 → containerd → runc。runc才是真正在操作系统层面创建容器进程的程序。启动一个Pod涉及两类容器沙箱容器sandbox/pause容器Pod内的第一个容器通常叫pause或sandbox。它只做一件事——创建并持有这个Pod的网络命名空间、UTS命名空间、IPC命名空间。业务容器启动后加入这个沙箱同一个Pod里的所有容器因此能共享localhost网络。业务容器你定义的nginx或其他镜像容器真正跑业务进程的家伙。为什么要搞一个pause容器因为Pod是一个“逻辑主机”的概念里面的多个容器要共享网络栈和端口空间。如果直接把所有容器各自的网络命名空间打通复杂度极高。pause容器相当于一个占位符先把命名空间建好其他容器往里加就行。在镜像拉取这一环单节点环境最常见的错误是拉取不到镜像后面第4章我会专门讲排查思路。2.5 网络、探针与状态上报启动流程的最后两公里容器进程创建完成后CNI插件开始工作。CNIContainer Network Interface负责给Pod分配IP、创建虚拟网卡、配置网络路由。常用的CNI插件有flannel、calico、weave等单节点环境装哪个其实区别不大但要注意你init集群时指定的--pod-network-cidr必须和CNI插件的默认网段匹配否则插件启动后Pod网络会异常。网络就绪后容器真正进入Running状态。此时还有最后一步kubelet会持续向API Server上报Pod的状态包括容器是否启动成功、是否通过就绪探针等。这里我要提一个很多初学者会忽略的点探针Probe。kubectl run创建的Pod默认不配置探针但生产环境的Deployment一般都会配置readinessProbe和livenessProbe。前者决定Pod是否接入Service的负载均衡后者决定Pod要不要被重启。启动流程不只是“进程起来了”就算完还要满足探针条件才算Ready。3. 把单节点环境跑起来kubeadm部署过程与选型心得3.1 为什么我推荐kubeadm而不是二进制方式你在热搜词里会看到“k8s集群搭建”“二进制搭建k8s集群”这两类诉求。二进制方式的意思是你自己下载kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、kube-proxy的二进制文件手动把它们注册成systemd服务自己签证书、写kubeconfig、配置启动参数。这个过程对理解组件之间如何通信、证书如何签发非常有帮助但新手照着做很容易卡在证书和配置文件上一排错就是几个小时。kubeadm把这些事情自动化了。它会自动生成CA证书和各组件证书自动生成kubeconfig文件自动以静态Pod的方式启动控制面组件自动生成join token方便后续加节点学习阶段我强烈建议先用kubeadm把集群跑起来对着一条启动链路理解组件协作然后再有意识地去看kubeadm生成的静态Pod定义和证书文件这样既不会淹死在细节里又能学到底层原理。3.2 安装前最关键的三个系统准备kubeadm init之前操作系统层面有三件事必须先做否则后面的问题会让你抓狂。第一关闭swap。kubelet要求swap必须是关闭状态否则启动失败。命令是swapoff -a同时需要注释掉/etc/fstab里swap那行否则重启系统后swap又会挂载回来。这一步很多人会忘结果就是每次重启都要重新处理。第二加载内核模块。K8s网络转发依赖overlay和br_netfilter模块。先确认模块已加载modprobe overlay modprobe br_netfilter然后配置系统参数让iptables能够处理桥接流量cat EOF | 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 sysctl --system第三配置容器运行时。前面说过现在主流是containerd。安装完containerd后需要修改配置把SystemdCgroup改成true这关系到kubelet和容器运行时的cgroup驱动是否一致。两者的cgroup driver如果不一致kubelet会直接报错Pod永远起不来。3.3 kubeadm init之后必须处理的两件事执行kubeadm init --pod-network-cidr10.244.0.0/16之后只要看到控制台输出“Your Kubernetes control-plane has initialized successfully”说明控制面已经起来了。但此时集群还不能正常跑业务Pod因为还有两件事必须做。第一件事是配置kubectl。把生成的admin.conf拷到当前用户下mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config第二件事是安装CNI网络插件。这一步不做节点状态会一直是NotReadyPod也创建不出来。如果你用flannel直接应用它提供的manifest文件就行kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml然后执行kubectl get nodes等一到两分钟节点状态应该变成Ready。3.4 单节点网络方案的选择建议CNI插件里flannel和calico是两种最常见的方案。flannel实现简单默认使用VXLAN隧道模式适合学习和中小规模集群性能损耗可接受。calico功能更全面支持NetworkPolicy、BGP路由模式性能更好但部署和排查难度也更高。单节点学习环境我推荐flannel因为逻辑简单出问题的概率低。等你理解了Pod网络的基本原理再试calico也不迟。热搜词里还有一个“k8s multus网络vlan配置”multus是给Pod挂多块网卡的CNI插件属于进阶玩法单节点入门阶段不建议碰容易把自己绕进去。4. 容器启动常翻车几个单节点环境的高频故障和排查顺序4.1 第一步永远是kubectl describe pod不是查日志我见过太多人一遇到Pod状态不对第一反应就是kubectl logs。这其实搞反了。logs只能看到容器主进程输出而很多启动失败发生在容器创建之前比如镜像拉不下来、卷挂载失败、探针检查失败。这些信息在logs里根本看不到全在Pod的Events里。正确做法是先看状态kubectl get pods再describe这个Pod重点看最下面的Events字段kubectl describe pod nginx-xxxxxxxx举例说明单节点环境最常见的镜像拉取失败Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 4m23s default-scheduler Successfully assigned default/nginx-xxx to node1 Normal Pulling 4m22s kubelet Pulling image nginx:latest Warning Failed 4m20s kubelet Failed to pull image nginx:latest: failed to resolve reference docker.io/library/nginx:latest Warning Failed 4m20s kubelet Error: ErrImagePull看到Failed to pull image和ErrImagePull说明问题出在镜像拉取环节。这时再去检查containerd配置的镜像仓库镜像源是否正确而不是去翻业务日志。提示kubectl describe pod里的Events是排查启动问题的第一现场。它记录了Pod从调度到创建到启动的完整过程每一步失败原因都会写在这里。4.2 CrashLoopBackOff日志要看“上一次退出的”如果你看到Pod状态是CrashLoopBackOff意思是容器起来之后又崩了kubelet在反复重启。这种情况才轮到kubectl logs登场。但有一个坑容器崩溃后当前实例可能已经退出了直接kubectl logs看到的可能是空日志。这时候要加--previous参数查看上一次容器实例的日志kubectl logs pod-name --previous比如我遇到过的一个案例镜像本身没问题但容器启动命令引用了不存在的环境变量导致进程启动后立刻退出。通过--previous看到退出前的报错信息一下子就定位了。还有一个常见原因是探针配置太严。livenessProbe设定的检查路径不对或者初始延迟时间太短容器还没就绪就被探针杀掉也会表现为CrashLoopBackOff。这种情况日志里看不到业务错误要把探针参数调大再观察。4.3 不是容器本身的问题节点级别的故障有时候Pod状态一直ContainerCreatingdescribe之后发现Events里没有明显错误或者一直卡在sandbox创建上。这时候要把视野从Pod扩大到节点和运行时。典型问题cgroup driver不一致。container的SystemdCgroup配置和kubelet的cgroup driver如果不一致kubelet启动容器时会把错误写进Events但有时候错误信息不够直观。排查时可以查看kubelet服务的日志journalctl -u kubelet -f还有一类问题更隐蔽节点磁盘压力大或镜像存储目录满导致容器镜像拉下来却无法解压。单节点环境经常因为用了小硬盘而踩这个坑df -h和docker system df如果装了docker能快速判断。这个场景对应热搜词里的“k8s docker排查”虽然现在运行时换成了containerd但排查思路是一样的先看事件再看日志最后看节点资源。4.4 单节点环境特有的坑时区、重启与快速重置我们在热搜词里看到“为什么我的docker容器时间是utc”这个问题在K8s单节点环境同样会出现。原因是容器和宿主机共享内核时钟但镜像默认的时区配置是UTC所以容器内date看到的时间比北京时间早8小时。解决方式有两种一种是在Deployment里设置环境变量env: - name: TZ value: Asia/Shanghai另一种是把宿主机的localtime挂载进去volumeMounts: - name: localtime mountPath: /etc/localtime readOnly: true我自己更推荐TZ环境变量因为跨平台可移植性更好不依赖宿主机的目录结构。单节点还有一个特殊场景机器重启后kubelet和containerd可能没有自动启动。务必确认这两项服务是enable状态systemctl enable --now containerd systemctl enable --now kubelet另外如果集群状态搞得一团糟与其逐项排查不如直接用kubeadm reset重置然后把/etc/kubernetes和/etc/cni/net.d清理干净再重新init。学习环境不需要复盘生产故障快速重建反而更高效。5. 从单节点走向集群思维导图上还差哪几块5.1 网络模型从“一机一网”到“跨节点Pod IP互通”单节点环境下CNI插件给Pod分配IP这些IP都在本机通信逻辑简单。但到了多节点集群Pod可能落在任何一台节点上而Pod IP必须是集群内全局可路由的这就是Overlay网络的用武之地。flannel的VXLAN模式把每个节点的网络包封装在UDP隧道里节点只见隧道信息对Pod IP一无所知。这套机制让“Pod IP跨节点互通”成为可能也是Service能够通过kube-proxy把流量转发到任意节点Pod的前提。学到这里你再回头看热搜词里的“k8s lnmp架构”、“rancher装k8s”会发现它们本质都是在讲怎么在K8s之上把一套完整应用跑起来底层依赖的还是网络模型和调度模型。5.2 控制面高可用意味着什么多节点集群的另一个变化是控制面要冗余。生产环境常见的架构是三个控制面节点、一个etcd集群、多个工作节点。API Server前面加负载均衡kubelet和kubectl都连负载均衡。这样任何一个控制面节点挂掉集群依然可以正常调度和响应请求。这部分内容学习路径比较靠后我不建议入门阶段就死磕。单节点先把调度、启动链路、Pod生命周期吃透高可用的原理自然能理解——无非就是把第2章的链路复制到多台机器上。5.3 给未来的自己留一份“活”的思维导图最后分享一个我的个人习惯思维导图不是画完就固定的而是跟着实践不断补充。比如我今天遇到一个CrashLoopBackOff问题排查完就会在“Pod生命周期”分支下加一条“探针初始延迟太短会误杀容器”的笔记。今天搞懂一个滚动更新就在“Deployment”分支下补充“maxSurge和maxUnavailable的语义”和验证过的例子。这样半年下来你的思维导图就是你的私人排障手册和经验库比任何网上的模板都有价值。我自己踩过不少坑之后最大的体会是K8s的知识点不是一条直线而是一张网但网的骨架是那条“容器启动链路”。先把这条链路走通、走熟再把各种概念往线上挂你就能避开“背了一堆名词依然不会排障”的尴尬阶段。如果你正在入门K8s不妨就用一台虚拟机、一个单节点集群跟着第2章这条启动链路一步步验证遇到问题了回到第4章对照排查。这个过程走完一遍你对K8s的理解会上一个大台阶。
RELATED

相关推荐

德承工控机DX-1300的Ubuntu NPU驱动安装教程与避坑指南

德承工控机DX-1300的Ubuntu NPU驱动安装教程与避坑指南

拿到一台德承工控机DX-1300,系统装好了Ubuntu,项目却在NPU驱动这一步卡了一整天,这种滋味我太熟悉了。边缘AI项目里,硬件选型往往不是最难的部分,真正的分水岭往往在软件栈能不能顺利跑起来,而NPU驱动正是这…

📅 2026/9/11 4:32:42
论文降AI率实用指南:5个免费技巧彻底改写AI腔

论文降AI率实用指南:5个免费技巧彻底改写AI腔

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/11 4:32:42
如何判断 kitty 打开大量窗口后内存占用高是否为内存泄漏(valgrind massif)

如何判断 kitty 打开大量窗口后内存占用高是否为内存泄漏(valgrind massif)

如何判断 kitty 打开大量窗口后内存占用高是否为内存泄漏(valgrind massif) 【免费下载链接】kitty If you live in the terminal, kitty is made for you! Cross-platform, fast, feature-rich, GPU based. 项目地址: https://gitcode.com/GitHub_Tre…

📅 2026/9/11 4:27:41
MORE NEWS

更多资讯

📰

FastAPI服务告警实战:从健康检查到企业微信机器人推送

半夜三点,手机在企业微信上开始疯狂震动。我迷迷糊糊摸到手机,看到告警群里一行红字:“生产服务 5xx 错误率超过阈值”。我一个激灵坐起来,打开电脑,登录 Grafana 一看——错误率确实超了,但持续了不到两分…

📰

Kubernetes策略引擎Kyverno安装指南:从入门到生产实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

2026游戏本性能评估新范式:从跑分到场景化四维实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Nextcloud Server 如何基于 config.sample.php 的说明安全修改 config.php?

Nextcloud Server 如何基于 config.sample.php 的说明安全修改 config.php? 【免费下载链接】server ☁️ Nextcloud server, a safe home for all your data 项目地址: https://gitcode.com/GitHub_Trending/se/server 在部署和日常运维 Nextcloud Server 时…

📰

25款AI应用现状解析:大厂光环下的真实困境

1. 25款AI应用现状解析:大厂光环下的真实困境最近在测试各类AI应用时发现一个有趣现象:即使是背靠科技巨头的AI产品,也普遍存在"叫好不叫座"的情况。这25款涵盖办公、创作、社交等场景的AI工具,虽然顶着大厂光环&#x…

📰

本地部署大模型实战:用Ollama告别API账单与限流困扰

先说我最近的亲身经历。上个月我随手翻了翻上季度的账单,发现光一个 AI 编程助手的 API 调用费,就够我买一台不错的二手显卡了。更扎心的是,连 ChatGPT Plus 这类订阅,也时不时因为上下文太长、请求太频繁被限流。就在这时候&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬