Kubernetes
Kubernetes是一个开源容器编排平台,大大简化了应用程序的创建和管理。
Kubernetes之类的分布式系统可能很难管理,原因是涉及许多活动组件,所有这些组件必须正常工作,整个系统才能顺畅运行。即使某个小组件坏掉,也需要检测和修复它。
这些操作还需要自动化。Kubernetes让我们可以借助就绪探针和存活探针做到这一点。这里详细讨论了这些探针,在此之前先讨论一下健康检查。

1、什么是健康检查?

健康检查是一种让系统知道应用程序实例是否正常运行的简单方法。如果应用程序实例未正常运行,其他服务不会访问它或向它发送请求。相反,会将请求发送到另一个准备就绪的实例,或者应该重试发送请求。
系统应该能够使应用程序处于健康状态。默认情况下,pod内的所有容器都已启动后,Kubernetes会开始向该pod发送流量。容器崩溃时,Kubernetes会重启容器。这个默认行为应该足以开始上手。由于Kubernetes有助于创建自定义健康检查,提高部署稳健性就变得比较简单,现在先讨论一下pod生命周期。

2、pod生命周期

Kubernetes pod遵循已定义的生命周期。这些是不同的阶段:
• pod首次创建后,从pending(挂起)阶段开始。调度器试图搞清楚把pod放置在哪里。如果调度器找不到放置pod的节点,它将保持挂起状态。(要检查pod为何处于挂起状态,运行kubectl describe pod <pod name>命令)。
• 一旦pod被调度,它进入容器creating(创建)阶段,在此阶段拉取应用程序所需的镜像,随后容器启动。
• 一旦容器在pod中,它进入running(运行)阶段,在此阶段它继续运行,直至程序成功完成或终止。
要检查pod的状态,请运行kubectl get pod命令,检查STATUS列。在这种情况下,所有pod都处于运行状态。此外,READY列表明pod已准备好接受用户流量。

  1. # kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. my-nginx-6b74b79f57-fldq6 1/1 Running 0 20s
  4. my-nginx-6b74b79f57-n67wp 1/1 Running 0 20s
  5. my-nginx-6b74b79f57-r6pcq 1/1 Running 0 20s

3、Kubernetes中不同类型的探针

Kubernetes提供了以下类型的健康检查:
• 就绪探针:该探针将告诉你应用程序何时准备为流量提供服务。在允许服务向pod发送流量之前,Kubernetes将确保就绪探针通过。如果就绪探针未通过,Kubernetes不会向pod发送流量,直至探针通过。
• 存活探针:存活探针会让Kubernetes可以知道应用程序是否健康。如果应用程序健康,Kubernetes不会干扰pod的运行,但如果不健康,Kubernetes就会销毁pod,并启动新的pod来替换它。
为了进一步理解这点,不妨以实际场景为例。应用程序需要一些时间来预热,或从GitHub等某个外部源下载应用程序内容。除非完全准备好,否则应用程序不会接受流量。默认情况下,一旦容器内的进程启动,Kubernetes就会开始发送流量。使用就绪探针,Kubernetes会等到应用程序完全启动后,才允许服务将流量发送到新副本。
不妨看另一种场景:应用程序因代码错误而崩溃(可能是极端情况),并且无限期挂起,停止为请求提供服务。由于进程默认继续运行,Kubernetes会将流量发送到坏掉的pod。使用存活探针,Kubernetes将检测到应用程序不再为请求提供服务,默认情况下重启出故障的pod。
现在看看如何定义探针。探针有三种类型:
• HTTP
• TCP
• 命令
注意:可以选择从定义就绪探针或存活探针开始,因为两者的实现都需要类似的模板。比如说,如果先定义存活探针,可以使用它来定义就绪探针,反之亦然。
• HTTP探针(httpGet):这是最常见的探针类型。即使应用程序不是HTTP服务器,通常也可以在应用程序内创建轻量级 HTTP服务器以响应存活探针。Kubernetes将在特定端口(本例中端口8080)测式ping路径(比如/healthz)。如果它收到200或300范围内的HTTP响应,将被标记为健康。(想进一步了解HTTP响应代码,请参阅该链接https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)。否则,它会被标记为不健康。以下是定义HTTP存活探针的方法:

  1. livenessProbe:
  2. httpGet:
  3. path: /healthz
  4. port: 8080

