【问题标题】:Pod name resolution for StatefulSet doesn't workStatefulSet 的 Pod 名称解析不起作用
【发布时间】:2021-12-03 05:15:46
【问题描述】:

我有一个带有 StatefulSet 的 following Kubernetes YAML,我用它来部署一个带有 Patroni 的 PostgreSQL 集群。然而,这个问题与 Kubernetes 如何在 CoreDNS 中注册 Pod 名称有关。

根据稳定网络 ID 部分中的this documentation,如果我为我的 Pod 创建一个名为 spilodemo-svc 的无头服务,我可以使用短主机名 (podname.servicename) 访问它们:

spilodemo-0.spilodemo-svc

基本上,我的代码在 VirtualBox 和 Vagrant 上使用 kubeadm 部署的 K8s 集群上正常运行了很长时间。今天我想在 IBM Cloud 上部署它,但上面的主机名不起作用,奇怪的是,当我再次在 Vagrant/VirtualBox 上重复测试时,我无法再让它工作了,我不知道为什么。

现在 YAML 部署 Spilo,它是 Zalando 开发的一个开源项目,它是一个带有 Patroni 和 PostgreSQL 的 Docker 镜像。我的代码来自他们的example here

基本上,他们创建了一个没有选择器的 ClusterIP 服务(而不是无头)。在这些情况下,Kubernetes 不会在其中创建 Endpoint。出于这个原因,我们在 YAML 中有一个与服务名称相同的 Endpoint(这似乎是 Kubernetes 期望的绑定)。

Spilo 的 Python 代码始终使用主节点的 IP 更新此 Endpoint。

StatefulSet 的字段 serviceName 等于服务的名称:

serviceName: spilodemo-svc

根据文档,这保证了 Kubernetes 在 CoreDNS 中为这个短主机名 (podname.servicename) 创建一个条目:

spilodemo-0.spilodemo-svc

它工作了很长时间,直到今天,同时没有发生任何事情。老实说,到目前为止,我还没有完全理解 DNS 名称 spilodemo-0.spilodemo-svc 是如何工作的,因为它使用 ClusterIP 服务而不是 Headless 服务。

另一个奇怪的事情是,Zalando 团队使用了另一个 Headless 服务,我称之为 spilodemo-config,根据他们代码中的注释,它应该避免 Kubernetes 删除端点,但这对我来说没有多大意义。

但是,今天我也尝试将服务转换为无头服务,删除spilodemo-config 但没有运气。 Kubernetes 只在 CoreDNS 中为服务创建入口:

spilodemo.spilons.svc.cluster.local

但不是每个 Pod 都有一个:

spilodemo-0.spilodemo-svc
spilodemo-1.spilodemo-svc
spilodemo-2.spilodemo-svc

谁能帮我弄清楚我的 YAML 文件发生了什么,以及如何让上面的三个短主机名在 CoreDNS 中工作?

PS 在 Stackoverflow 上,我发现了这些讨论:

【问题讨论】:

  • 我从这个文件github.com/zalando/spilo/blob/master/kubernetes/…重新开始做了一些实验。如果我按原样使用它,那么它就可以工作,但是如果我将我的 StatefulSet 放在命名空间 中,那么域 . 就不再工作了。命名空间如何影响 StatefulSet 域注册以使短名称 . 不再起作用?
  • 你用的是什么k8s版本?
  • 1.21 用于 kubectl 1.22 用于服务器
  • 看起来您正在使用没有选择器的无头服务,这意味着端点不是自动创建的,要解决此问题,您可能希望手动端点与无头服务同名。
  • 我会尽快发布我的问题的解决方案。它与 Patroni 的工作方式密切相关。

标签: kubernetes kubernetes-pod kubernetes-statefulset coredns patroni


【解决方案1】:

经过将近三天的测试,我找到了解决方案。解决方案取决于两件事:

  1. Kubernetes 的工作原理;
  2. Patroni 的工作原理。

Kubernetes 的工作原理

当您创建 StatefulSet 部署时(但部署也是如此),假设有 3 个 pod,Kubernetes 在 CoreDNS 中注册三个 DNS 名称:

IP-with-dashes.<namespace>.pod.cluster.local

但是,这些名称对我来说毫无用处,因为我无法在我的 YAML 文件中预先设置它们,因为它取决于分配给 Pod 的 Kubernetes 的 IP。

