1.什么是Pod

2.Pod的使用

3.Pod的生命周期

4.Probe 探针机制(健康检查机制)

1.什么是Pod

虽然我们要介绍pod,但是我们一般不直接创建pod,而是创建一些(deployment等)来题我们创建Pod,通过其它途径创建出来的pod拥有自恢复能力

Pod是一组(一个或者多个)的容器(docker)集合,如同豌豆存在于豌豆荚中,这些容器共享存储,网络,以及如何运行这些容器等申明。
image.png

  • pod的形式

    • pod对容器有自恢复的能力(Pod自动重启启动失败的容器)
    • Pod自己没有自恢复的能力,删除了就真的没了。(deployment部署下的Pod有自恢复的能力。)
    • Pod 天生地为其成员容器提供了两种共享资源:网络和存储。
    • 单一容器的pod
    • 多容器的pod,我们把另外的容器成为SideCar(为应用赋能)。
    • 一个Pod由一个Pause容器设置好整个Pod里面所有容器的网络、名称空间等信息
    • kubelet启动一个Pod,准备两个容器,一个是Pod声明的应用容器(nginx),另外一个是

    Pause。Pause给当前应用容器设置好网络空间各种的。
    image.png

2.Pod的使用

我们可以打开Lens,连上们的K8s集群,使用如图功能,再选择pod模板,就可以直接创建pod了。
image.png
image.png

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80
          protocol: TCP

接着再点击右边的 Create&Close 就可以创建了.
image.png

3.Pod的生命周期

在讲解pod的生命周期之前,我们要先理解一个概念:initContainers(初始化容器)。初始化容器是K8s官网为我们提供的一个可以用来判断环境是否已经满足运行Pod应用前提的所需条件。

比如我们部署一个应用,必须要拥有一个前置环境,比如线上服务运行时得先启动Tomcat。我们需要检查Tomcat是否准备好,InitContainer就可以来帮助我们做这个事情。(一般在生产上会初始化一个容器监控服务,比如skeywalking的初始化,就会放在initContainers)。

image.png

  • Pod启动,会先依次执行所有初始化容器,有一个失败,则Pod不能启动。
  • 接下来启动所有的应用容器(每一个应用容器都必须能够一直运行),Pod开始正式工作,一个启动失败就会尝试重启Pod内的这个容器,Pod只要是NotReady,Pod就不对外提供服务了。

apiVersion: v1
kind: Pod
metadata:
  name: static-web
  labels:
    role: myrole
spec:
  initContainers: # 支持配置多个初始化容器,当前面的初始化容器运行成功后,便会进行退出操作,紧接着启动下一个容器。
    - name: my-init-container
      image: busybox:1.28
      # 打印666,睡眠60秒后启动程序。
      command: [ 'sh', '-c', 'echo 666 ;sleep 60' ]
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80
          protocol: TCP

4.Probe 探针机制(健康检查机制)
探针是一种协助容器是否正常启动的辅助工具,通过配置各种探针来监控服务是否正常启动和运行,如果异常该pod就会自动重启或者不启动。

每个容器都有三种探针(Probe)

  • 启动探针

    • 使用启动探针,来检测应用是否正常启动,如果启动就可以进行后续的探测检查。
    • 启动探针成功以后就不用了,剩下存活探针和就绪探针持续运行。
  • 存活探针

    • 使用存活探针,来检测容器是否正常存活。有些容器可能因为某些原因cpu飙升或者死锁,此时存活探针就会检测失败,导致重启这个pod。
  • 就绪探针

    • 使用就绪探针,来检测容器是否准备好了可以接收流量。当一个Pod内所有容器都准备好了,才能把这个pod看作就绪。用途就是:Service后端负载均衡多个Pod,如果某个Pod还没就绪,就会从service负载均衡里面剔除。

容器探针的yml写法:

apiVersion: v1
kind: Pod
metadata:
  name: "nginx-start-probe02"
  namespace: default
  labels:
    app: "nginx-start-probe02"
