文章目录
- Pod 基础认知
- 什么是 Pod
- Pod 的示例 yaml
- Pod 的形式
- Pod 的多容器协同
- Pod 的生命周期
- 容器的类型
- 应用容器
- 初始化容器
- 临时容器
- 静态 Pod
- 什么是静态 Pod
- 静态 Pod 位置
- Pod 探针机制
- 探针类型
- Probe 配置项
- 探针案例
Pod 基础认知
什么是 Pod
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/
-
Pod 是可以在 k8s 中创建和管理的、最小的可部署的计算单元
-
Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的 “逻辑主机”,其中包含一个或多个应用容器, 这些容器相对紧密地耦合在一起。 在非云环境中,在相同的物理机或虚拟机上运行的应用类似于在同一逻辑主机上运行的云应用
-
Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离方面, 即用来隔离容器的技术。 在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离
-
Pod 类似于共享名字空间并共享文件系统卷的一组容器
Pod 的示例 yaml
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
containers:
- name: pod-demo
image: nginx
启动测试一下:kubectl apply -f pod-demo.yaml
查看详细信息:kubectl get pod -owide
- 尝试在
k8s-02
节点通过docker rm -f
杀死这个容器
- 观察一下
pod
状态
-
可以看到对于
Pod
里面的容器进程,是具有自恢复能力的 -
如果我们是直接删除
Pod
,kubectl delete pod pod-demo
,可以看到Pod
就直接结束了,Pod
自身并不具备自恢复能力
总结如下:
Pod
对于容器来说,具有自恢复能力Pod
本身不具有自恢复能力Pod
在借助了【工作负载】资源加持后,使Pod
具有自恢复能力,不同的工作负载资源控制pod
的不同行为
Pod 的形式
- 单容器
“每个 Pod 一个容器” 模型是最常见的 k8s 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器
- 多容器协同
运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的 “边车”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。
比如:为共享卷中的文件提供 Web 服务器支持,以及一个单独的 “边车 (sidercar)” 容器负责从远端更新这些文件,在这个Pod
里面,Pod 天生地为其成员容器提供了两种共享资源:网络和存储。
- pause 容器
一个
pod
由一个pause
容器和真正的业务容器组成
pause
容器的作用:设置好整个Pod
里面所有容器的网络、名称空间等信息
我们可以通过查看进程关系看到这个Pause
容器:
在【k8s-03】节点执行systemctl status
也正是因为pause
容器存在的关系,Pod
里面的容器在自恢复的时候还能保持原有的 IP 地址
总结如下:
pause
容器的作用:设置好整个Pod
里面所有容器的网络、名称空间等信息pause
容器在kubectl describe
中是隐藏的pod
里面容器自愈后 IP 地址不变的原因,使因为pause
容器在
Pod 的多容器协同
场景:现在要访问一个 nginx 的页面,需要不断展示当前时间
- 先准备一个 yaml 文件,这个
Pod
就是标准的nginx容器,访问的页面也是标准的页面
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
containers:
- name: pod-demo
image: nginx
- 我现在需要将这个页面挂载出来,如何进行挂载声明,可以通过
kubectl explain
去看
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
containers:
- name: pod-demo
image: nginx
volumeMounts:
- name: test
mountPath: /usr/share/nginx/html
- 然后我需要另一个容器,一个边车,让它不断地向一个文件写当前最新的时间
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
containers:
- name: pod-demo
image: nginx
volumeMounts:
- name: test
mountPath: /usr/share/nginx/html
- name: sidecar-demo
image: nginx ### 我还是以nginx镜像为例
command: ["/bin/sh","-c","while true;do sleep 1; date > /share/index.html;done;"]
##我在通过同样的方式将/share声明挂载
volumeMounts:
- name: test
mountPath: /share
- 2个容器的挂载声明在外部在进行一个联合
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
containers:
- name: pod-demo
image: nginx
volumeMounts:
- name: test
mountPath: /usr/share/nginx/html
- name: sidecar-demo
image: nginx ### 我还是以nginx镜像为例
command: ["/bin/sh","-c","while true;do sleep 1; date > /share/index.html;done;"]
##我在通过同样的方式将/share声明挂载
volumeMounts:
- name: test
mountPath: /share
volumes:
- name: test
emptyDir: {} ##外部创建一个位置
- 然后启动一下试试:
kubectl apply -f pod-demo.yaml
- 访问测试一下:
while true;do curl 192.168.0.137;sleep 1;done
Pod 的生命周期
容器的类型
从kubectl explain pod.spec
可以看到,关于containers
关键词的三个类型
- 初始化容器(
initContainers
) - 应用容器(
containers
) - 临时容器(
ephemeralContainers
)
Pod
启动会依次执行完所有初始化容器后,再启动所有的应用容器
应用容器
对于多容器协同,每一个容器启动都必须能一直运行起来,一个启动失败就会尝试重启
POd
内的这个容器,Pod
只要是【Notready】,就不对外提供服务
- 现在有这么一组协同容器的
Pod
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
containers:
- name: pod-demo1
image: nginx
- name: pod-demo2
image: alpine
- 运行启动一下:
- 对于
alpine
这个容器来说,本身是没有容器启动命令的,所以这个Pod
一直会处于NotReady
状态 - 简单修改一下
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
containers:
- name: pod-demo1
image: nginx
- name: pod-demo2
image: alpine
command: ["/bin/sh","-c","sleep 3600"]
- 启动尝试一下:(因为现在两个应用容器都能一直运行,所以最终
Pod
状态正常,能够对外提供服务)
- 对于一个
Pod
的2个容器,我们可以通过下面的方法进入任意一个容器中
kubectl exec (POD | TYPE/NAME) [-c CONTAINER] [flags] -- COMMAND [args...] [options]
初始化容器
通过kubectl explain pod.spec.initContainers
可以看出,k8s 中的初始化容器写法是和containers
一样一样的
Pod 在启动【containers】前,必须先启动所有的初始化容器,并且初始化的容器必须有终结的时刻,不然就会一直阻塞着,【containers】的容器就无法启动
- 一个样本的
yaml
文件
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
initContainers:
- name: pod-demo1
image: nginx
containers:
- name: pod-demo2
image: nginx
- 尝试启动一下,并跟踪一下状态
- 如果有初始化容器,从状态来看,带有
Init
关键字样,等待着初始化 - 发现不论等多久,
Pod
状态一直处于异常状态,因为初始化容器没有终结,
- 如果有初始化容器,从状态来看,带有
- 修改一下
yaml
文件后
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
initContainers:
- name: pod-demo1
image: nginx
command: ["/bin/sh","-c","sleep 10"] ## 会覆盖nginx的启动命令,睡眠10s这个容器就结束了
containers:
- name: pod-demo2
image: nginx
初始化容器运行结束后,就不会阻塞下一步容器的运行了,如果有多个初始化容器,会依次执行所有初始化容器,只要有一个失败,则Pod
是不能启动的
临时容器
官方参考地址:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/ephemeral-containers/
什么是临时容器
临时容器与其他容器的不同之处在于,它们缺少对资源或执行的保证,并且永远不会自动重启, 因此不适用于构建应用程序。 临时容器使用与常规容器相同的 ContainerSpec
节来描述,但许多字段是不兼容和不允许的。
- 临时容器没有端口配置,因此像
ports
、livenessProbe
、readinessProbe
这样的字段是不允许的。 - Pod 资源分配是不可变的,因此
resources
配置是不允许的 - …
临时容器的使用场景
容器排错
如何使用
这个地方后续参考一下官方文档:https://kubernetes.io/zh-cn/docs/tasks/debug/debug-application/debug-running-pod/#ephemeral-container
注意事项
- 1.21版本的 k8s 有关临时容器需要额外开启特性
- 最新的版本应该是可以直接拿来用的,因为官方的特性状态
Kubernetes v1.25 [stable]
静态 Pod
官方地址:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/#static-pods
什么是静态 Pod
- 静态 Pod(Static Pod) 直接由特定节点上的
kubelet
守护进程管理, 不需要 API 服务器看到它们。 尽管大多数 Pod 都是通过控制面(例如,Deployment) 来管理的,对于静态 Pod 而言,kubelet
直接监控每个 Pod,并在其失效时重启之。 - 静态 Pod 通常绑定到某个节点上的 kubelet。 其主要用途是运行自托管的控制面。 在自托管场景中,使用
kubelet
来管理各个独立的控制面组件。 kubelet
自动尝试为每个静态 Pod 在 Kubernetes API 服务器上创建一个镜像 Pod。 这意味着在节点上运行的 Pod 在 API 服务器上是可见的,但不可以通过 API 服务器来控制。
静态 Pod 位置
放在/etc/kubernetes/manifests
下面的 Pod 文件,就是静态Pod
,机器启动,kubelet
就会自动启动这个目录下所有的Pod
尝试在这个目录下尝试一个Pod
##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: MYAPP
spec:
initContainers:
- name: pod-demo
image: nginx
看一下状态:不知道为啥没有生效
这个后面深究一下,暂时跳过
Pod 探针机制
这个之前的容器的探究有浅尝过
探针类型
每个容器提供三种探针(Probe
)
-
启动探针(
startupProbe
)kubelet
使用启动探针,来检测应用是否已经启动,如果启动就可以进行后续的探测,慢容器一定指定启动探针- 启动探针成功以后就不用了,剩下的探针会持续运行
-
存活探针(
livenessProbe
)-
kubelet
使用存活探针,来检测容器是否正常存活。(有些容器可能产生死锁【应用程序在运行,但是无法继续执行后面的步骤】)
-
如果存活探针检测失败,就会重启这个容器
-
有的人活着,它已经死了
-
-
就绪探针(
readinessProbe
)-
kubelet
使用就绪探针,来检测容器是否准备好了,当一个Pod
内的所有容器都准备好了,才能把这个
Pod
看作就绪了。用途就是:Service后端负载均衡多个Pod
,如果某个Pod
还没就绪,就会从service负载均衡里面剔除
-
官网地址:https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
Probe 配置项
Probe 有很多配置字段,可以使用这些字段精确地控制启动、存活和就绪检测的行为:
-
initialDelaySeconds
:容器启动后要等待多少秒后才启动启动、存活和就绪探针, 默认是 0 秒,最小值是 0。(指定多少秒以后才执行探测) -
periodSeconds
:执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。(每隔几秒来运行这个探测) -
timeoutSeconds
:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。(探测超时时间,到了超时时间探测没返回结果说明失败) -
successThreshold
:探针在失败后,被视为成功的最小连续成功数。默认值是 1。 存活和启动探测的这个值必须是 1。最小值是 1。(成功阈值,连续几次才算成功) -
failureThreshold
:探针连续失败了failureThreshold
次之后, Kubernetes 认为总体上检查已失败:容器状态未就绪、不健康、不活跃。 对于启动探针或存活探针而言,如果至少有failureThreshold
个探针已失败, Kubernetes 会将容器视为不健康并为这个特定的容器触发重启操作。 kubelet 会考虑该容器的terminationGracePeriodSeconds
设置。 对于失败的就绪探针,kubelet 继续运行检查失败的容器,并继续运行更多探针; 因为检查失败,kubelet 将 Pod 的Ready
状况设置为false
。(失败阈值,连续几次失败才算真失败) -
terminationGracePeriodSeconds
:为 kubelet 配置从为失败的容器触发终止操作到强制容器运行时停止该容器之前等待的宽限时长。 默认值是继承 Pod 级别的terminationGracePeriodSeconds
值(如果不设置则为 30 秒),最小值为 1
HTTP Probes 允许针对 httpGet
配置额外的字段:
host
:连接使用的主机名,默认是 Pod 的 IP。也可以在 HTTP 头中设置 “Host” 来代替。scheme
:用于设置连接主机的方式(HTTP 还是 HTTPS)。默认是 “HTTP”。path
:访问 HTTP 服务的路径。默认值为 “/”。httpHeaders
:请求中自定义的 HTTP 头。HTTP 头字段允许重复。port
:访问容器的端口号或者端口名。如果数字必须在 1~65535 之间。
探针案例
许多长时间运行的应用最终会进入损坏状态,除非重新启动,否则无法被恢复。 Kubernetes 提供了存活探针来发现并处理这种情况。
示例 yaml 文件
####exec-liveness.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox
command:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5 ### 容器启动后5秒开始探测
periodSeconds: 5 ### 5秒一次探测
启动并追踪一下状态
- 容器正常启动,5秒后开始探测
- 探测成功,容器继续运行
- 探测失败,容器重新启动
- …
有关探针的描述和具体用法可以再参考官方链接
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/#container-probes