HTTP就绪探针的定义与HTTP存活探针类似,只需要把liveness换成readiness。

  1. readinessProbe:
  2. httpGet:
  3. path: /healthz
  4. port: 8080

• TCP探针(tcpSocket):使用TCP探针,Kubernetes会尝试在指定端口(比如下例中的8080端口)建立TCP连接。如果可以建立连接,则认为容器是健康的。如果不能,视为失败。在HTTP或命令探针无法正常工作的情况下,这些探针会很方便。比如说,FTP服务将能够使用这种类型的探针。

  1. readinessProbe:
  2. tcpSocket:
  3. port: 8080

• 命令探针(exec命令):在命令探针情况下,Kubernetes将在容器内运行命令。如果命令返回退出代码0,容器将被标记为健康。否则,将被标记为不健康。当不能或不想运行HTTP服务器时,这种类型的探针很有用,可以运行命令来检查应用程序是否健康。在下面示例中,检查文件/tmp/healthy是否存在;如果命令返回退出代码0,容器将被标记为健康;否则,它将被标记为不健康。

  1. livenessProbe:
  2. exec:
  3. command:
  4. - cat
  5. - /tmp/healthy

可根据需要运行的频率、成功和失败阈值以及等待响应的时间,以多种方式配置探针。
• initialDelaySeconds(默认值0):如果知道应用程序需要n秒(比如30秒)来预热,可以使用initialDelaySeconds来添加延迟(以秒为单位),直至执行第一次检查。
periodSeconds(默认值10):如果想要指定执行检查的频率,可以使用periodSeconds来定义。
timeoutSeconds(默认值1):这定义了探针操作超时之前的最大秒数。
successThreshold(默认值1):这是在失败后探针直至被认为成功的尝试次数。
failureThreshold(默认值 3):万一探针失败,Kubernetes会尝试多次,然后将探针标记为失败。
注意:默认情况下,如果应用程序在尝试3次后仍未准备好,探针将停止。如果是存活探针,它将重启容器。如果是就绪探针,它会将pod标记为不健康。
有关探针配置的更多信息,请参阅该链接:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes
不妨结合到目前为止已讨论过的所有内容。这里要注意的关键是readinessProbe与httpGet的使用。第一次检查将在10秒后执行,然后每5秒重复一次。

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. labels:
  5. run: nginx
  6. name: nginx
  7. spec:
  8. containers:
  9. - image: nginx
  10. name: nginx
  11. readinessProbe:
  12. httpGet:
  13. path: /
  14. port: 80
  15. initialDelaySeconds: 10
  16. periodSeconds: 5

• 要创建pod,请使用kubectl create命令,并使用-f标志指定YAML清单文件。可以为该文件取任何名称,但后缀名应该是.yaml。

  1. kubectl create -f readinessprobe.yaml
  2. pod/nginx created

• 如果现在检查pod的状态,它应该在STATUS列下显示状态为Running。但如果检查READY列,它仍然会显示0/1,这意味着它没有准备好接受新的连接。

  1. kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. nginx 0/1 Running 0 16s

• 由于将初始延迟设置为1秒,几秒钟后验证状态。现在,pod应该在运行。

  1. kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. nginx 1/1 Running 0 28s

• 要检查定义就绪探针时使用的所有参数(比如initialDelaySecondsperiodSeconds等)的详细状态,运行kubectl describe命令。

  1. kubectl describe pod nginx |grep -i readiness
  2. Readiness: http-get http://:80/ delay=10s timeout=1s period=5s #success=1 #failure=3

不妨通过一个例子进一步加深对存活探针和就绪探针概念的了解。先从活性探针开始。在下面例子中,在执行命令:touch healthy; sleep 20; rm -rf healthy; sleep 600’。
借助该命令,使用touch 命令创建了文件名“healthy”。该文件前20秒将存在于容器中,然后使用rm -rf命令将其删除。最后,容器将休眠600秒。
随后定义了存活探针。它先使用cat health命令检查该文件是否存在。它以5秒的初始延迟完成此操作。进一步定义了参数periodSeconds,它每5秒就执行存活探针。一旦删除该文件,20秒后,探针将处于失败状态。

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. labels:
  5. name: liveness-probe-exec
  6. spec:
  7. containers:
  8. - name: liveness-probe
  9. image: busybox
  10. args:
  11. - /bin/sh
  12. - -c
  13. - touch healthy; sleep 20; rm -rf healthy; sleep 600
  14. livenessProbe:
  15. exec:
  16. command:
  17. - cat
  18. - healthy
  19. initialDelaySeconds: 5
  20. periodSeconds: 5

