
# 业务探针（Readiness probe）
一个新Pod创建后，Service就能立即选择到它，并会把请求转发给Pod，那问题就来了，通常一个Pod启动是需要时间的，如果Pod还没准备好（可能需要时间来加载配置或数据，或者可能需要执行 一个预热程序之类），这时把请求转给Pod的话，Pod也无法处理，造成请求失败。
Kubernetes中解决这个问题的方法就是给Pod加一个业务就绪探针Readiness Probe，当检测到Pod就绪后才允许Service请求转给Pod。
Readiness Probe同样是周期性的检测Pod，然后根据响应来判断Pod是否就绪，与[存活探针（liveness probe）](https://support.huaweicloud.com/devg-cci/cci_05_0013.html)相同，云容器实例中也支持两种类型的Readiness Probe。
- HTTP GET：往容器的IP:Port发送HTTP GET请求，如果probe收到2xx或3xx，说明已经就绪。
  ![](https://support.huaweicloud.com/devg-cci/public_sys-resources/note_3.0-zh-cn.png)
  需要为pod配置以下annotation使超时时间(timeoutSeconds)生效：
  cci.io/httpget-probe-timeout-enable:"true"
  具体请参见[Liveness Probe高级配置](https://support.huaweicloud.com/devg-cci/cci_05_0013.html#cci_05_0013__section1987894361812)样例。
  
- Exec：probe执行容器中的命令并检查命令退出的状态码，如果状态码为0则说明已经就绪。
#### Readiness Probe的工作原理
如果调用kubectl describe命令查看Service的信息，您会看到如下信息。
```
$ kubectl describe svc nginx -n $namespace_name
Name:              nginx
......
Endpoints:         192.168.113.81:80,192.168.165.64:80,192.168.198.10:80
......
```
可以看到一个Endpoints，Endpoints同样也是Kubernetes的一种资源对象，可以查询得到。
```
$ kubectl get endpoints -n $namespace_name
NAME         ENDPOINTS                                               AGE
nginx        192.168.113.81:80,192.168.165.64:80,192.168.198.10:80   14m
```
这里的192.168.113.81:80是Pod的IP:Port，通过如下命令可以查看到Pod的IP，与上面的IP一致。
```
# kubectl get pods -o wide -n $namespace_name
NAME                     READY     STATUS    RESTARTS   AGE       IP                                                                             
nginx-55c54cc5c7-49chn   1/1       Running   0          1m        192.168.198.10
nginx-55c54cc5c7-x87lb   1/1       Running   0          1m        192.168.165.64
nginx-55c54cc5c7-xp4c5   1/1       Running   0          1m        192.168.113.81
```
通过Endpoints就可以实现Readiness Probe的效果，当Pod还未就绪时，将Pod的IP:Port在Endpoints中删除，Pod就绪后再加入到Endpoints中，如下图所示。
图1Readiness Probe的实现原理   
![](https://support.huaweicloud.com/devg-cci/zh-cn_image_0198433583.png "点击放大")
#### Exec
Exec方式与HTTP GET方式一致，如下所示，这个探针执行**ls /ready**命令，如果这个文件存在，则返回0，说明Pod就绪了，否则返回其他状态码。
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: container-0
        resources:
          limits:
            cpu: 500m
            memory: 1024Mi
          requests:
            cpu: 500m
            memory: 1024Mi
        readinessProbe:      # Readiness Probe
          exec:              # 定义 ls /ready 命令
            command:
            - ls
            - /ready
      imagePullSecrets:
      - name: imagepull-secret
```
将上面Deployment的定义保存到deploy-read.yaml文件中，删除之前创建的Deployment，用deploy-read.yaml创建这个Deployment。
```
# kubectl delete deploy nginx -n $namespace_name
deployment.apps "nginx" deleted
# kubectl create -f deploy-read.yaml -n $namespace_name
deployment.apps/nginx created
```
这里由于nginx镜像不包含 /ready 这个文件，所以在创建完成后容器不在Ready状态，如下所示，注意READY这一列的值为0/1，表示容器没有Ready。
```
# kubectl get po -n $namespace_name
NAME                     READY     STATUS    RESTARTS   AGE
nginx-7955fd7786-686hp   0/1       Running   0          7s
nginx-7955fd7786-9tgwq   0/1       Running   0          7s
nginx-7955fd7786-bqsbj   0/1       Running   0          7s
```
再次查看Service，发现Endpoints一行的值为空，表示没有Endpoints。
```
$ kubectl describe svc nginx -n $namespace_name
Name:              nginx
......
Endpoints:         
......
```
如果此时给容器中创建一个 /ready 的文件，让Readiness Probe成功，则容器会处于Ready状态。再查看Pod和Endpoints，发现创建了/ready文件的容器已经Ready，Endpoints也已经添加。
```
# kubectl exec -n $namespace_name nginx-7955fd7786-686hp -- touch /ready 
# kubectl get po -o wide -n $namespace_name
NAME                     READY     STATUS    RESTARTS   AGE       IP
nginx-7955fd7786-686hp   1/1       Running   0          10m       192.168.93.169 
nginx-7955fd7786-9tgwq   0/1       Running   0          10m       192.168.166.130
nginx-7955fd7786-bqsbj   0/1       Running   0          10m       192.168.252.160
# kubectl get endpoints -n $namespace_name
NAME       ENDPOINTS           AGE
nginx      192.168.93.169:80   14d
```
#### HTTP GET
Readiness Probe的配置与[存活探针（livness probe）](https://support.huaweicloud.com/devg-cci/cci_05_0013.html)一样，都是在 Pod Template 的 containers 里面，如下所示，这个Readiness Probe向Pod发送HTTP请求，当Probe收到2xx或3xx返回时，说明Pod已经就绪。
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: container-0
        resources:
          limits:
            cpu: 500m
            memory: 1024Mi
          requests:
            cpu: 500m
            memory: 1024Mi
        readinessProbe:           # readinessProbe
          httpGet:                # HTTP GET定义
            path: /read
            port: 80
      imagePullSecrets:
      - name: imagepull-secret
```
#### Readiness Probe高级配置
与Liveness Probe相同，Readiness Probe也有同样的高级配置选项，上面nginx Pod的describe命令回显有中有如下行。
```
Readiness: exec [ls /var/ready] delay=0s timeout=1s period=10s #success=1 #failure=3
```
这一行表示readiness probe的具体参数配置，其含义如下：
- delay=0s 表示容器启动后立即开始探测，没有延迟时间
- timeout=1s 表示容器必须在1s内做出相应反馈给probe，否则视为探测失败
- period=10s 表示每10s探测一次
- #success=1 表示探测连续1次成功表示成功
- #failure=3 表示探测连续3次失败后会重启容器
这些是创建时默认设置的，您也可以手动配置，如下所示。
```
readinessProbe:      # Readiness Probe
          exec:              # 定义 ls /readiness/ready 命令
            command:
            - ls
            - /readiness/ready
          initialDelaySeconds: 10    # 容器启动后多久开始探测
          timeoutSeconds: 2          # 表示容器必须在2s内做出相应反馈给probe，否则视为探测失败
          periodSeconds: 30          # 探测周期，每30s探测一次
          successThreshold: 1        # 连续探测1次成功表示成功
          failureThreshold: 3        # 连续探测3次失败表示失败
```
