Skip to content

Kubernetes 探针

在 Kubernetes 中 Pod 是最小的计算单元,而一个 Pod 又由多个容器组成,相当于每个容器就是一个应用,应用在运行期间,可能因为某也意外情况致使程序挂掉。那么如何监控这些容器状态稳定性,保证服务在运行期间不会发生问题,发生问题后进行重启等机制,就成为了重中之重的事情,考虑到这点 kubernetes 推出了活性探针机制。有了存活性探针能保证程序在运行中如果挂掉能够自动重启,但是还有个经常遇到的问题,比如说,在 Kubernetes 中启动 Pod,显示明明 Pod 已经启动成功,且能访问里面的端口,但是却返回错误信息。还有就是在执行滚动更新时候,总会出现一段时间,Pod对外提供网络访问,但是访问却发生 404,这两个原因,都是因为 Pod 已经成功启动,但是 Pod 的的容器中应用程序还在启动中导致,考虑到这点 Kubernetes 推出了就绪性探针机制。

Kubernetes 探针类型

探针类型检查时机失败后果典型应用场景
Startup:启动探针容器启动阶段阻塞后续探针执行慢启动应用初始化
Liveness:存活探针运行期间定期检查重启容器(kubelet)检测死锁/内存泄漏
Readiness:就绪探针服务就绪检查从Service端点移除流量切换/依赖检查
  • 启动探针 Startup Probe :用于判断容器内应用程序是否启动,如果配置了startupProbe,就会先禁止其他的探针,直到它成功为止,成功后将不再进行探测。(1.16版本后加入,针对容器内应用服务是否已经启动监控)

  • 就绪探针 Readiness Probe :判断容器是否已经就绪,若未就绪,容器将会处于未就绪,未就绪的容器,不会进行流量的调度。 Kubernetes 会把 Pod 从 service endpoints 中剔除。

  • 存活探针 Liveness Probe :判断容器内的应用程序是否正常,若不正常,根据 Pod 的restartPolicy 重启策略操作,如果没有配置该探针,默认就是success

探针的检查方法

  • exec:通过在容器内执行指定命令,来判断命令退出时返回的状态码,返回状态码是0表示正常。

  • httpGet:通过对容器的 IP 地址、端口和 URL 路径来发送 GET 请求;如果响应的状态码在 200 ~399 间,表示正常。

  • tcpSocket:通过对容器的 IP 地址和指定端口,进行 TCP 检查,如果端口打开,发起 TCPSocket 建立成功,表示正常。

配置说明表

参数推荐值作用说明
initialDelaySeconds慢启动应用:30+延迟多少秒开始探测。避免应用未完成启动时被误判
periodSeconds生产环境≥5检查间隔,高频检查会增加应用负载,默认是10s最少是1秒
timeoutSeconds1-3超时时间,超过即视为失败
failureThreshold3-5连续失败次数,过大延长故障恢复时间,过小易误判,默认3次最少1次
successThreshold1(Readiness可设2)要求连续成功次数,防止偶发成功,只能1

经典案例

Startup Probe 启动探针

Nginx 挂载示例

场景:Nginx前端挂载宿主机目录检测

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: demo-probe
  labels:
    app: demo
    app: probe
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-start-probe
  namespace: demo-probe
  labels:
    app: demo
    app: probe
spec:
  volumes:
    - name: html
      hostPath:
        path: /data/html
  containers:
    - name: nginx-start-probe
      image: nginx
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - name: html
          mountPath: /html
      startupProbe:
        exec:
          command: ["/bin/sh","-c","cat /html/index.html"]
        initialDelaySeconds: 3
        periodSeconds: 5
        timeoutSeconds: 3
        failureThreshold: 3

Tomcat 示例

场景:Tomcat 应用需要长时间初始化(加载大型配置文件)

yaml
apiVersion: v1
kind: Pod
metadata:
  name: tomcat-app
