From faa5f517bd0c17b1364a99dae33261efb62b619b Mon Sep 17 00:00:00 2001 From: Jimmy Song Date: Mon, 22 May 2017 17:44:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0pod=E6=8E=A2=E9=92=88?= =?UTF-8?q?=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SUMMARY.md | 1 + guide/configure-liveness-readiness-probes.md | 236 +++++++++++++++++++ guide/index.md | 3 + 3 files changed, 240 insertions(+) create mode 100644 guide/configure-liveness-readiness-probes.md diff --git a/SUMMARY.md b/SUMMARY.md index a49a38857..1e4b8d41a 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -21,6 +21,7 @@ - [2.2.14 Ingress](concepts/ingress.md) - [2.2.15 ConfigMap](concepts/configmap.md) - [3. 用户指南](guide/index.md) + - [3.1 配置Pod的liveness和readiness探针](configure-liveness-readiness-probes.md) - [4. 最佳实践](practice/index.md) - [ 4.1 在CentOS上部署kubernetes1.6集群](practice/install-kbernetes1.6-on-centos.md) - [4.1.1 创建TLS证书和秘钥](practice/create-tls-and-secret-key.md) diff --git a/guide/configure-liveness-readiness-probes.md b/guide/configure-liveness-readiness-probes.md new file mode 100644 index 000000000..a45cb09a1 --- /dev/null +++ b/guide/configure-liveness-readiness-probes.md @@ -0,0 +1,236 @@ +# 配置Pod的liveness和readiness探针 + +当你使用kuberentes的时候,有没有遇到过Pod在启动后一会就挂掉然后又重新启动这样的恶性循环?你有没有想过kubernetes是如何检测pod是否还存活?虽然容器已经启动,但是kubernetes如何知道容器的进程是否准备好对外提供服务了呢?通过kuberentes官网的这篇文章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` 命令。如果命令执行成功,将返回0,kubelet就会认为该容器是活着的并且很健康。如果返回非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将尝试在指定端口上打开容器的套接字。 如果可以建立连接,容器被认为是健康的,如果不能就认为是失败的。 + +如您所见,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中有很多精确和详细的配置,通过它们你能准确的控制liveness和readiness检查: + +- `initialDelaySeconds`:容器启动后第一次执行探测是需要等待多少秒。 +- `periodSeconds`:执行探测的频率。默认是10秒,最小1秒。 +- `timeoutSeconds`:探测超时时间。默认1秒,最小1秒。 +- `successThreshold`:探测失败后,最少连续探测成功多少次才被认定为成功。默认是1。对于liveness必须是1。最小值是1。 +- `failureThreshold`:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1。 + +HTTP probe中可以给 `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`头。 + diff --git a/guide/index.md b/guide/index.md index 893c9f5f3..8fffbdce0 100644 --- a/guide/index.md +++ b/guide/index.md @@ -1,2 +1,5 @@ # 用户指南 +该章节主要记录kubernetes使用过程中的一些配置技巧和操作。 + +- [配置Pod的liveness和readiness探针](configure-liveness-readiness-probes.md) \ No newline at end of file