关于 Kubernetes 系列其他文章的传送门
-
《 深度学习 Pod 》 您当前所在位置

一、什么是 Pod ?¶
同一个 Pod 中的容器共享 6 个名称空间中的 3 个:
- IPC(系统级的进程间通信、消息队列)
- UTS(主机名,域名)
- Network(网络设备、网络协议栈、端口)
思考:为什么设计 Pod?¶
问题:一般情况下,一个 Pod 中是不建议运行多个容器,那为什么要设计 Pod 这个概念,还让其内部可以运行多个容器呢?
有些时候,一个单一进程可能无法完成我们期望的额外任务,例如:如果想在一个 Nginx 中使用 ELK 收集日志,就需要在 Nginx 主机中部署 Filebeat,但是一个容器中原则上只能运行一个进程,这时就可以在同一个 Pod 中另外启动一个容器来运行 Filebeat,使其能够紧密的辅助主容器完成任务。
所以在 Pod 中,通常只能有一个主容器,其他的容器是为了辅助主容器的任务而设定的,这些辅助容器也被称为 side car(边车)。
并不是让你在 Pod 中运行一整套 “nmp” 的。
二、学习 Pod 前必须了解的 k8s 网络¶
k8s 集群中的网络类型¶
- Node Network:节点真正与外部网络通信的接口;
- Service Network:这个网络所拥有的 IP 地址仅会出现在 Iptables/IPVS 规则当中,不会配置在任何一个网络接口上,也没有办法直接去 ping 通,也不可能有一个协议栈来响应 ping 请求,它仅仅出现在规则当中,是用来路由和调度发给 Service IP 地址的请求流量的;
- Pod Network:属于 k8s 的内部网络,每一个 Pod 都处于这个网络当中,Pod 的 IP 地址也都是这个网络当中被动态分配的的一个 IP 地址。因此各 Pod 彼此之间无论跑在哪个节点上,都是可以直接互相通信的。
Pod 是动态的,随时可能被 Pod 控制器所重建,IP 地址就会发生变化,如果这时 Pod 之间是直接使用 IP 地址通信反而不是一种理想的状态,而应该借助于 Service 的地址来通信。因此在 k8s 上跑的应用程序有一个特点,为了让客户端能够稳定的访问 Pod,必须在 Pod 前端加一个抽象层,也就是 Service。
将 Pod 网络对外开放¶
有三种方法可以使 Pod 能被集群外的客户端访问到:
- hostNetwork:让 Pod 直接共享它所在主机的网络名称空间,因此 Pod 的地址和端口也就是主机的地址和端口。直接访问 Pod 所在物理节点的
IP:Port即可直接与 Pod 进行通信。 - NodePort:在集群内的每一个物理节点上打开一个端口。访问物理节点的端口时,会被映射到 Service 上,再由 Service 映射到 Pod 上;
- hostPort(DNAT):使容器可以使用其所在的物理节点的端口,会被映射到 Pod 上。和 NodePort 不同的是,访问时只能使用 Pod 所在的物理节点的地址和端口;
三、Label 标签¶
为什么要有标签 ?¶
Pod 控制器对应到 Pod,既不是通过 IP 地址,也不是通过名称,因为当 Pod 重建后,这两个信息都会发生变化。所以在 k8s 中,所有的资源都可以被附加一个标签(Label),而 Pod 控制器就是通过标签选择器去找到 Pod。
标签其实就是“键值”类型的数据:
- 一个对象可拥有不止一个标签,而同一个标签也可被添加到多个资源之上;
- 实践中,可以为资源附加多个不同维度的标签以实现灵活的资源分组管理功能,例如版本标签、环境标签、分层标签等;
- 标签中的键名称通常由键前缀和键名组成,其中键前缀可选,其格式形如:
KEY_PREFIX/KEY_NAME;
标签的增删改查¶
查¶
使用 --show-labels 可以显示标签:
1 | kubectl get pods --show-label |
增¶
标签属于元数据,所以在 metadata 中就可以自定义标签:
1 | ~]# vim /root/pod-demo.yaml |
查询刚刚创建的 Pod 标签:
1 | kubectl get pods --show-labels |
也可以使用 kubectl label... 来直接为资源新增一个标签。
例如:为 pod-demo 添加一个 color 值为 red 的标签;
kubectl label pods pod-demo -n default color=red
改¶
替换已存在的标签。
kubectl label pods pod-demo -n default color=black --overwrite- 如果资源已经有一个同名的标签,使用
--overwrite参数才能替换原有标签;
- 如果资源已经有一个同名的标签,使用
删¶
删除一个标签的方法。
kubectl label pods pod-demo -n default color-color-代表删除此标签
标签选择器¶
通过 -l 参数,按照特定的规则过滤资源的标签,例如:
kubectl get pods --show-labels -l app=myapp:只显示包含app标签且值等于myapp的资源;kubectl get pods --show-labels -l app!=myapp:只显示不包含app标签或app的值不等于myapp的资源;kubectl get pods --show-labels -l "app in (myapp,ngx-dep)":显示包含app标签,且值等于myapp或者ngx-dep的资源;kubectl get pods --show-labels -l "app":显示包含app标签,可以是任何值;kubectl get pods --show-labels -l '!app':显示不包含app标签,注意这时有特殊符号,需要使用强引用;
标签还有另一种显示的方法:
- 在不使用
--show-labels的情况下,用-L app明确要显示的标签,会以独立标签的形式显示app的值;
1 | kubectl get pods -l "app in (myapp,ngx-dep)" -L app |
资源注解(annotation)¶
注解和标签很像,也是“键值”类型的数据,不过它不能用于标签及挑选 k8s 对象,只是为用户提供一个自定义元数据的接口;
注解中的元数据不受字符数量的限制,它可大可小,可以为结构化或非结构化的形式,也支持使用在标签中禁止使用的其他字符;
注解在 k8s 中很重要,后期很多管理工具是通过注解来管理资源;
注解的使用方法¶
注解也属于元数据,所以同样可以在 metadata 中自定义:
1 | ~]# vim /root/pod-demo.yaml |
查看刚刚创建的注解:
1 | kubectl describe pods pod-demo -n default |grep Annotations -C 3 |
可以发现,在注解中,自动帮我们保存了在执行 kubectl apply 时指定的配置文件中的所有配置信息,这样下次使用 apply 重新构建时,会自动对比两次的不同,新加的部分会以补丁的形式补充上去。这就是为什么使用 kubectl apply 可以重复构建资源的原因,而使用 kubectl create 则不行
四、Pod 的生命周期¶

