先把丑话说在前面:K8s 入门最大的坎,不是概念多,而是大多数人把 Docker 和 K8s 之间的边界彻底搞混了。我见过不少同事,docker run 用得飞起,到了 K8s 里却连 Pod 和容器是什么关系都讲不清;也见过有人把 Pod 直接当成容器来管,遇到多容器 Pod 启动问题就当场懵掉。这篇内容不是官方文档的搬运,是我从 Pod 核心原理一路做到 Rancher 实战、再把单节点 K8s 上的整套微服务环境迁移上云的完整梳理。我会把 Pod 为什么要存在、kubectl 和原生 Dashboard 怎么配合日常管理、Rancher 部署业务容器并解决外部访问、以及若依(RuoYi)微服务不停服不丢数据迁移到阿里云 ECS 的全链路都讲一遍。适合刚学 K8s 的人建立整个体系,也适合准备上生产环境的同学直接对照操作。
1. Pod 到底是什么?一个容易被误解的 K8s 最小单元
1.1 K8s 为什么不直接管容器
很多从 Docker 转过来的朋友,第一个问题就是:K8s 里最小管理单位既然是容器,那为什么要多套一层 Pod?直接把容器扔给 K8s 管不是更简单吗?
这个问题想明白了,K8s 的整体架构也就通了一半。Docker 容器本身解决的是"单机上怎么打包和运行应用",它天然不具备跨主机调度的能力。你在 Node1 上跑了一个 nginx,但 Node2 上怎么访问它?Docker 时代你得自己维护端口映射、自己写服务发现。K8s 出现就是为了解决大规模编排问题,它需要一个比容器更上层的概念来承载调度、网络、存储和生命周期的统一管理。
Pod 就是这一层的产物。按照官方说法,Pod 是 K8s 中最小的部署单元和调度单元。一个 Pod 里可以有一个容器,也可以有多个容器。K8s 不会单独调度某一个容器,而是把 Pod 整体调度到某个节点上,Pod 里的所有容器共享同一个 Network Namespace、共享同一个 IP 地址、共享挂载的存储卷。你可以把 Pod 理解成"一组需要紧密协作的进程的集合体",这些进程被绑定在同一台机器上,用 localhost 就能互相通信。
这个过程里有个很关键的分工逻辑:API Server 负责接收请求、Scheduler 负责决定 Pod 落在哪个节点、kubelet 负责在节点上真正拉起容器、kube-proxy 负责维护网络规则。但所有动作的颗粒度都是 Pod,不是容器。
1.2 一个 Pod 多个容器:sidecar、init 容器与共享生命周期
单容器 Pod 没什么难理解的,真正容易出问题的是多容器 Pod。这里先说一个大家都很关心的场景:一个 Pod 里如果有多个容器,其中一个容器没有成功启动,会不会影响其它容器?
答案是:会,而且影响方式比你想的更直接。
先说多容器 Pod 的典型结构。常见的有两类角色:一类是 sidecar 容器,它跟主容器并行存在,负责辅助功能,比如日志采集、网络代理(Envoy、Istio 的 istio-proxy 就是典型的 sidecar)、指标上报;另一类是 init 容器,它必须先于主容器启动完成,主容器才会被创建,init 容器一般用来做初始化动作,比如等待数据库就绪、生成配置文件、预加载数据。
这两种角色对 Pod 状态的影响完全不同。init 容器只要有一个失败,整个 Pod 就会一直停留在初始化阶段,主容器根本不会启动。sidecar 容器虽然和主容器并行,但 K8s 判断 Pod 是否 Ready 的依据是所有容器都处于 Running 且通过就绪探针。假如日志采集的 sidecar 因为镜像版本问题一直 CrashLoopBackOff,主容器就算正常运行,整个 Pod 也会被标记为 NotReady。
实际影响是什么?Service 的 Endpoints 里会摘掉这个 Pod,负载均衡不会把新流量转发进来;如果配置了滚动更新,新版本 Pod 一直不 Ready,Deployment 会卡住,旧版本 Pod 也不会被删除。我踩过这个坑:一个应用的主进程好好的,就是因为 sidecar 的采集配置写错,导致整条链路的数据流全断了。
所以记住一个结论:在 Pod 层面,容器之间不是"各管各的",而是一荣俱荣、一损俱损。这也是为什么多容器 Pod 里的每个镜像都要做好健康检查,别指望某个容器挂了其它容器还能独善其身。
1.3 Pod 从创建到销毁:生命周期与常见故障定位
Pod 的生命周期在不同阶段有不同的状态,这是排查问题的基本功。
一个 Pod 大致会经历这几个阶段:
- Pending:Pod 已被 API Server 接受,但还没有分配到节点,或者正在拉取镜像、初始化存储。卡在这通常是资源不足、镜像拉取太慢、PVC 没绑定成功。
- Running:Pod 已绑定节点,所有容器已创建,至少有一个容器还在运行。
- Succeeded:所有容器正常退出,一般用于 Job 类任务。
- Failed:至少有一个容器以非零状态退出。
- Unknown:kubelet 跟 API Server 失联,通常是节点本身出了问题。
除了这几个大阶段,K8s 内部还有一组 Conditions 可以帮助判断细节,最常用的四个是:PodScheduled、Initialized、ContainersReady、Ready。用 kubectl describe pod 能看到它们的状态和最后变更时间,排查卡在哪个环节非常有用。
举个例子,Pod 一直 Pending,你第一反应不是去看容器日志,而是 kubectl describe pod xxx,看 Events 区域写的什么原因。最常见的是 0/1 nodes are available: 1 Insufficient cpu,意思是所有节点都满足不了 CPU 请求,解决办法要么扩容节点,要么调小 requests 配置。如果节点
