Pod 基础认知

什么是 Pod

https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/

image-20230228211721796

  • 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

image-20230301163853234

  1. 尝试在k8s-02节点通过docker rm -f杀死这个容器

image-20230301164015072

  1. 观察一下pod状态

image-20230301164055683

  1. 可以看到对于Pod里面的容器进程,是具有自恢复能力的

  2. 如果我们是直接删除Pod,kubectl delete pod pod-demo,可以看到Pod就直接结束了,Pod自身并不具备自恢复能力

image-20230301164331041

总结如下:

  • Pod对于容器来说,具有自恢复能力
  • Pod本身不具有自恢复能力
  • Pod在借助了【工作负载】资源加持后,使Pod具有自恢复能力,不同的工作负载资源控制pod的不同行为

Pod 的形式

  1. 单容器

“每个 Pod 一个容器” 模型是最常见的 k8s 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器

  1. 多容器协同

运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的 “边车”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。

比如:为共享卷中的文件提供 Web 服务器支持,以及一个单独的 “边车 (sidercar)” 容器负责从远端更新这些文件,在这个Pod里面,Pod 天生地为其成员容器提供了两种共享资源:网络存储

image-20230301165823396

  1. pause 容器

一个pod由一个pause容器和真正的业务容器组成

pause 容器的作用:设置好整个Pod里面所有容器的网络、名称空间等信息

我们可以通过查看进程关系看到这个Pause容器:

image-20230301170419389

在【k8s-03】节点执行systemctl status

image-20230301170525433

也正是因为pause容器存在的关系,Pod里面的容器在自恢复的时候还能保持原有的 IP 地址

总结如下:

  1. pause容器的作用:设置好整个Pod里面所有容器的网络、名称空间等信息
  2. pause 容器在kubectl describe中是隐藏的
  3. 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

image-20230301171624936

  • 我现在需要将这个页面挂载出来,如何进行挂载声明,可以通过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

image-20230301172624282

  • 访问测试一下:while true;do curl 192.168.0.137;sleep 1;done

image-20230301172815916

Pod 的生命周期

容器的类型

kubectl explain pod.spec可以看到,关于containers关键词的三个类型

  • 初始化容器(initContainers
  • 应用容器(containers
  • 临时容器(ephemeralContainers

image-20230301212624992

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
  • 运行启动一下:

image-20230301214346262

image-20230301214448609

  • 对于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状态正常,能够对外提供服务)

image-20230301214841223

  • 对于一个Pod的2个容器,我们可以通过下面的方法进入任意一个容器中
kubectl exec (POD | TYPE/NAME) [-c CONTAINER] [flags] -- COMMAND [args...] [options]

image-20230301215311979

初始化容器

通过kubectl explain pod.spec.initContainers可以看出,k8s 中的初始化容器写法是和containers一样一样的

Pod 在启动【containers】前,必须先启动所有的初始化容器,并且初始化的容器必须有终结的时刻,不然就会一直阻塞着,【containers】的容器就无法启动

  1. 一个样本的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
  1. 尝试启动一下,并跟踪一下状态
    • 如果有初始化容器,从状态来看,带有Init关键字样,等待着初始化
    • 发现不论等多久,Pod状态一直处于异常状态,因为初始化容器没有终结,

image-20230301220222299

  1. 修改一下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

image-20230301222204810

初始化容器运行结束后,就不会阻塞下一步容器的运行了,如果有多个初始化容器,会依次执行所有初始化容器,只要有一个失败,则Pod是不能启动的

临时容器

官方参考地址:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/ephemeral-containers/

什么是临时容器

临时容器与其他容器的不同之处在于,它们缺少对资源或执行的保证,并且永远不会自动重启, 因此不适用于构建应用程序。 临时容器使用与常规容器相同的 ContainerSpec 节来描述,但许多字段是不兼容和不允许的。

  • 临时容器没有端口配置,因此像 portslivenessProbereadinessProbe 这样的字段是不允许的。
  • Pod 资源分配是不可变的,因此 resources 配置是不允许的

临时容器的使用场景

容器排错

如何使用

这个地方后续参考一下官方文档:https://kubernetes.io/zh-cn/docs/tasks/debug/debug-application/debug-running-pod/#ephemeral-container

注意事项

  1. 1.21版本的 k8s 有关临时容器需要额外开启特性
  2. 最新的版本应该是可以直接拿来用的,因为官方的特性状态Kubernetes v1.25 [stable]

静态 Pod

官方地址:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/#static-pods

什么是静态 Pod

  1. 静态 Pod(Static Pod) 直接由特定节点上的 kubelet 守护进程管理, 不需要 API 服务器看到它们。 尽管大多数 Pod 都是通过控制面(例如,Deployment) 来管理的,对于静态 Pod 而言,kubelet 直接监控每个 Pod,并在其失效时重启之。
  2. 静态 Pod 通常绑定到某个节点上的 kubelet。 其主要用途是运行自托管的控制面。 在自托管场景中,使用 kubelet 来管理各个独立的控制面组件
  3. kubelet 自动尝试为每个静态 Pod 在 Kubernetes API 服务器上创建一个镜像 Pod。 这意味着在节点上运行的 Pod 在 API 服务器上是可见的,但不可以通过 API 服务器来控制。

静态 Pod 位置

放在/etc/kubernetes/manifests下面的 Pod 文件,就是静态Pod,机器启动,kubelet就会自动启动这个目录下所有的Pod

image-20230302090658404

尝试在这个目录下尝试一个Pod

##pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  labels: 
    app: MYAPP
spec:
  initContainers:
  - name: pod-demo
    image: nginx

看一下状态:不知道为啥没有生效

这个后面深究一下,暂时跳过

image-20230302093546154

Pod 探针机制

这个之前的容器的探究有浅尝过

探针类型

image-20230302100830451

每个容器提供三种探针(Probe

  1. 启动探针(startupProbe

    • kubelet使用启动探针,来检测应用是否已经启动,如果启动就可以进行后续的探测,慢容器一定指定启动探针
    • 启动探针成功以后就不用了,剩下的探针会持续运行
  2. 存活探针(livenessProbe

    • kubelet 使用存活探针,来检测容器是否正常存活。(有些容器可能产生死锁【应用程序

      在运行,但是无法继续执行后面的步骤】)

    • 如果存活探针检测失败,就会重启这个容器

    • 有的人活着,它已经死了

  3. 就绪探针(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 之间。

image-20230302103110506

探针案例

许多长时间运行的应用最终会进入损坏状态,除非重新启动,否则无法被恢复。 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秒一次探测

启动并追踪一下状态

image-20230302104253159

image-20230302103430357

  1. 容器正常启动,5秒后开始探测
  2. 探测成功,容器继续运行
  3. 探测失败,容器重新启动

有关探针的描述和具体用法可以再参考官方链接

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

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