流程:
- 首先启动一个 Infra 容器(又叫 Pause 容器),用来和 Pod 中的其他容器共享 linux 命名空间,并开启 init 进程。(上图中忽略了这一步)
- 然后启动 Init 容器,它是一种专用的容器,在应用程序容器启动之前运行,用来对 Pod 进行一些初始化操作,并包括一些应用镜像中不存在的实用工具和安装脚本;
- 之后,应用程序容器和 post-start hook 同时启动;
- 开始启动 liveness 和 readiness 探针;
- 手动停止 Pod 时,pre-stop hook 执行,优雅删除期限过期后(默认是 30 秒),应用程序容器停止。实际的 Pod 终止过程要更复杂,具体参考 Pod 的终止。
livenessProbe 健康状态检测¶
livenessProbe 的作用是检测容器健康状态,如果不健康,会重启容器。
常用的有 3 种检测方式:
exec:执行指定的命令来做健康状态检测,要执行的命令一定是容器内包含的命令;httpGet:请求一个 URL;tcpSocket:请求一个套接字;
其他参数:
failureThreshold:检测健康状态变为失败时,需要确认几次,默认为 3;successTHreshold:检测健康状态变为成功时,需要确认几次,默认且只能为 1;periodSeconds:检测周期,默认 10s;initialDelaySeconds:当容器启动后延迟多久后才开始检查;默认容器一启动就检查;timeoutSeconds:每次检查时如果对方无响应,最多等待多久后自动断开,以减少连接数;默认 1s;
1. 通过命令来检测的示例¶
示例配置文件:
1 | ~]# vim liveness-exec.yaml |
启动 Pod:
1 | kubectl apply -f /root/liveness-exec.yaml |
之后在描述信息里能看到检测状态:
1 | ~]# kubectl describe pods liveness-exec |
2. 通过 http 请求来检测的示例¶
先使用 lifecycle 在容器启动后,创建一个页面文件 healthz,之后定义健康状态检查时,通过 URI 请求这个页面。
示例配置文件:
1 | ~]# vim liveness-http.yaml |
readinessProbe 就绪状态检测¶
readinessProbe 就绪检测的配置方式和健康状态检测的配置方式是相像的,但不同的是,就绪状态检测在检测到容器还未就绪时,是不会重启容器的。
- 当就绪检查成功了,Service 就会把 Pod 当做后端用了,这是 Service 非常依赖的评估标准;
- 如果检查不成功,就会把 Pod 从后端移走,无论 Pod 运行是否正常。
配置示例:
1 | ~]# vim readiness-exec.yaml |
五、Pod 对象的相位¶
无论是手动创建还是通过控制器创建 pod,pod 对象总是应该处于其生命进程中以下几个相位之一:
pending:apiserver 创建了 pod 资源对象并存入 etcd 中,但它尚未被调度完成或者仍处于下载镜像的过程中;running:pod 已经被调度至某节点,并且所有容器都已经被 kubelet 创建完成;succeeded:pod 中的所有容器都已经成功终止并且不会被重启;failed:所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态或已经被系统终止;unknown:apiserver 无法正常获取到 pod 对象的状态信息,通常是由于其无法于所在工作节点的 kubelet 通信所致;
Pod 对象的创建过程:

