对于Pod的健康状态检测,kubernetes提供了两类探针(Probe)来执行对Pod的健康状态检测:java
每类探针都支持三种探测方法:node
探针探测的结果有如下三者之一:docker
exec-liveness.yaml apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-exec spec: containers: - name: liveness image: k8s.gcr.io/busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5
在该配置文件中,对容器执行livenessProbe检查,periodSeconds字段指定kubelet每5s执行一次检查,检查的命令为cat /tmp/healthy,initialDelaySeconds字段告诉kubelet应该在执行第一次检查以前等待5秒,
若是命令执行成功,则返回0,那么kubelet就认为容器是健康的,若是为非0,则Kubelet会Kill掉容器并根据重启策略来决定是否须要重启。api
当容器启动时,它会执行如下命令:服务器
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
对于容器的前30秒,有一个/tmp/healthy文件。所以,在前30秒内,该命令cat /tmp/healthy返回成功代码。30秒后,cat /tmp/healthy返回失败代码。app
建立Pod:tcp
kubectl create -f https://k8s.io/examples/pods/probe/exec-liveness.yaml
在30秒内,查看Pod事件:ide
kubectl describe pod liveness-exec
输出代表还没有探测到失败:spa
FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 24s 24s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "k8s.gcr.io/busybox" 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "k8s.gcr.io/busybox" 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined] 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e
35秒后,再次查看Pod事件:code
kubectl describe pod liveness-exec
在输出的中显示探测失败,而且容器已被杀死并从新建立。
FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 37s 37s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "k8s.gcr.io/busybox" 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "k8s.gcr.io/busybox" 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined] 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e 2s 2s 1 {kubelet worker0} spec.containers{liveness} Warning Unhealthy Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
再等30秒,确认Container已从新启动:
kubectl get pod liveness-exec
下面输出中RESTARTS的次数已增长:
AME READY STATUS RESTARTS AGE liveness-exec 1/1 Running 1 1m
pods/probe/http-liveness.yaml apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-http spec: containers: - name: liveness image: k8s.gcr.io/liveness args: - /server livenessProbe: httpGet: path: /healthz port: 8080 httpHeaders: - name: X-Custom-Header value: Awesome initialDelaySeconds: 3 periodSeconds: 3
在配置文件中,使用k8s.gcr.io/liveness镜像,建立出一个Pod,其中periodSeconds字段指定kubelet每3秒执行一次探测,initialDelaySeconds字段告诉kubelet延迟等待3秒,探测方式为向容器中运行的服务发送HTTP GET请求,请求8080端口下的/healthz, 任何大于或等于200且小于400的代码表示成功。任何其余代码表示失败。
建立此Pod
kubectl create -f https://k8s.io/examples/pods/probe/http-liveness.yaml
10秒后,查看Pod事件以验证liveness探测失败而且Container已从新启动:
kubectl describe pod liveness-http
httpGet探测方式有以下可选的控制字段
- host:要链接的主机名,默认为Pod IP,能够在http request head中设置host头部。
- scheme: 用于链接host的协议,默认为HTTP。
- path:http服务器上的访问URI。
- httpHeaders:自定义HTTP请求headers,HTTP容许重复headers。
- port: 容器上要访问端口号或名称。
Kubelet将尝试在指定的端口上打开容器上的套接字,若是能创建链接,则代表容器健康。
pods/probe/tcp-liveness-readiness.yaml apiVersion: v1 kind: Pod metadata: name: goproxy labels: app: goproxy spec: containers: - name: goproxy image: k8s.gcr.io/goproxy:0.1 ports: - containerPort: 8080 readinessProbe: tcpSocket: port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 15 periodSeconds: 20
TCP检查方式和HTTP检查方式很是类似,示例中两种探针都使用了,在容器启动5秒后,kubelet将发送第一个readinessProbe探针,这将链接到容器的8080端口,若是探测成功,则该Pod将被标识为ready,10秒后,kubelet将进行第二次链接。
除此以后,此配置还包含了livenessProbe探针,在容器启动15秒后,kubelet将发送第一个livenessProbe探针,仍然尝试链接容器的8080端口,若是链接失败则重启容器。
建立:
kubectl create -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml
15秒后,查看Pod事件以验证活动探测:
kubectl describe pod goproxy
当容器有多个端口时,一般会给每一个端口命名,因此在使用探针探测时,也能够直接写自定义的端口名称
ports: - name: liveness-port containerPort: 8080 hostPort: 8080 livenessProbe: httpGet: path: /healthz port: liveness-port
ReadinessProbe探针的使用场景livenessProbe稍有不一样,有的时候应用程序可能暂时没法接受请求,好比Pod已经Running了,可是容器内应用程序还没有启动成功,在这种状况下,若是没有ReadinessProbe,则Kubernetes认为它能够处理请求了,然而此时,咱们知道程序还没启动成功是不能接收用户请求的,因此不但愿kubernetes把请求调度给它,则使用ReadinessProbe探针。
ReadinessProbe和livenessProbe可使用相同探测方式,只是对Pod的处置方式不一样,ReadinessProbe是将Pod IP:Port从对应的EndPoint列表中删除,而livenessProbe则Kill容器并根据Pod的重启策略来决定做出对应的措施。
ReadinessProbe探针探测容器是否已准备就绪,若是未准备就绪则kubernetes不会将流量转发给此Pod。
ReadinessProbe探针与livenessProbe同样也支持exec、httpGet、TCP的探测方式,配置方式相同,只不过是将livenessProbe字段修改成ReadinessProbe。
readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5
ReadinessProbe探针的HTTP、TCP的探测方式也与livenessProbe的基本一致。
如今来看一个加入ReadinessProbe探针和一个没有ReadinessProbe探针的示例:
该示例中,建立了一个deploy,名为JavaApp,启动的容器运行一个java应用程序,程序监听端口为8080。
# 没有加入ReadinessProbe cat JavaApp.yaml --- kind: Deployment apiVersion: apps/v1 metadata: name: JavaApp namespace: default spec: replicas: 1 selector: matchLabels: test: JavaApp template: metadata: labels: test: JavaApp spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: env operator: In values: - testing containers: - image: 192.168.1.183:8081/jar/JavaApp:29 name: JavaApp ports: - containerPort: 8080 imagePullSecrets: - name: myregistrykey --- kind: Service apiVersion: v1 metadata: name: JavaApp namespace: default spec: selector: test: JavaApp ports: - protocol: TCP port: 8080
建立:
kubectl create -f JavaApp.yaml
刚建立后,等几秒钟后,查看Pod状态:
$ kubectl get pod NAME READY STATUS RESTARTS AGE JavaApp-579b45567c-tdsrk 1/1 Running 0 6s
从上面能够看到,Pod刚启动6s,自身状态已Running,其READ字段,1/1 表示1个容器状态已准备就绪了,此时,对于kubernetes而言,它已经能够接收请求了,而实际上服务还没法访问,由于JAVA程序还尚启动起来,本人实验中的JAVA程序启动时间大概须要50s,50s后方可正常访问,因此针对此类程序,必须配置ReadinessProbe。
#加入readinessProbe kind: Deployment apiVersion: apps/v1 metadata: name: JavaApp namespace: default spec: replicas: 1 selector: matchLabels: test: JavaApp template: metadata: labels: test: JavaApp spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: env operator: In values: - testing containers: - image: 192.168.1.183:8081/jar/JavaApp:29 name: JavaApp ports: - containerPort: 8080 readinessProbe: tcpSocket: port: 8080 initialDelaySeconds: 60 periodSeconds: 10 imagePullSecrets: - name: myregistrykey --- kind: Service apiVersion: v1 metadata: name: JavaApp namespace: default spec: selector: test: JavaApp ports: - protocol: TCP port: 8080
在该配置文件中,ReadinessProbe探针的探测方式为tcpSocket,由于程序监听在8080端口,因此这里探测为对8080创建链接。程序启动时间大概50多秒,因此这里第一次探测时间是在Pod Runing后60秒后,间隔10秒后执行第二次探测。
建立Pod:
kubectl create -f JavaApp.yaml
建立后等50秒查看状态:
$ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE JavaApp-64b58cfd5c-kpc4s 0/1 Running 0 55s 172.26.91.109 192.168.1.180
Pod虽然已处于Runnig状态,可是因为第一次探测时间未到,因此READY字段为0/1,即容器的状态为未准备就绪,在未准备就绪的状况下,其Pod对应的Service下的Endpoint也为空,因此才不会有任何请求被调度进来。
$ kubectl get endpoints NAME ENDPOINTS JavaApp
当经过第一次探测的检查经过后,容器的状态天然会转为READ状态。
$ kubectl get pod NAME READY STATUS RESTARTS AGE JavaApp-64b58cfd5c-qj886 1/ Running 0 1m $ kubectl get endpoints NAME ENDPOINTS AGE JavaApp 172.26.91.113:8080 1m
此后根据指定的间隔时间10s后再次探测,若是不经过,则kubernetes就会将Pod IP从EndPoint列表中移除。
探针(Probe)有许多可选字段,能够用来更加精确的控制Liveness和Readiness两种探针的行为(Probe):