pod.jpeg
字面含义是如图所示的豌豆,在 k8s 中用这个名字形象的表示若干个关系紧密的、共享一定资源的容器集合(1个或者多个)。

pod 在 k8s 中的示意图:
image.png

关于 pod 有如下理解:

  • pod 是 k8s 项目的原子调度单位,也就是说 k8s 的调度器是按照 pod 而不是容器的资源需求来进行调度的
  • pod 只是一个逻辑概念,并不存在所谓的 pod 的边界或者隔离环境(虽然在概念上我们可以认为存在)
  • k8s 引入 pod 的概念目的是:
    • 通过成“组”的概念能比较好的表达真实世界里的进程之间的亲密关系,并且在这种情况下资源调度也会成“组”调度
    • 容器设计模式,典型的比如 sidecar 模式(可以在一个 Pod 中,启动一个辅助容器,来完成一些独立于主进程(主容器)之外的工作)
  • pod 里的所有容器,共享同一个 Network Namespace,并且可以共享同一个 Volume
  • 在 k8s 中,pod 中会先创建一个 Infra 容器,而用户定义的其他的容器 Join 到 Infra 容器的 Network Namepace

image.png

  • pod 里的容器可直接使用 localhost 通信
  • 一个 pod 只有一个 IP 地址
  • pod 的生命周期只和 Infra 容器一致,与用户容器无关
  • 某种角度看,pod 实际是类似传统基础设施里“虚拟机”的角色;而容器则是这个虚拟机里运行的用户程序(这种理解对于迁移基于传统虚拟机的应用非常重要,要摒弃同一个容器里放多个进程,仔细分析应用程序的关系,来决定是否/哪些容器放到哪些 pod 里)
  • pod 中的所有 Init Container 定义的容器会按顺序逐一启动,而直到它们都启动并且退出了,用户容器才会启动

pod 的资源配置(cpu & memory)

在 k8s 中,资源分为两类:

  • 可压缩资源(compressible resources):当可压缩资源不足时,Pod 只会“饥饿”,但不会退出。比如 cpu
  • 不可压缩资源(incompressible resources):当不可压缩资源不足时,Pod 会被迫退出。比如 memory,当不足时就会因为 OOM(Out-Of-Memory)被内核杀掉

pod 是 k8s 的最小的原子调度单元,其中包含的一个或者多个 container 可以分别设置 resource,比如:

  1. resources:
  2. requests:
  3. memory: "64Mi"
  4. cpu: "250m"
  5. limits:
  6. memory: "128Mi"
  7. cpu: "500m"

pod 整体的资源配置,就由这些 Container 的配置值累加得到。k8s 在调度时根据这个累加值中的 request 部分决定,在最终执行时由 kubelet 根据 limit 值设置 cgroup。
几个注意小项:

  • cpu 建议使用单位 m,比如:500m 表示半个 cpu 的能力,不建议写成 0.5,因为 k8s 内部通用就是这种整数表达方式。
  • memory 的单位,建议带 i,因为带 i 的是表示基于 1024 计算的,不带 i 是基于 1000 计算的,比如:1Mi=10241024;1M=10001000

关于资源 QoS

  • Guaranteed: 当 pod 里的每个 container 都同时设置了资源的 request 和 limit,并且 request 值等于 limit 值

    // 每个 container 都符合这种配置模式时
    resources:
    limits:
      memory: "500Mi"
      cpu: "700m"
    requests:
      memory: "500Mi"
      cpu: "700m"
    
  • Burstable:当 Pod 不满足 Guaranteed 的条件,但至少有一个 Container 设置了 requests 时

    resources:
    limits
      memory: "200Mi"
    requests:
      memory: "100Mi"
    
  • Besteffort:当 Pod 既没有设置 requests,也没有设置 limits 时

QoS 的目的,是当宿主机资源紧张的时候,kubelet 对 Pod 进行 Eviction(即资源回收)时需要用到的。
k8s 设置了 Eviction 的默认值,也可以通过 kubelet 进行显式的设置,比如:

kubelet --eviction-hard=imagefs.available<10%,memory.available<500Mi,nodefs.available<5%,nodefs.inodesFree<5% --eviction-soft=imagefs.available<30%,nodefs.available<10% --eviction-soft-grace-period=imagefs.available=2m,nodefs.available=2m --eviction-max-pod-grace-period=600

注意 Eviction 在 k8s 里其实分为 Soft 和 Hard 两种模式。

  • Soft Eviction:可以为 Eviction 设置一段“优雅时间”,表示达到阈值不立即驱逐,而是经过“优雅时间”后才驱逐
  • Hard Eviction:达到阈值了就开始驱逐

驱逐 pod 的顺序是:优先 Qos Besteffort,然后 Burstable 的,最后才是 Guaranteed。

当宿主机的 Eviction 阈值达到后,就会进入 MemoryPressure 或者 DiskPressure 状态,从而避免新的 Pod 被调度到这台宿主机上。

cpuset

通过设置 cpuset 可以把容器绑定到某个 CPU 的核上,而不是像 cpushare 那样共享 CPU 的计算能力,这样可以减少 cpu 上下文切换,提升性能。只需要同时满足下面两个条件,就能设置使用 cpuset:

  1. pod 的 QoS 是 Guaranteed 的
  2. Pod 的 CPU 资源的 requests 和 limits 设置为同一个相等的整数值
    resources:
    limits:
     memory: "500Mi"
     cpu: "2"
    requests:
     memory: "500Mi"
     cpu: "2"
    

    该 Pod 会被绑定在 2 个独占的 CPU 核上。由 kubelet 决定到底是哪两个 CPU 核。