带 Pod 间通信的 Job

在此例中,你将以索引完成模式运行一个 Job, 并通过配置使得该 Job 所创建的各 Pod 之间可以使用 Pod 主机名而不是 Pod IP 地址进行通信。

某 Job 内的 Pod 之间可能需要通信。每个 Pod 中运行的用户工作负载可以查询 Kubernetes API 服务器以获知其他 Pod 的 IP,但使用 Kubernetes 内置的 DNS 解析会更加简单。

索引完成模式下的 Job 自动将 Pod 的主机名设置为 ${jobName}-${completionIndex} 的格式。 你可以使用此格式确定性地构建 Pod 主机名并启用 Pod 通信,无需创建到 Kubernetes 控制平面的客户端连接来通过 API 请求获取 Pod 主机名/IP。

此配置可用于需要 Pod 联网但不想依赖 Kubernetes API 服务器网络连接的使用场景。

准备开始

你应该已熟悉了 Job 的基本用法。

你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。 建议在至少有两个节点的集群上运行本教程,且这些节点不作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:

你的 Kubernetes 服务器版本必须不低于版本 v1.21. 要获知版本信息,请输入 kubectl version.

说明:

如果你正在使用 MiniKube 或类似的工具, 你可能需要采取额外的步骤来确保你拥有 DNS。

启动带 Pod 间通信的 Job

要在某 Job 中启用使用 Pod 主机名的 Pod 间通信,你必须执行以下操作:

  1. 对于 Job 所创建的那些 Pod, 使用一个有效的标签选择算符创建无头服务。 该无头服务必须位于与该 Job 相同的名字空间内。 实现这一目的的一种简单的方式是使用 job-name: <任务名称> 作为选择算符, 因为 job-name 标签将由 Kubernetes 自动添加。 此配置将触发 DNS 系统为运行 Job 的 Pod 创建其主机名的记录。

  2. 通过将以下值包括到你的 Job 模板规约中,针对该 Job 的 Pod,将无头服务配置为其子域服务:

    1. subdomain: <无头服务的名称>

示例

以下是启用通过 Pod 主机名来完成 Pod 间通信的 Job 示例。 只有在使用主机名成功 ping 通所有 Pod 之后,此 Job 才会结束。

说明:

在以下示例中的每个 Pod 中执行的 Bash 脚本中,如果需要从名字空间外到达 Pod, Pod 主机名也可以带有该名字空间作为前缀。

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: headless-svc
  5. spec:
  6. clusterIP: None # clusterIP 必须为 None 以创建无头服务
  7. selector:
  8. job-name: example-job # 必须与 Job 名称匹配
  9. ---
  10. apiVersion: batch/v1
  11. kind: Job
  12. metadata:
  13. name: example-job
  14. spec:
  15. completions: 3
  16. parallelism: 3
  17. completionMode: Indexed
  18. template:
  19. spec:
  20. subdomain: headless-svc # 必须与 Service 名称匹配
  21. restartPolicy: Never
  22. containers:
  23. - name: example-workload
  24. image: bash:latest
  25. command:
  26. - bash
  27. - -c
  28. - |
  29. for i in 0 1 2
  30. do
  31. gotStatus="-1"
  32. wantStatus="0"
  33. while [ $gotStatus -ne $wantStatus ]
  34. do
  35. ping -c 1 example-job-${i}.headless-svc > /dev/null 2>&1
  36. gotStatus=$?
  37. if [ $gotStatus -ne $wantStatus ]; then
  38. echo "Failed to ping pod example-job-${i}.headless-svc, retrying in 1 second..."
  39. sleep 1
  40. fi
  41. done
  42. echo "Successfully pinged pod: example-job-${i}.headless-svc"
  43. done

应用上述示例之后,使用 <Pod 主机名>.<无头服务名> 通过网络到达彼此。 你应看到类似以下的输出:

  1. kubectl logs example-job-0-qws42
  1. Failed to ping pod example-job-0.headless-svc, retrying in 1 second...
  2. Successfully pinged pod: example-job-0.headless-svc
  3. Successfully pinged pod: example-job-1.headless-svc
  4. Successfully pinged pod: example-job-2.headless-svc

说明:

谨记此例中使用的 <Pod 主机名>.<无头服务名称> 名称格式不适用于设置为 NoneDefault 的 DNS 策略。 你可以在此处了解有关 Pod DNS 策略的更多信息。