Pod,是 Kubernetes 项目中最小的 API 对象,更加专业的说,Pod,是 Kubernetes 项目的原子调度单位。
Pod 是 Kubernetes 里的原子调度单位。这就意味着,Kubernetes 项目的调度器,是统一按照 Pod 而非容器的资源需求进行计算的。
例子:
所以,像 imklog、imuxsock 和 main 函数主进程这样的三个容器,正是一个典型的由三个容器组成的 Pod。这样 Kubernetes 项目在调度时,自然就会去选择可用内存等于 3 GB 的 node-1 节点进行 绑定,而根本不会考虑 node-2。
但并不是所有有“关系”的容器都属于同一个 Pod。比如,PHP 应用容器和 MySQL 虽然会发生访问关系,但并没有必要、也不应该部署在同一台机器上,它们更适合做成两个 Pod。
Pod 在 Kubernetes 项目里还有更重要的意义,那就是:容器设计模式。
为了理解这一层含义,我就必须先给你介绍一下Pod 的实现原理。
首先,关于 Pod 最重要的一个事实是:它只是一个逻辑概念。
问题:Pod 是怎么被“创建”出来的呢?
Kubernetes 真正处理的,还是宿主机操作系统上 Linux 容器的 Namespace 和 Cgroups,而并不存在一个所谓的 Pod 的边界或者隔离环境。
也就是说 Pod,其实是一组共享了某些资源的容器。更具体的说 Pod 里的所有容器,共享的是同一个 Network Namespace,并且可以声明共享同一个 Volume。
那么你会认为假如 一个有A和B两个容器的Pod,不就等同于一个容器共享另一个容器的网络和Volume吗?通过 docker run --net=B --volumes-from=B --name=A image-A ...
这样的问题,容器B必须比容器A先启动,这样Pod里面多个容器就不是对等关系,而是拓扑关系了。
那么在 Kubernetes 项目里面,Pod 的实现需要使用一个中间容器,这个容器叫做 infra 容器,这个 Pod 中,Infra 容器永远都是第一个被创建的容器,而其他用户定义的容器,则通过 Join Network Namespace 的方式,与 Infra 容器关联在一起。
Infra 容器一定要占用极少的资源,所以它使用的是一个非常特殊的镜像,叫 作:k8s.gcr.io/pause。
对于 Pod 里的容器 A 和容器 B 来说:
- 它们可以直接使用 localhost 进行通信;
- 它们看到的网络设备跟 Infra 容器看到的完全一样;
- 一个 Pod 只有一个 IP 地址,也就是这个 Pod 的 Network Namespace 对应的 IP 地址;
- 当然,其他的所有网络资源,都是一个 Pod 一份,并且被该 Pod 中的所有容器共享;
- Pod 的生命周期只跟 Infra 容器一致,而与容器 A 和 B 无关。
而对于同一个 Pod 里面的所有用户容器来说,它们的进出流量,也可以认为都是通过 Infra 容器完 成的。这一点很重要,因为将来如果你要为 Kubernetes 开发一个网络插件时应该重点考虑的是 如何配置这个 Pod 的 Network Namespace,而不是每一个用户容器如何使用你的网络配置,这是 没有意义的。
有了这个设计之后,共享 Volume 就简单多了:Kubernetes 项目只要把所有 Volume 的定义都设计在 Pod 层级即可。
这样,一个 Volume 对应的宿主机目录对于 Pod 来说就只有一个,Pod 里的容器只要声明挂载这个 Volume,就一定可以共享这个 Volume 对应的宿主机目录。
栗子:
apiVersion: v1
kind: Pod
metadata:
name: "two-containers"
namespace: default
spec:
restartPolicy: Never
volumes:
- name: shared-data
hostPath:
path