K8s 中 Node、Pod、容器、镜像的关系

一图看懂(层级与共享)

Cluster
└─ Node(物理机/虚机)
   ├─ kubelet + 容器运行时(containerd / CRI-O)
   └─ Pod(调度最小单位,可有多个)
      ├─ [基础设施容器 pause:承载 Pod 的网络/IPC 命名空间]
      ├─ 共享网络栈(同一 Pod 内容器共享同一 IP、localhost)
      ├─ 共享 Volume(同一 Pod 内可挂载并共享)
      └─ 容器(一个或多个)
         └─ 来自“一个镜像”(registry/repo:tag 或 @sha256:digest)
  • 直白总结
    • Node 上运行很多 Pod
    • 一个 Pod 内可以有多个 容器
    • 每个 容器 只能来源于 一个镜像
    • 一个 镜像 可以被很多容器复用(跨 Pod/Node)

核心对比表

概念 作用 关键属性 生命周期管理 资源/隔离 常用命令
Node 工作节点,承载 Pod CPU/内存/磁盘/网络、标签/污点 集群与节点运维 节点级 cgroups/内核隔离 kubectl get nodes -o wide
Pod 调度与网络最小单位 IP、Volume、标签、注解 K8s 控制面(调度器、kubelet) Pod 内共享网络/IPC;与其他 Pod 隔离 kubectl get/describe pod
容器 (Container) 运行进程的封装 镜像、命令、env、探针、资源限额 kubelet 通过 CRI 调用运行时 cgroup/namespace 级资源隔离 kubectl logs/exec
镜像 (Image) 不可变运行时文件系统与元数据 repo:tag 或 @digest、多层 仓库存储与节点缓存 只读层 + 容器可写层 kubectl describe pod 中看镜像;节点用 crictl/nerdctl 查看缓存

基数与约束(Cardinality)

  • (1) Node ↔ (N) Pods(一个节点可运行很多 Pod;一个 Pod 任何时刻只在一个节点上)
  • (1) Pod ↔ (N) Containers(≥1 个业务容器,可含 initContainers、临时容器)
  • (1) Container ↔ (1) Image(容器只能由一个镜像创建)
  • (1) Image ↔ (0…N) Containers(同一镜像可被重复使用)
  • (1) Pod ↔ (1) IP(Pod 内所有容器共享该 IP 和端口空间)
  • Pod 内可挂载多个 Volume 并在容器间共享

调度与拉镜像流程(简化)

  1. 你提交 Pod/Deployment(API Server 接收)
  2. 调度器为 Pod 选定合适的 Node(看资源、亲和/污点等)
  3. 目标 Node 上的 kubelet
    • 解析容器的 image 引用(registry/repo:tag@digest
    • 按顺序尝试 imagePullSecrets 进行认证并拉镜像(节点有缓存则复用)
    • 为 Pod 创建网络命名空间(由 pause/沙箱容器持有)
    • 顺序运行 initContainers → 再启动业务容器
    • 等待 readinessProbe 就绪,将 Pod 加入 Service Endpoints
  4. 期间失败则见 ErrImagePull/ImagePullBackOff/CrashLoopBackOff 等事件

镜像要点(命名、拉取、缓存)

  • 名称结构:[registry/][namespace/]name[:tag]name@sha256:<digest>
    • 未写 registry 通常默认为 docker.io(内部实际为 index.docker.io/v1/
    • @digest 可确保版本不可变,避免 tag 漂移
  • 镜像是多层只读层的组合;容器运行时会叠加一个可写层
  • 节点会缓存已拉取的镜像层;不同镜像若共享层可复用,加速拉取
  • 多个 imagePullSecrets 可并存;kubelet会按顺序尝试,先成功先用,不存在“被覆盖”

常见误区澄清

  • “一个容器能否用多个镜像?”——不能。一个容器只能来自一个镜像
  • “Pod 就是容器吗?”——不等同。常见是 1 Pod 1 容器,但 Pod 可包含多个容器(如 sidecar)
  • “容器端口与 Pod IP 的关系?”——Pod 只有一个 IP,容器共享端口空间;containerPort 仅作元数据
  • “Node IP 就是 Pod IP 吗?”——不是。Pod IP 来自 CNI 网段;Node IP 是节点网卡地址
  • “拉镜像一定需要凭据吗?”——公共镜像可匿名拉取;私有仓库需 imagePullSecrets

典型示例

一个 Pod,两个业务容器 + 一个 init 容器

apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  imagePullSecrets:
    - name: reg-harbor
  initContainers:
    - name: init-db
      image: busybox:1.36
      command: ["sh", "-c", "until nc -zv db 5432; do sleep 1; done"]
  containers:
    - name: app
      image: registry.local/team/app:v2
      ports:
        - containerPort: 8080
      readinessProbe:
        httpGet: { path: /healthz, port: 8080 }
    - name: sidecar-proxy
      image: registry.local/mesh/proxy:1.0
      args: ["--upstream=localhost:8080"]
  volumes:
    - name: shared
      emptyDir: {}
  • 两个业务容器共享 Pod 的 IP、emptyDir 卷与环境
  • 每个容器各自来自一个镜像;Pod 内并不存在“一个容器用多个镜像”的情况

观察与排查常用命令

  • 查看层级与位置
    • kubectl get nodes -o wide
    • kubectl get pod -o wide
    • kubectl describe pod <name>(看调度、镜像拉取事件、探针)
  • 节点侧(需要登录节点)
    • crictl images / crictl ps(CRI 通用)
    • nerdctl images(containerd 友好)
  • 网络与服务
    • kubectl get endpoints <svc>
    • kubectl exec <pod> -- netstat -tnlp(检查端口)

何时用多容器(Sidecar)而不是合并到一个镜像

  • 适合 Sidecar:代理/日志收集/文件同步/服务网格注入,和主进程解耦、独立演进
  • 适合合并:强耦合的小工具仅在构建期生成产物(用 Docker 多阶段构建),保持运行时只有一个干净镜像
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