容器的重启策略¶
容器程序发生崩溃或者容器申请超出限制的资源等原因都会导致 Pod 对象的终止,此时是否应该重建该 Pod 对象取决于其重启策略
- Always:但凡 Pod 对象终止就将其重启,此为默认设定;
- onfailure:仅在容器出现错误时将其重启;
- Never:从不重启;
Pod 的终止过程:

六、Pod 资源限制需求及资源限制¶
容器的计算资源配额:
- 相比较来说,CPU 属于可压缩(compressible)资源,即资源额度可按需收缩,而内存(当前)则是不可压缩型资源,对其执行收缩操作可能会导致某种程度的问题。
- CPU 资源的计量方式:
- 在 k8s 系统上,1 个单位的 CPU 相当于虚拟机上的 1 颗 CPU(vcpu)或物理机上的一个超线程或逻辑 CPU,它支持分数计量方式,一个核心相当于 1000 个微(m)核心,因此 500m 相当于是 0.5 个核心;
- 内存资源的计量方式:
- 内存的计量方式与日常使用方式相同,默认单位是字节,也可以使用
E、P、T、G、M和K作为单位后缀;
- 内存的计量方式与日常使用方式相同,默认单位是字节,也可以使用
- CPU 资源的计量方式:
如果不满足下限,则拒绝启动容器,影响调度;
如果不满足上限,不会影响调度;
Pod 资源限制的示例¶
使用 CPU 密集型镜像,来测试对 CPU 的限制。
1 |
|
使用内存密集型镜像,此镜像会不停的申请内存而不释放,来测试对内存的限制。
1 | ~]# vim memleak-pod.yaml |
Pod 服务指令类别¶
根据 Pod 的 requests 和 limits 设定,kubernetes 在创建 Pod 时,会将 Pod 归类到 BestEffort、Burstable 和 Guaranteed 三个服务质量(Quality of Service,QoS)类别的其中一个:
- Guaranteed:当每个容器 cpu 和内存资源的 requests 和 limits 定义的值相等时,Pod 资源会自动归属于此类别,这类 pod 资源具有最高优先级;
- Burstable:Pod 内至少有一个容器设置了 cpu 或内存资源的 requests 属性,但不满足 Guaranteed 类别要求的 pod,将自动归属此类别,它们具有中等优先级;
- BestEffort:未为任何一个容器设置 requests 和 limits 属性的 pod 资源将自动归属于此类别,它们的优先级为最低级别;
使用以下命令可以查看容器当前被归为哪一类别:
1 | kubectl describe pod pod-demo | grep "QoS Class" |