但是,对于 StatefulSet 部署,根据this documentation in the Stable Network ID section,如果我为我的 Pod 创建一个无头服务,我可以使用 FQDN (...svc.cluster.local) 的短主机名 (podname.servicename) 访问它们。

这是我需要创建的 Headless 服务:

---
apiVersion: v1
kind: Service
metadata:
  name: spilodemo-svc
  labels:
    application: spilo
    spilo-cluster: spilodemo
spec:
  clusterIP: None
  selector:
    application: spilo
    spilo-cluster: spilodemo

在这里设置选择器来绑定所有三个 pod 很重要。另一件重要的事情是将以下行添加到您的 StatefulSet 中,其名称等于无头服务:

serviceName: spilodemo-svc

这是 Kubernetes 部分。现在您可以使用 DNS 名称引用您的 Pod:

spilodemo-0.spilodemo-svc
spilodemo-1.spilodemo-svc
spilodemo-2.spilodemo-svc

或 FQDN:

spilodemo-0.spilodemo-svc.<namespace>.svc.cluster.local
spilodemo-1.spilodemo-svc.<namespace>.svc.cluster.local
spilodemo-2.spilodemo-svc.<namespace>.svc.cluster.local

Patroni 的工作原理

但是,使用 Pod 的 DNS 名称对客户端没有意义,因为它们需要单点访问。出于这个原因,Patroni 团队建议像这样创建一个 ClusterIP 服务:

---
apiVersion: v1
kind: Service
metadata:
  name: spilodemo
  labels:
    application: spilo
    spilo-cluster: spilodemo
spec:
  type: ClusterIP
  ports:
  - name: postgresql
    port: 5432
    targetPort: 5432

注意:没有选择器。这不是错误。当您创建这样的服务时,Kubernetes 会创建一个 ClusterIP 服务(然后可以使用 IP 或主机名来引用它)但没有端点。这意味着您连接到它的 IP 或它的 DNS 名称:spilodemo.&lt;namespace&gt;.svc.cluster.local,连接挂起。

因此,Patroni 团队要求您在 YAML 文件中添加以下与 ClusterIP 服务同名的端点。

apiVersion: v1
kind: Endpoints
metadata:
  name: spilodemo
  labels:
    application: spilo
    spilo-cluster: spilodemo
subsets: []

Patroni 在内部有一段 Python 代码,它通过 Kubernetes API 使用 Master Pod IP 更新此端点。 Patroni 能够使用您甚至可以自定义的上述相关标签(应用程序、spilo-cluster)来确定要更新的端点。

此时,Patroni 集群客户端只需要使用这个 DNS 名称(ClusterIP 之一)或相对 IP:

spilodemo.spilons.svc.cluster.local

连接会自动重定向到 Pod 主节点 IP。

到目前为止一切顺利。现在是令人困惑的部分。如果您查看 Spilo 代码中的 Patroni Kubernetes sample file,您的节点已经存在另一个无头服务。

---
# headless service to avoid deletion of patronidemo-config endpoint
apiVersion: v1
kind: Service
metadata:
  name: spilodemo-config
  labels:
    application: spilo
    spilo-cluster: spilodemo
spec:
  clusterIP: None

让我感到困惑的是这种无头服务的存在。我不明白它的目的。一开始,我以为是需要上面提到的 Pods DNS 名称的 headless 服务。但是我错了。这项服务的目的是不同的。基本上,Zalando 团队不知道用户如何编写 YAML 文件来部署 Patroni。如果用户创建了 Endpoint 但忘记将其关联到 Service,Kubernetes 会将其视为孤儿并将其删除。因此,Patroni 代码本身会自行创建此服务。事实上,如果你没有在 YAML 文件中定义它,Patroni 会为你创建它。

那么,如果 Patroni 为您创建了它,他们为什么要在上面的示例 YAML 中添加它?原因是权限。如果 Pod 没有权限,则无法创建它。这就是他们在 YAML 中添加它的原因。这有点令人困惑,但这就是全部。

【讨论】:

    猜你喜欢
    • 2020-07-23
    • 1970-01-01
    • 2023-03-05
    • 2019-02-06
    • 1970-01-01
    • 2019-04-14
    • 1970-01-01
    • 2020-10-21
    • 2023-02-22
    相关资源
    最近更新 更多