kubernetes-handbook/guide/configure-liveness-readines...

264 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 配置Pod的liveness和readiness探针
当你使用kuberentes的时候有没有遇到过Pod在启动后一会就挂掉然后又重新启动这样的恶性循环你有没有想过kubernetes是如何检测pod是否还存活虽然容器已经启动但是kubernetes如何知道容器的进程是否准备好对外提供服务了呢让我们通过kuberentes官网的这篇文章[Configure Liveness and Readiness Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/),来一探究竟。
本文将向展示如何配置容器的存活和可读性探针。
Kubelet使用liveness probe存活探针来确定何时重启容器。例如当应用程序处于运行状态但无法做进一步操作liveness探针将捕获到deadlock重启处于该状态下的容器使应用程序在存在bug的情况下依然能够继续运行下去谁的程序还没几个bug呢
Kubelet使用readiness probe就绪探针来确定容器是否已经就绪可以接受流量。只有当Pod中的容器都处于就绪状态时kubelet才会认定该Pod处于就绪状态。该信号的作用是控制哪些Pod应该作为service的后端。如果Pod处于非就绪状态那么它们将会被从service的load balancer中移除。
## 定义 liveness命令
许多长时间运行的应用程序最终会转换到broken状态除非重新启动否则无法恢复。Kubernetes提供了liveness probe来检测和补救这种情况。
在本次练习将基于 `gcr.io/google_containers/busybox`镜像创建运行一个容器的Pod。以下是Pod的配置文件`exec-liveness.yaml`
```Yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
image: gcr.io/google_containers/busybox
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
```
该配置文件给Pod配置了一个容器。`periodSeconds` 规定kubelet要每隔5秒执行一次liveness probe。 `initialDelaySeconds` 告诉kubelet在第一次执行probe之前要的等待5秒钟。探针检测命令是在容器中执行 `cat /tmp/healthy` 命令。如果命令执行成功将返回0kubelet就会认为该容器是活着的并且很健康。如果返回非0值kubelet就会杀掉这个容器并重启它。
容器启动时,执行该命令:
```shell
/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` 将返回失败的返回码。
创建Pod
```shell
kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/exec-liveness.yaml
```
在30秒内查看Pod的event
```
kubectl describe pod liveness-exec
```
结果显示没有失败的liveness probe
```shell
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 "gcr.io/google_containers/busybox"
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "gcr.io/google_containers/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的event
```shell
kubectl describe pod liveness-exec
```
在最下面有一条信息显示liveness probe失败容器被删掉并重新创建。
```shell
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 "gcr.io/google_containers/busybox"
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "gcr.io/google_containers/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秒确认容器已经重启
```shell
kubectl get pod liveness-exec
```
从输出结果来`RESTARTS`值加1了。
```shell
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 1m
```
## 定义一个liveness HTTP请求
我们还可以使用HTTP GET请求作为liveness probe。下面是一个基于`gcr.io/google_containers/liveness`镜像运行了一个容器的Pod的例子`http-liveness.yaml`
```yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
args:
- /server
image: gcr.io/google_containers/liveness
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
```
该配置文件只定义了一个容器,`livenessProbe` 指定kubelete需要每隔3秒执行一次liveness probe。`initialDelaySeconds` 指定kubelet在该执行第一次探测之前需要等待3秒钟。该探针将向容器中的server的8080端口发送一个HTTP GET请求。如果server的`/healthz`路径的handler返回一个成功的返回码kubelet就会认定该容器是活着的并且很健康。如果返回失败的返回码kubelet将杀掉该容器并重启它。
任何大于200小于400的返回码都会认定是成功的返回码。其他返回码都会被认为是失败的返回码。
查看该server的源码[server.go](http://k8s.io/docs/user-guide/liveness/image/server.go).
最开始的10秒该容器是活着的 `/healthz` handler返回200的状态码。这之后将返回500的返回码。
```go
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
```
容器启动3秒后kubelet开始执行健康检查。第一次健康监测会成功但是10秒后健康检查将失败kubelet将杀掉和重启容器。
创建一个Pod来测试一下HTTP liveness检测
```shell
kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/http-liveness.yaml
```
After 10 seconds, view Pod events to verify that liveness probes have failed and
the Container has been restarted:
10秒后查看Pod的event确认liveness probe失败并重启了容器。
```shell
kubectl describe pod liveness-http
```
## 定义TCP liveness探针
第三种liveness probe使用TCP Socket。 使用此配置kubelet将尝试在指定端口上打开容器的套接字。 如果可以建立连接,容器被认为是健康的,如果不能就认为是失败的。
```yaml
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: gcr.io/google_containers/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
```
如您所见TCP检查的配置与HTTP检查非常相似。 此示例同时使用了readiness和liveness probe。 容器启动后5秒钟kubelet将发送第一个readiness probe。 这将尝试连接到端口8080上的goproxy容器。如果探测成功则该pod将被标记为就绪。Kubelet将每隔10秒钟执行一次该检查。
除了readiness probe之外该配置还包括liveness probe。 容器启动15秒后kubelet将运行第一个liveness probe。 就像readiness probe一样这将尝试连接到goproxy容器上的8080端口。如果liveness probe失败容器将重新启动。
## 使用命名的端口
可以使用命名的ContainerPort作为HTTP或TCP liveness检查
```yaml
ports:
- name: liveness-port
containerPort: 8080
hostPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
```
## 定义readiness探针
有时,应用程序暂时无法对外部流量提供服务。 例如,应用程序可能需要在启动期间加载大量数据或配置文件。 在这种情况下,你不想杀死应用程序,但你也不想发送请求。 Kubernetes提供了readiness probe来检测和减轻这些情况。 Pod中的容器可以报告自己还没有准备不能处理Kubernetes服务发送过来的流量。
Readiness probe的配置跟liveness probe很像。唯一的不同是使用 `readinessProbe `而不是`livenessProbe`。
```yaml
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
```
Readiness probe的HTTP和TCP的探测器配置跟liveness probe一样。
Readiness和livenss probe可以并行用于同一容器。 使用两者可以确保流量无法到达未准备好的容器,并且容器在失败时重新启动。
## 配置Probe
[Probe](https://kubernetes.io/docs/api-reference/v1.6/#probe-v1-core)中有很多精确和详细的配置通过它们你能准确的控制liveness和readiness检查
- `initialDelaySeconds`:容器启动后第一次执行探测是需要等待多少秒。
- `periodSeconds`执行探测的频率。默认是10秒最小1秒。
- `timeoutSeconds`探测超时时间。默认1秒最小1秒。
- `successThreshold`探测失败后最少连续探测成功多少次才被认定为成功。默认是1。对于liveness必须是1。最小值是1。
- `failureThreshold`探测成功后最少连续探测失败多少次才被认定为失败。默认是3。最小值是1。
[HTTP probe](https://kubernetes.io/docs/api-reference/v1.6/#httpgetaction-v1-core)中可以给 `httpGet`设置其他配置项:
- `host`连接的主机名默认连接到pod的IP。你可能想在http header中设置"Host"而不是使用IP。
- `scheme`连接使用的schema默认HTTP。
- `path`: 访问的HTTP server的path。
- `httpHeaders`自定义请求的header。HTTP运行重复的header。
- `port`访问的容器的端口名字或者端口号。端口号必须介于1和65525之间。
对于HTTP探测器kubelet向指定的路径和端口发送HTTP请求以执行检查。 Kubelet将probe发送到容器的IP地址除非地址被`httpGet`中的可选`host`字段覆盖。 在大多数情况下,你不想设置主机字段。 有一种情况下你可以设置它。 假设容器在127.0.0.1上侦听并且Pod的`hostNetwork`字段为true。 然后,在`httpGet`下的`host`应该设置为127.0.0.1。 如果你的pod依赖于虚拟主机这可能是更常见的情况你不应该是用`host`,而是应该在`httpHeaders`中设置`Host`头。
## 参考
- 关于 [Container Probes](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes) 的更多信息