• 要创建pod,将上述代码存储在以.yaml结尾的文件中(比如liveness-probe.yaml),然后使用-f <file name> 执行kubectl create命令,这将创建pod。

  1. # kubectl create -f liveness-probe.yaml
  2. pod/liveness-probe-exec created

• 运行kubectl get events命令,会看到存活探针已失败,容器已被杀死并重启。

  1. 54s Normal Scheduled pod/liveness-probe-exec Successfully assigned default/liveness-probe-exec to controlplane
  2. 53s Normal Pulling pod/liveness-probe-exec Pulling image "busybox"
  3. 52s Normal Pulled pod/liveness-probe-exec Successfully pulled image "busybox" in 384.330188ms
  4. 52s Normal Created pod/liveness-probe-exec Created container liveness-probe
  5. 52s Normal Started pod/liveness-probe-exec Started container liveness-probe
  6. 18s Warning Unhealthy pod/liveness-probe-exec Liveness probe failed: cat: can't open 'healthy': No such file or directory
  7. 18s Normal Killing pod/liveness-probe-exec Container liveness-probe failed liveness probe, will be restarted

• 还可以使用kubectl get pods命令进行验证,正如在重启列中看到,容器重启了一次。

  1. # kubectl get pods
  2. NAME READY STATUS RESTARTS AGE
  3. liveness-probe-exec 1/1 Running 1 24s

• 现在已了解存活探针的工作原理,不妨调整上面的例子将其定义为就绪探针,以此了解就绪探针的工作原理。在下面例子中,在容器内执行命令(sleep 20; touch healthy; sleep 600),它先休眠20秒,创建一个文件,最后休眠600秒。由于初始延迟设置为15秒,第一次检查以15 秒延迟来执行。

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. labels:
  5. name: readiness-probe-exec
  6. spec:
  7. containers:
  8. - name: readiness-probe
  9. image: busybox
  10. args:
  11. - /bin/sh
  12. - -c
  13. - sleep 20;touch healthy;sleep 600
  14. readinessProbe:
  15. exec:
  16. command:
  17. - cat
  18. - healthy
  19. initialDelaySeconds: 15
  20. periodSeconds: 5

• 要创建pod,将上述代码存储在以.yaml结尾的文件中,然后执行kubectl create命令,该命令将创建pod。

  1. # kubectl create -f readiness-probe.yaml
  2. pod/readiness-probe-exec created

• 如果在这里执行kubectl get events,会看到探针失败,因为文件不存在。

  1. 63s Normal Scheduled pod/readiness-probe-exec Successfully assigned default/readiness-probe-exec to controlplane
  2. 62s Normal Pulling pod/readiness-probe-exec Pulling image "busybox"
  3. 62s Normal Pulled pod/readiness-probe-exec Successfully pulled image "busybox" in 156.57701ms
  4. 61s Normal Created pod/readiness-probe-exec Created container readiness-probe
  5. 61s Normal Started pod/readiness-probe-exec Started container readiness-probe
  6. 42s Warning Unhealthy pod/readiness-probe-exec Readiness probe failed: cat: can't open 'healthy': No such file or directory
  7. If you check the status of the container initially, it is not in a ready state.
  8. # kubectl get pods
  9. NAME READY STATUS RESTARTS AGE
  10. readiness-probe-exec 0/1 Running 0 5s

• 但是如果在20秒后检查它,它应该处于运行状态。

  1. # kubectl get pods
  2. NAME READY STATUS RESTARTS AGE
  3. readiness-probe-exec 1/1 Running 0 27s

结论

任何分布式系统都需要检查健康,Kubernetes也不例外。使用健康检查为Kubernetes服务提供稳固的基础、更高的可靠性和更长的正常运行时间。