1. 概念
Pod 是 Kubernetes 项目里定义的最小可调度单元,是 Kubernetes 对应用程序的抽象。
Pod 组成可以是一个或者多个容器,属于同一个 Pod 的容器会共享:
- 网络资源
- 相同的 IP
- 存储
- 应用到 Pod 的自定义配置
2. Pod 的模型
根据组成 Pod 的容器数量可以将 Pod 分为两种类型:
单容器模型:Pod是Kubernetes可识别的最小对象,Kubernetes管理调度Pod而不是直接管理容器,所以即使只有一个容器也需要封装到Pod里
多容器模型:在这个模型中,Pod可以容纳多个紧密关联的容器以共享Pod里的资源。这些容器作为单一的,凝聚在一起的服务单元工作。比如:在Pod中有一个应用程序容器和一个日志记录容器。日志记录容器的唯一工作是从应用程序容器中提取日志。将两个容器放置同一个Pod里可消除额外的通信时间,因为它们位于同一个"主机",因此所有内容都是本地的并且它们共享所有资源,就跟在同一台物理服务器上执行这些操作一样。
Pod 本身不具备调节功能,如果 Pod 所在的节点发生故障,Pod 是不能自动调度到其他节点,需要使用控制器来完成 pod 的调度问题。Deployment就是最基础的控制器。通常我们都是在定义的控制器的配置里通过PodTemplate定义要控制的Pod,让控制器和所管控的Pod一起被创建出来。
3. Pod 的生命周期
Pod的生命周期有5个阶段:
- Pending:pending 表示当 pod 中至少存在一个容器未创建的情况。
- Running:容器已经创建完成,并且Pod已经被调度到了一个Node上。此时Pod内的容器正在运行,或者正在启动或重新启动。
- Succeeded:Pod中的所有容器均已成功终止,并且不会重新启动。
- Faild:所有容器均已终止,至少有一个容器发生了故障。失败的容器以非零状态退出。
- Unknown:无法获得Pod的状态。
4. Pod 的 yaml 文件解析
Kubernetes 里所有的 API 对象都由四部分组成:
- apiVersion: 当前使用的 Kubernetes 的 API 版本
- kind:想创建的对象的种类
- metadata:元数据,用来唯一表示当前的对象,比如 name,namespace 等
- spec:Pod 的指定配置,例如镜像名称、容器名称、数据卷等
apiVersion,kind 和 metadata 是必填字段,适用于所有 Kubernetes 对象,而不仅仅是 pod。spec 里指定的内容(spec 也是必需字段)会因对象而异。
Pod 文件示例:
apiVersion: "api version"
kind: "Object to create"
metadata:
name: "Pod name"
labels:
app: "label value"
spec:
containers:
- name: "container name"
image: "image to use for container"
5. 示例:
5.1 单容器 Pod
apiVersion: v1 # kubernetes 的 API 版本
kind: Pod # 创建的对象为 Pod
metadata: # 元数据
name: first-pod # pod 的名称
labels:
app: myapp
spec: # 指定的配置信息
containers:
- name: my-first-pod #容器名
image: nginx # 指定的镜像
将 Pod 的清单文件部署到本地的 Kubernetes 集群中:
kubectl create -f pod-1.yaml
查看 Pod 的运行情况:
kubectl get pods
执行命令查看容器情况:
kubectl exec first-pod -- service nginx status
在Pod里执行service nginx status指令,类似docker exec命令。
删除创建的 Pod
kubectl delete pod first-pod
5.2 多容器的 Pod
一个拥有两个容器的Pod,这些容器相互协作作为一个实体工作。其中一个容器每10秒将当前日期写入一个文件,而另一个Nginx容器则为我们展示这些日志。
apiVersion: v1
kind: Pod
metadata:
name: multi-container-pod
spec:
volumes:
- name: shared-data-logs # 为 Pod 中创建一个共享的数据卷
emptyDir: {}
containers:
- name: container-writing-datas # 第一个容器的名称
image: alpine
command: ["/bin/sh"]
args: ["-c", "while true; do date >> /var/log/output.txt; sleep 10; done"] # 每10秒写入当前时间
volumeMounts:
- name: shared-data-logs
mountPath: /var/log
- name: container-serving-dates # 第二个容器的名字
image: nginx:1.7.9 # 镜像
ports:
- containerPort: 80 # 定义容器提供服务的端口
volumeMounts:
- name: shared-data-logs
mountPath: /usr/share/nginx/html
通过运行如下命令连接到Nginx容器里:
kubectl exec -it multi-container-pod -c container-serving-dates -- bash
在容器内运行curl'http://localhost:80/output.txt'
,它应该返回时间日志文件的内容给我们。
5.3 SideCar模式
可以在一个 Pod 中按照顺序启动一个或多个辅助容器,来完成一些独立于主进程(主容器)之外的工作,完成工作后这些辅助容器会依次退出,之后主容器才会启动,这种容器设计模式叫做 sidecar。
比如对于前端Web应用,如果把构建后的Js项目放到Nginx镜像的/usr/share/nginx/html目录下,Nginx和Js应用做成一个镜像运行容器,每次应用有更新或者Nginx要做升级、更新配置操作都需要重新做一个镜像,非常麻烦。
有了Pod之后,这样的问题就很容易解决了。我们可以把前端Web应用和Nginx分别做成镜像,然后把它们作为一个Pod里的两个容器"组合"在一起。这个Pod的配置文件如下所示:
apiVersion: v1
kind: Pod
metadata:
name: web-2
spec:
initContainers:
- image: kevinyan/front-app:v2
name: front
command: ["cp", "/www/application/*", "/app"]
volumeMounts:
- mountPath: /app
name: app-volume
containers:
- image: nginx:1.7.9
name: nginx
ports:
- containerPort: 80 # 定义容器提供服务的端口
volumeMounts:
- mountPath: /usr/share/nginx/html
name: app-volume
volumes:
- name: app-volume
emptyDir: {}
所有spec.initContainers定义的容器,都会比spec.containers定义的用户容器先启动。并且,Init容器会按顺序逐一启动,直到它们都启动并且退出了,用户容器才会启动。所以,这个Init类型的容器启动后,执行了一句"cp /www/application/* /app",把应用包拷贝到"/app"目录下,然后退出。这个"/app"目录,挂载了一个名叫app-volume 的Volume。接下来Nginx容器,同样声明了挂载app-volume到自己的"/usr/share/nginx/html"目录下。由于这个Volume 是被Pod里的容器共享的所以等Nginx容器启动时,它的目录下就一定会存在前端项目的文件。这个文件正是上面的Init容器启动时拷贝到Volume里面的。