spec:
  containers:
  - name: tomcat
    image: tomcat:9.0
    ports:
    - containerPort: 8080
    # Startup Probe 配置
    startupProbe:
      httpGet:
        path: /manager/html
        port: 8080
      initialDelaySeconds: 10  # 容器启动后等待10秒开始检查
      periodSeconds: 5         # 每5秒检查一次
      failureThreshold: 20     # 允许最多20次失败(总等待100秒)
      timeoutSeconds: 2        # 每次检查超时时间
    # 其他探针(仅在startup成功后生效)
    livenessProbe:
      httpGet:
        path: /manager/status
        port: 8080
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /manager/health
        port: 8080
      periodSeconds: 5

Liveness Probe 存活探针

Nginx 检测

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: demo-probe
  labels:
    app: demo
    app: probe
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-liveness-probe
  namespace: demo-probe
  labels:
    app: demo
    app: probe
spec:
  volumes:
    - name: conf
      hostPath:
        path: /data/nginx/conf
  containers:
    - name: nginx-liveness-probe
      image: nginx
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - name: conf
          mountPath: /etc/nginx/conf.d
      ports:
        - name: nginx-port
          containerPort: 8080
      livenessProbe:
        httpGet:
          port: 8080
          path: /health
          scheme: HTTP
        initialDelaySeconds: 15		# 等待应用完成启动
        periodSeconds: 10			# 每10秒检查一次
        timeoutSeconds: 3			# 超时时间
        failureThreshold: 3			# 连续失败3次即重启

Node.js 检测

场景:检测 Node.js 应用内存泄漏(进程存在但无响应)

yaml
apiVersion: v1
kind: Pod
metadata:
  name: nodejs-api
spec:
  containers:
  - name: nodejs
    image: node:18
    ports:
    - containerPort: 3000
    env:
    - name: NODE_ENV
      value: production
    # Liveness Probe 配置
    livenessProbe:
      httpGet:
        path: /health/live
        port: 3000
        httpHeaders:
        - name: X-Liveness-Token
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: liveness-token
      initialDelaySeconds: 30  # 等待应用完成启动
      periodSeconds: 15        # 每15秒检查一次
      failureThreshold: 2      # 连续失败2次即重启
      timeoutSeconds: 3        # 超时时间
    resources:
      limits:
        memory: "512Mi"
      requests:
        memory: "256Mi"

Readiness Probe 服务就绪探针

场景:MySQL 服务依赖检查(确保可接受新连接)

yaml
apiVersion: v1
kind: Pod
metadata:
  name: mysql-primary
spec:
  containers:
  - name: mysql
    image: mysql:8.0
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: '123456'
    ports:
    - containerPort: 3306
    # Readiness Probe 配置
    readinessProbe:
      exec:
        command:
        - sh
        - -c
        - "mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e 'SELECT 1' && test -f /var/lib/mysql/ready"
      initialDelaySeconds: 10
      periodSeconds: 5
      successThreshold: 1
      failureThreshold: 3
    volumeMounts:
    - name: mysql-data
      mountPath: /var/lib/mysql
  volumes:
  - name: mysql-data
    persistentVolumeClaim:
      claimName: mysql-pvc

三探针组合

场景:Spring Boot 微服务(包含数据库初始化)

yaml
apiVersion: v1
kind: Pod
metadata:
  name: order-service
spec:
  initContainers:
  - name: db-migration
    image: flyway/flyway
    command: ["flyway", "migrate"]
    envFrom:
    - configMapRef:
        name: db-config
  containers:
  - name: java-app
    image: springboot-order:2.7
    ports:
    - containerPort: 8080
    # 三探针组合配置
    startupProbe:
      httpGet:
        path: /actuator/health/startup
        port: 8080
      failureThreshold: 30  # 最长等待30 * 5=150秒
      periodSeconds: 5
    livenessProbe:
      httpGet:
        path: /actuator/health/liveness
        port: 8080
      periodSeconds: 10
      failureThreshold: 3
    readinessProbe:
      httpGet:
        path: /actuator/health/readiness
        port: 8080
      periodSeconds: 5
      failureThreshold: 3
    env:
    - name: JAVA_OPTS
      value: "-Xms512m -Xmx512m"
    volumeMounts:
    - name: config
      mountPath: "/app/config"
  volumes:
  - name: config
    configMap:
      name: app-config