spec:
  containers:
  - name: nginx-start-probe02
    image: "nginx"
    resources:
      limits:
        cpu: 200m
        memory: 500Mi
      requests:
        cpu: 100m
        memory: 200Mi
    ports:
    - containerPort: 80
    startupProbe: #启动探针
      exec:
        command: ["/bin/sh","-c","cat /app/abc"] #必须有这个文件才能启动
      initialDelaySeconds: 20 ## 指定的这个秒以后才执行探测
      periodSeconds: 5 ## 每隔几秒来运行这个
      timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
      successThreshold: 1 ## 成功阈值,连续几次成才算成功
      failureThreshold: 3 ## 失败阈值,连续几次失败才算真失败
    livenessProbe: #存活探针
      exec: 
        command: ["/bin/sh","-c","cat /usr/share/nginx/html/abc.html"] #必须有这个文件才算存活
      initialDelaySeconds: 20 ## 指定的这个秒以后才执行探测
      periodSeconds: 5 ## 每隔几秒来运行这个
      timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
      successThreshold: 1 ## 成功阈值,连续几次成才算成功
      failureThreshold: 3 ## 失败阈值,连续几次失败才算真失败
    readinessProbe: #就绪探针
      httpGet:
        path: /abc.html
        port: 80
        scheme: HTTP
      initialDelaySeconds: 20 ## 指定的这个秒以后才执行探测
      periodSeconds: 5 ## 每隔几秒来运行这个
      timeoutSeconds: 5 ##探测超时,到了超时时间探测还没返回结果说明失败
      successThreshold: 1 ## 成功阈值,连续几次成才算成功
      failureThreshold: 3 ## 失败阈值,连续几次失败才算真失败
    volumeMounts:
    - name: nginx-vol
      mountPath: /app
    - name: nginx-html
      mountPath: /usr/share/nginx/html
  volumes:
    - name:  nginx-vol
      hostPath:
        path: /app
    - name:  nginx-html
      hostPath:
        path: /html
  restartPolicy: Always

以上只是demo写法,生产中我们部署springBoot应用,可以引入如下依赖,然后访问服务的/actuator/health接口就可以实现容器的健康检查。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
 
livenessProbe:
  httpGet:
    path: /actuator/health
    port: 80
    scheme: HTTP
  initialDelaySeconds: 220
  timeoutSeconds: 5
  periodSeconds: 5
  successThreshold: 1
  failureThreshold: 1
readinessProbe:
  httpGet:
    path: /actuator/health
    port: 80
    scheme: HTTP
  initialDelaySeconds: 120
  timeoutSeconds: 10
  periodSeconds: 10
  successThreshold: 1
  failureThreshold: 1
startupProbe:
  httpGet:
    path: /actuator/health
    port: 80
    scheme: HTTP
  initialDelaySeconds: 200
  timeoutSeconds: 10
  periodSeconds: 10
  successThreshold: 1
  failureThreshold: 1
startupProbe:
  httpGet:
    path: /actuator/health
    port: 80
    scheme: HTTP
  initialDelaySeconds: 180
  timeoutSeconds: 10
  periodSeconds: 10
  successThreshold: 1
  failureThreshold: 3

同时我们还可以接入服务的优雅停机,这样我们就可以实现健康检查+优雅停机=0宕机的做法,来无缝衔接发布一个服务。

springBoot的yaml:

server:
  # 设置关闭方式为优雅关闭 默认立即
  shutdown: graceful
  
spring:
  lifecycle:
    # 优雅关闭超时时间, 默认30s
    timeout-per-shutdown-phase: 300s

或者也可以在K8s的yaml中配置优雅停机:

# 和containers同一级别 因为这是操作整个pod的
spec.terminationGracePeriodSeconds:100

配合k8s的探针,当ctl 发起 kubeclt delete pod 时。k8s发起一个kill -2 命令,服务会立即不接受流量,k8sReadiness探针失败,不再分配流量。

springboot项目若配置了优雅停止,在超时时间内等待所有的controller,即tomcat的线程池的任务全部完成后k8s持续探测的Liveness探针会在服务完全关闭的时候失败,之后k8s就算成功杀死pod了。
注意controller fork 出来的子线程的任务不会收到web的优雅停机的影响。


苏凌峰
73 声望38 粉丝

你的迷惑在于想得太多而书读的太少。