Kubernetes3 为什么需要Pod

为什么需要Pod

  1. 在工业实际部署中,经常需要多个进程部署在同一个节点上。类似于Linux操作系统中的进程组的概念(pstree -g 命令查看进程组),他们之间有着”超亲密关系”,例如相互之间会发生直接的文件交换、使用localhost或者Socket文件进行本地通信、共享某些Linux Namespace等。
  2. 容器的”单进程模型”,PID=1的进程往往是应用本身,无法像正常操作系统中的init进程那样拥有进程管理的功能。
  3. 存在”超亲密关系”的进程,需要按照严格的拓扑顺序启动。也就是需要对容器成组进行调度(gang scheduling)。
    基于上述原因,Kubernetes提供了Pod这个逻辑概念,将需要在同一节点上,可能共享Namespace以及其他本地资源的容器进行成组调度。

Pod的实现机制

Pod是逻辑概念,其实是一组共享了某些资源(Network Namespace)的容器组。在没有成组调度时,如要实现容器A和容器B共享网络和Volume,可以通过如下命令实现:

1
$ docker run --net=B --volumes-from=B --name=A image-A ...

但容器B就必须先于容器A启动,改变了容器A和容器B的对等关系。

因此,在Kubernetes项目中,Pod的是基于一个中间容器——Infra容器来实现的。

1
k8s.gcr.io/pause这个镜像,是用汇编写的永远暂停的很小的镜像。用户容器通过加入Infra容器的Network Namespace实现资源的本地共享。

在Pod中,对于AB两个容器:

  • 可以直接通过localhost进行网络通信
  • 看到的网络设备跟Infra容器看到的完全一样,网络资源被Pod中的所有容器共享
  • 一个Pod对应一个IP地址
  • Pod的生命周期只和Infra容器有关,与AB容器无关。
  • Volume只需要在Pod中挂载一次,Pod内的所有容器即可共享。

容器设计模式

Kubernetes 希望当用户想在同一个容器中跑多个不相关的应用时,优先考虑使用Pod模式,看它们是否可以被描述为一个Pod中的多个容器。

典型的例子:

  1. war包和Web服务器

在这种模型下,我们可以将war包和web服务器分别制作成两个容器镜像(包含war包的镜像可以做的非常小和简单,方便应用更新和部署),并且共享同一个Volume,包含war包的容器先于web服务器容器启动。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: v1
kind: Pod
metadata:
name: javaweb-2
spec:
initContainers:
- image: app:v2
name: war
command: ["cp", "/app.war", "/app"]
volumeMounts:
- mountPath: /app
name: app-volume
containers:
- image: tomcat:7.0
name: tomcat
command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
volumeMounts:
- mountPath: /root/apache-tomcat-7.0/webapps
name: app-volume
ports:
- containerPort: 8080
hostPort: 8001
volumes:
- name: app-volume
emptyDir: {}

所有spec.initContainers定义的容器,都会比spec.containers 定义的用户容器先启动。并且,spec.initContainers 容器会按顺序逐一启动,而直到它们都启动并且退出了,用户容器才会启动。

  1. 日志收集

应用进程容器不断的输出日志到特定的Volume路径,日志收集进程容器共享日志Volume进行收集。

其实,上述Pod组合模式,就是容器设计模式中的Sidecar模式,更多细节,可参见之前的文章:Pattern-Service-Mesh