k8s之pod概念

  1. [1. pod基本概念](#1. pod基本概念)
  2. [2. pod网络概念](#2. pod网络概念)
  3. [3. pod的生命周期和状态](#3. pod的生命周期和状态)
  4. [4. 探针](#4. 探针)
  5. [5. 创建pod](#5. 创建pod)
  6. [6. 总结](#6. 总结)

1. pod基本概念

Kubernetes 中,Pod 是最小的网络调度单位, 每个pod可以放多个容器(例如可以放多个docke容器在同一个pod中运行),这些容器共享pod的网络、存储、以及容器规约。每个 Pod 被分配一个唯一的 IP 地址(Pod IP),这个 IP 在集群内是可达的。

在介绍其他概念之前,首先先介绍一下相关的网络概念,因为这是容易比较迷糊的地方。在k8s中,node有一个ip,pod也有一个ip,然后一个pod中又有很多pod,对应了很多ip,这容易让人造成误解。

  • node的ip:node的是node对应的物理机(虚拟机,云主机)上的真实ip,比如说,你的一台物理机在公网上,那么这个node的ip便是一个公网的ip地址,我可以在任何地方拿着这个ip连接到这个node上。
  • pod的ip:pod的ip实际上就是一个内网ip,由k8s的网络插件在pod启动的时候进行动态分配。

Pod 运行在 Node 上,其网络流量进出需经过宿主机(Node),当外部访问 Pod 时,流量先到达 Node,再由相关组件转发到对应的pod

在一个正常工作的 Kubernetes 集群中,Node 节点之间的网络必须是互通的 ------ 不仅 Node 之间要通,更重要的是,运行在不同 Node 上的 Pod 之间也必须能直接通信(三层路由可达)。
graph TD %% 定义节点和 Pod subgraph NodeA["NodeA (192.168.1.10)"] direction TB PodA["PodA IP: 10.244.1.5 Port: 8080"] PodX["Podx IP: 10.244.1.x Port: xx"] end subgraph NodeB["NodeB (192.168.1.11)"] direction TB PodB["PodB IP: 10.244.2.8 Listens: 8080"] end %% 定义 Service Service["Service: podB-service ClusterIP: 10.96.xx.xx Port: 80 → targetPort: 8080"] %% 正确通信路径 ------ PodA → PodB PodA -->|✅直接访问 Pod IP<br>curl http://10.244.2.8:8080</br>| PodB %% 推荐路径 ------ PodA → Service → PodB PodA -->|✅推荐:通过 Service<br>curl http://podB-service:80</br>| Service Service -->|自动负载均衡| PodB %% 错误路径(虚线 + 红色风格) PodA -.->|❌通常无效<br>curl http://192.168.1.11:8080</br>| NodeB PodA -->|✅显式设置<br>curl http://192.168.1.11:8080</br>| NodeB %% 添加说明注释 classDef node fill:#e0f7fa,stroke:#0097a7; classDef pod fill:#fff9c4,stroke:#fbc02d; classDef svc fill:#c8e6c9,stroke:#388e3c; classDef invalid stroke:#f44336,stroke-dasharray: 5 5; class NodeA,NodeB node class PodA,PodB pod class Service svc class NodeB invalid

2. pod网络概念

在同一个 Pod 中的所有容器共享同一个网络命名空间(network namespace),因此它们拥有相同的 IP 地址(即 Pod IP),并共享同一个端口空间。容器之间可以通过 localhost 互相访问,但必须避免端口冲突。

当你在一个 Pod 中定义多个容器,Kubernetes 会将这些容器放在同一个 Linux 网络命名空间中

这意味着:

  • 所有容器看到的是同一个网络接口(如 eth0)
  • 所有容器共享同一个 IP 地址 ------ 即 Pod IP
  • 所有容器共享同一个端口命名空间 ------ 不能有两个容器监听同一个端口

Pod IP 是集群内可路由的。外部(其他 Pod、Service、Node)访问该 Pod 时,访问的是 Pod IP + 某个端口,而这个端口由 Pod 内某个容器监听。

plantuml 复制代码
@startuml
skinparam componentStyle rectangle
skinparam linetype ortho

title Kubernetes Pod 网络关系图

package "Node 1" {
  [Pod A\n(IP: 10.244.1.10)\nNamespace: dev] as podA #LightBlue
  package "Pod A 内部" {
    [Container: nginx\n:80] as nginxA
    [Container: sidecar\n访问 localhost:80] as sidecarA
  }
}

package "Node 2" {
  [Pod B\n(IP: 10.244.2.20)\nNamespace: prod] as podB #LightGreen
  package "Pod B 内部"  {
    [Container: app\n:8080] as appB
    [Container: logger\n访问 localhost:8080] as loggerB
  }
}

note right of podA
  所有容器共享同一个网络命名空间
  - 共享 IP: 10.244.1.10
  - 通过 localhost 通信
  - 端口不能冲突
end note

note right of podB
  同理:
  - 共享 IP: 10.244.2.20
  - localhost 通信
end note

' Pod 内部连接
nginxA -[hidden]-> sidecarA
sidecarA --> nginxA : "curl localhost:80\n直接访问"

appB -[hidden]-> loggerB
loggerB --> appB : "curl localhost:8080\n直接访问"

' Pod 之间跨节点/跨命名空间通信
podA --> podB : "curl 10.244.2.20:8080\n跨命名空间可达\n(默认无 NetworkPolicy 限制)"

' 说明网络平面
rectangle "Kubernetes 集群网络平面\n所有 Pod IP 全局路由可达" as netplane #FFF4E0
netplane .. podA
netplane .. podB

legend right
  <b>说明</b>
  - Pod 内部:容器共享网络栈,localhost 通信
  - Pod 之间:无论命名空间或节点,IP 直接可达
end legend

@enduml

3. pod的生命周期和状态

pod的生命周期可以分为如下4种,pod的生命周期是单向的,不会回到之前的状态。

  1. Pending
  2. Running
  3. Succeeded or Failed
  4. Unknown

graph TD A[创建 Pod<br>kubectl apply / Controller] --> B[Pending] B -->|镜像拉取中 / 调度中 / PVC绑定 / Init容器运行| C[Running] C -->|所有容器成功退出<br>exit 0| D[Succeeded] C -->|至少一个容器失败退出<br>exit ≠0 或 Crash| E[Failed] C -->|节点失联 / Kubelet无响应| F[Unknown] %% 探针和条件影响(非状态,但影响行为) C -->|readinessProbe 失败| G[Pod NotReady<br>不加入 Endpoints<br>不接收流量] C -->|livenessProbe 失败| H[重启容器<br>→ CrashLoopBackOff] C -->|startupProbe 失败| I[重启容器] %% Init 容器路径 B -->|Init 容器执行中| J[Init:0/2, Init:Error 等] J -->|全部成功| C J -->|失败| E %% 从 Unknown 可恢复 F -->|节点恢复| C F -->|节点永久丢失| K[需手动/控制器重建] %% 样式美化 classDef pending fill:#fff3cd,stroke:#ffeaa7; classDef running fill:#d4edda,stroke:#c3e6cb; classDef success fill:#d1e7dd,stroke:#badbcc; classDef failed fill:#f8d7da,stroke:#f5c6cb; classDef unknown fill:#e2e3e5,stroke:#d6d8db; classDef note fill:#f0f0f0,stroke:#ccc,stroke-dasharray: 5 5; class B pending class C running class D success class E failed class F unknown class G,H,I,J,K note

而pod又可以分为如下5种状态:

取值 描述
Pending Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
Running Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。注意Runing状态≠pod健康
Succeeded Pod 中的所有容器都已成功结束,并且不会再重启。
Failed Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止,且未被设置为自动重启。
Unknown 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

那么如何知道pod究竟可不可用呢,那就得看pod的就绪状态,pod.status.conditions[? type=="Ready"],如果type=Ready就代表pod可用,能接受流量,否则就代表不可用。

4. 探针

前文我们提到了pod分为不同的生命周期,以及对应的pod相关状态,那么问题来了,我怎么知道pod就行有没有运行成功呢,有没有ready呢,这就得靠我们的探针大哥帮忙。

探针的目的就是为了检测容器相关的状态,一共有如下四种探针检查机制:

  1. exec:执行命令,检查容器是否ok
  2. grpc:使用grpc检查容器是否正常
  3. httpGet:http请求检查容器是否正常
  4. tcpSocket:检查容器tcp端口是否打开,打开则正常

针对于探针的检查结果,无非就三种结果:成功、失败、未知(也就是探测失败,不采取任何行动)。当然,如果你不设置探针,那结果肯定就都是默认成功。

有了探针的检查结果,那么应该做什么呢?k8s有如下3种探针类型:

  1. livenessProbe检查容器是否"活着"(进程是否卡死/假死),失败则根据重启策略重启容器。
  2. readinessProbe检查容器是否"准备好服务"。如果失败,则容器容器就不能对外提供服务(其实就是自动将该 Pod 从对应的 Endpoints 对象中移除,从而不再将流量路由到这个 Pod,容器的状态为NotReady,对应的pod的状态Ready=False)。
  3. startupProbe指示容器中的应用是否已经启动。如果提供了该类型探针,在成功前,会屏蔽其他类型的探针。当然,如果失败了,则会根据对应的策略进行重启。

Pod 从创建到"真正可用",必须等待所有容器的 readinessProbe 成功 ------ 这是探针对 Pod "可用性"的核心控制点。

以下是千问老师总结的使用要点:

‍♂️ Readiness = 能不能干活 → 不行就"靠边站",别重启!
Liveness = 还有没有气 → 不行就"抬走重来",必须重启!
Startup = 刚出生要呵护 → 启动期特殊保护,长大再考核!


graph TD A[Pod 创建] --> B[容器启动] B --> C{是否有 startupProbe?} C -- 有 --> D[执行 startupProbe 直到成功] C -- 无 --> E[开始 liveness/readinessProbe] D --> E E --> F[周期性探测] F --> G{liveness 失败?} G -- 是 --> H[重启容器 → Pod RestartCount++] F --> I{readiness 失败?} I -- 是 --> J[Pod Ready=False → 从 Endpoints 移除]

5. 创建pod

前面介绍了这么多,现在让我们使用命令来创建一个pod吧,大家可以在这个Killercoda Interactive Environments进行在线创建。

bash 复制代码
kubectl run nginxtest --image=nginx:latest --port=80

这样,我们便创建了一个nginx的pod:

6. 总结

Pod 是 Kubernetes 中最小的可部署、可调度的计算单元,一个 Pod 可以包含一个或多个紧密耦合的容器(共享网络、存储、生命周期)。pod的生命周期是不可逆的,而探针能够不断去对pod的状态进行检测,从而保证服务的可用性。我们有通过相关命令创建了一个pod,但是大家可以想一想,这个pod如果挂了,还能够重启吗?如果不能重启,那怎么去解决这个问题呢?让我们在下一章再进行介绍。