Pod概述
Pod是K8s系统中可以创建和管理的小单元,是资源对象模型总由用户创建或部署的最小资源对象模型,也是在K8s上运行容器化应用的资源对象,其他的资源对象都是用来支撑或者扩展Pod对象功能的,比如控制器对象是用来管控Pod对象的,Service或者Ingress资源是用来暴露Pod引用对象的,PersistentVolume资源对象是用来为Pod提供存储的,K8s不会直接处理容器,而是通过Pod来进行的,Pod则是由一个或多个容器组成的。
Pod是K8s中最重要的概念,每一个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于K8s平台的一部分。除了Pause容器,每个Pod中还包含一个或多个紧密相关的用户业务容器。
Pod 的特性
- 资源共享
- 一个Pod中的多个容器可以共享存储和网络,可以看作一个逻辑主机(服务器),共享如namespace、cgroups或其他的隔离资源
- 多个容器共享一个network namespace,因此在一个Pod中的多个容器共享Pod的Ip和端口,所以一个Pod中的容器可以通过localhost进行通信,只需注意多个容器之间不要有端口冲突即可。不同的Pod有不同的Ip,不同Pod内的多个容器之间进行通信,不可以使用IPC(如果没有特殊指定的话)进行通信,通常使用Pod的Ip进行通信。
- 一个Pod内的容器可以共享存储卷,这个存储卷会被定义为Pod的一部分,并且可以挂载到该Pod里的所有容器的文件系统上。
- 生命周期短暂
- Pod属于生命周期比较短暂的组件,比如,当Pod所在的节点发生故障,那么该节点上的Pod就会被调度到其他节点,值得注意的是,重新调度运行的Pod是一个全新的Pod,与之前的Pod没有任何关系。
- 平坦的网络
- K8s集群中的所有Pod都在同一个共享网络地址空间中,也就是说每个Pod都可以通过其他Pod的地址来访问。
Pod 存在的意义
- 运行多个应用程序
- docker一个容器对应一个进程,对应一个应用程序,而Pod可以在一个Pod中运行多个容器,也就可以运行多个应用程序。
- 运行亲密性应用
- 在两个应用之间有耦合或者两个应用间会进行频繁的调用,Pod使两个应用程序的交互变得简单,通过localhost就可以进行通信
Pod 的实现机制
-
共享网络
- 在一个Pod中,所有的容器网络都是共享的。我们知道,在docker中,所有的容器都是相互隔离的,而Pod实现网络共享的原理则是上面提到的Pause,在创建一个Pod的过程中,首先会创建一个Pause的容器,然后再去创建指定的业务容器并加入到Pasue容器中,而这个Pause就负责管理这个Pod以及其他的业务容器的IP、Mac、端口,以达到网络共享的目的。
-
共享存储
-
在一个Pod的运行中,可能会出现各种情况导致容器无法继续运行需要重启,在docker中我们知道一个容器重启之后如果没有指定数据卷,那么重启启动的容器就是根据镜像启动的一个新的容器,跟之前的容器毫无关系。在Pod中也是如此,如果Pod出现意外需要重启,或者运行Pod的K8s节点宕机,需要调度到另一个节点上继续运行,那么就会运行一个新的Pod,但是如果我们运行的Pod是一个有状态的应用,那么数据的丢失是我们不能接受的。于是我们可以在创建Pod的时候指定持久化存储的路径,也就是存储卷Volumn,跟docker类似。这样在Pod在重启之后就能够恢复到宕机之前的状态,保留下了它的日志数据和业务数据。
-
Yaml绑定存储卷示例:
-
apiVersion: apps/v1 kind: Pod metadata: name: my-testPod spec: containers: - name: write image: centos command: ["bash","-c","for i in (1..100);do echo $i >> /data/hello;sleep 1;done"] volumeMounts: - name: data moutPath: /data - name: read image: centos command: ["bash","-c","tail -f /data/hello"] volumeMounts: - name: data moutPath: /data volumes: - name: data emptyDir: {}
-
Pod镜像拉取策略
apiVersion: apps/v1
kind: Pod
metadata:
name: my-imagePod
spec:
containers:
- name: nginx
image: nginx:1.18
imagePullPolicy: Always # 镜像拉取策略
- IfNotPresent:默认值,镜像在宿主机上不存在时才拉取
- Always:每次创建Pod都重新拉取一次
- Never:Pod永远不会主动拉去这个镜像
Pod的资源请求和限制
每个 Pod 都可以对其能使用的服务器上的资源设置限额,K8s中可以设置限额的资源有 Cpu 与 Memory 两种,其中 Cpu 的资源单位为 Cpu 数量,是一个绝对值而非相对值。Memory 配额也是一个绝对值,它的单位是内存字节数。K8s里,一个计算资源进行配额限定需要设定以下两个参数:
- Requests :该资源最 小申请数量,系统必须满足要求。
- Limits:该资源最大允许使用的量,不能突破,当容器试图使用超过这个量的资源时,可能会被 K8s Kill 并重启。
apiVersion: apps/v1
kind: Pod
metadata:
name: my-resourcePod
spec:
containers:
- name: db
image: mysql:5.27
env:
- name: MYSQL_ROOT_PASSWORD
value: root
resource:
requests: # 资源请求
memery: "64Mi"
cpu: "250m"
limits: # 资源限制
memery: "128Mi"
cpu: "500m"
上述代码表明 MySQL 容器的最低运行标准为 0.25 个 Cpu 以及 64MiB 内存,在运行过程中容器所能使用的资源配额为 0.5 个 Cpu 以及 128MiB 内存。
Pod 的生命周期和重启策略
Pod的状态
状态值 | 说明 |
---|---|
Pending | Api Server已经创建了该Pod,但Pod中的一个或多个容器的镜像还没有创建,包括镜像的下载过程。 |
Running | Pod中的所有容器均已创建,且至少一个容器处于运行、正在启动或正在重启状态 |
Completed | Pod中的所有容器均已成功执行并退出,且不会再重启 |
Failed | Pod中的所有容器均已退出,但至少一个容器退出失败 |
Unknown | 由于某种原因无法获取Pod状态,例如网络通信不稳定 |
Pod重启策略
Pod的重启状态由spec.restartPolicy定义,有以下三种策略
重启策略 | 说明 |
---|---|
Always | 默认值,当容器失效时,由Kubectl自动重启该容器 |
OnFailed | 当容器终止运行且退出码不为0时,由Kubectl自动重启该容器 |
Never | 无论容器状态如何,Kubectl都不会重启该容器 |
常见的状态转换
Pod包含的容器数 | Pod当前的状态 | 发生事件 | Pod不同重启策略的结果状态 | ||
---|---|---|---|---|---|
Always | OnFailed | Never | |||
1 | Running | 容器成功退出 | Running | Succeeded | Succeeded |
1 | Running | 容器失败退出 | Running | Running | Failed |
1+ 至少两个 | Running | 其中一个容器失败退出 | Running | Running | Running |
1+ 至少两个 | Running | 容器被OOM kill退出 | Running | Running | Failed |
Pod的健康检查
Pod的健康检查是用于判断该容器是否能够对外正常提供服务的一种检查机制。根据服务类型的不同,K8s提供了两种不同类型的探针,分别是LivenessProbe
(存活探测)和 ReadinessProbe
(就绪探测)。
LivenessProbe
(存活探测)- 存活探测将通过http、shell命令或者tcp等方式去检测容器中的应用是否健康,然后将检查结果返回给kubelet,如果检查容器中应用为不健康状态提交给kubelet后,kubelet将根据Pod配置清单中定义的重启策略
restartPolicy
来对Pod进行重启。
- 存活探测将通过http、shell命令或者tcp等方式去检测容器中的应用是否健康,然后将检查结果返回给kubelet,如果检查容器中应用为不健康状态提交给kubelet后,kubelet将根据Pod配置清单中定义的重启策略
ReadinessProbe
(就绪探测)- 就绪探测也是通过http、shell命令或者tcp等方式去检测容器中的应用是否健康或则是否能够正常对外提供服务,如果能够正常对外提供服务,则认为该容器为(Ready状态),达到(Ready状态)的Pod才可以接收请求。
- 对于被Service所管理的Pod,Service与被管理Pod的关联关系也将基于Pod是否Ready进行设置,Pod对象启动后,容器应用通常需要一段时间才能完成其初始化的过程,例如加载配置或数据,甚至有些程序需要运行某类的预热过程,若在此阶段完成之前就接收客户端的请求,那么客户端返回时间肯定非常慢,严重影响了体验,所以因为避免Pod对象启动后立即让其处理客户端请求,而是等待容器初始化工作执行完成并转为Ready状态后再接收客户端请求。
- 如果容器或则Pod状态为(NoReady)状态,Kubernetes则会把该Pod从Service的后端endpoints Pod中去剔除。
探针的实现方式
- ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
以上每种检查动作都可能有以下三种返回状态
- Success:表示通过了健康检查
- Failure:表示没有通过健康检查
- Unknown:表示检查动作失败
创建一个Pod——>运行Nginx容器——>首先启动nginx——>然后沉睡60秒后——〉删除nginx.pid 通过livenessProbe存活探测的exec命令判断nginx.pid文件是否存在,如果探测返回结果非0,则按照重启策略进行重启。 预期是容器真正(Ready)状态60s后,删除nginx.pid,exec命令探测生效,按照重启策略进行重启
apiVersion: v1
kind: Pod
metadata:
name: ngx-health
spec:
containers:
- name: ngx-liveness
image: nginx:latest
command:
- /bin/sh
- -c
- /usr/sbin/nginx; sleep 60; rm -rf /run/nginx.pid
livenessProbe:
exec:
command: [ "/bin/sh", "-c", "test", "-e", "/run/nginx.pid" ]
restartPolicy: Always