探索 Pod 及其端点的终止行为

一旦你参照使用 Service 连接到应用中概述的那些步骤使用 Service 连接到了你的应用,你就有了一个持续运行的多副本应用暴露在了网络上。 本教程帮助你了解 Pod 的终止流程,探索实现连接排空的几种方式。

Pod 及其端点的终止过程

你经常会遇到需要终止 Pod 的场景,例如为了升级或缩容。 为了改良应用的可用性,实现一种合适的活跃连接排空机制变得重要。

本教程将通过使用一个简单的 nginx Web 服务器演示此概念, 解释 Pod 终止的流程及其与相应端点状态和移除的联系。

端点终止的示例流程

以下是 Pod 终止文档中所述的流程示例。

假设你有包含单个 nginx 副本(仅用于演示目的)的一个 Deployment 和一个 Service:

service/pod-with-graceful-termination.yaml 探索 Pod 及其端点的终止行为 - 图1

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: nginx-deployment
  5. labels:
  6. app: nginx
  7. spec:
  8. replicas: 1
  9. selector:
  10. matchLabels:
  11. app: nginx
  12. template:
  13. metadata:
  14. labels:
  15. app: nginx
  16. spec:
  17. terminationGracePeriodSeconds: 120 # 超长优雅期
  18. containers:
  19. - name: nginx
  20. image: nginx:latest
  21. ports:
  22. - containerPort: 80
  23. lifecycle:
  24. preStop:
  25. exec:
  26. # 实际生产环境中的 Pod 终止可能需要执行任何时长,但不会超过 terminationGracePeriodSeconds。
  27. # 在本例中,只需挂起至少 terminationGracePeriodSeconds 所指定的持续时间,
  28. # 在 120 秒时容器将被强制终止。
  29. # 请注意,在所有这些时间点 nginx 都将继续处理请求。
  30. command: [
  31. "/bin/sh", "-c", "sleep 180"
  32. ]
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: nginx-deployment
  5. labels:
  6. app: nginx
  7. spec:
  8. replicas: 1
  9. selector:
  10. matchLabels:
  11. app: nginx
  12. template:
  13. metadata:
  14. labels:
  15. app: nginx
  16. spec:
  17. terminationGracePeriodSeconds: 120 # 超长优雅期
  18. containers:
  19. - name: nginx
  20. image: nginx:latest
  21. ports:
  22. - containerPort: 80
  23. lifecycle:
  24. preStop:
  25. exec:
  26. # 实际生产环境中的 Pod 终止可能需要执行任何时长,但不会超过 terminationGracePeriodSeconds。
  27. # 在本例中,只需挂起至少 terminationGracePeriodSeconds 所指定的持续时间,
  28. # 在 120 秒时容器将被强制终止。
  29. # 请注意,在所有这些时间点 nginx 都将继续处理请求。
  30. command: [
  31. "/bin/sh", "-c", "sleep 180"
  32. ]
  33. ---
  34. apiVersion: v1
  35. kind: Service
  36. metadata:
  37. name: nginx-service
  38. spec:
  39. selector:
  40. app: nginx
  41. ports:
  42. - protocol: TCP
  43. port: 80
  44. targetPort: 80

一旦 Pod 和 Service 开始运行,你就可以获取对应的所有 EndpointSlices 的名称:

  1. kubectl get endpointslice

输出类似于:

  1. NAME ADDRESSTYPE PORTS ENDPOINTS AGE
  2. nginx-service-6tjbr IPv4 80 10.12.1.199,10.12.1.201 22m

你可以查看其 status 并验证已经有一个端点被注册:

  1. kubectl get endpointslices -o json -l kubernetes.io/service-name=nginx-service

输出类似于:

  1. {
  2. "addressType": "IPv4",
  3. "apiVersion": "discovery.k8s.io/v1",
  4. "endpoints": [
  5. {
  6. "addresses": [
  7. "10.12.1.201"
  8. ],
  9. "conditions": {
  10. "ready": true,
  11. "serving": true,
  12. "terminating": false
  13. }
  14. }
  15. ]
  16. }

现在让我们终止这个 Pod 并验证该 Pod 正在遵从体面终止期限的配置进行终止:

  1. kubectl delete pod nginx-deployment-7768647bf9-b4b9s

查看所有 Pod:

  1. kubectl get pods

输出类似于:

  1. NAME READY STATUS RESTARTS AGE
  2. nginx-deployment-7768647bf9-b4b9s 1/1 Terminating 0 4m1s
  3. nginx-deployment-7768647bf9-rkxlw 1/1 Running 0 8s

你可以看到新的 Pod 已被调度。

当系统在为新的 Pod 创建新的端点时,旧的端点仍处于 Terminating 状态:

  1. kubectl get endpointslice -o json nginx-service-6tjbr

输出类似于:

  1. {
  2. "addressType": "IPv4",
  3. "apiVersion": "discovery.k8s.io/v1",
  4. "endpoints": [
  5. {
  6. "addresses": [
  7. "10.12.1.201"
  8. ],
  9. "conditions": {
  10. "ready": false,
  11. "serving": true,
  12. "terminating": true
  13. },
  14. "nodeName": "gke-main-default-pool-dca1511c-d17b",
  15. "targetRef": {
  16. "kind": "Pod",
  17. "name": "nginx-deployment-7768647bf9-b4b9s",
  18. "namespace": "default",
  19. "uid": "66fa831c-7eb2-407f-bd2c-f96dfe841478"
  20. },
  21. "zone": "us-central1-c"
  22. },
  23. ]
  24. {
  25. "addresses": [
  26. "10.12.1.202"
  27. ],
  28. "conditions": {
  29. "ready": true,
  30. "serving": true,
  31. "terminating": false
  32. },
  33. "nodeName": "gke-main-default-pool-dca1511c-d17b",
  34. "targetRef": {
  35. "kind": "Pod",
  36. "name": "nginx-deployment-7768647bf9-rkxlw",
  37. "namespace": "default",
  38. "uid": "722b1cbe-dcd7-4ed4-8928-4a4d0e2bbe35"
  39. },
  40. "zone": "us-central1-c"
  41. }
  42. }

这种设计使得应用可以在终止期间公布自己的状态,而客户端(如负载均衡器)则可以实现连接排空功能。 这些客户端可以检测到正在终止的端点,并为这些端点实现特殊的逻辑。

在 Kubernetes 中,正在终止的端点始终将其 ready 状态设置为 false。 这是为了满足向后兼容的需求,确保现有的负载均衡器不会将 Pod 用于常规流量。 如果需要排空正被终止的 Pod 上的流量,可以将 serving 状况作为实际的就绪状态。

当 Pod 被删除时,旧的端点也会被删除。

接下来