如何向 Google 容器引擎 [GKE] 中的所有 pods 添加名称服务器?

How do I add a nameserver to all pods in Google Container Engine [GKE]?

我正在尝试将我的本地集群迁移到 GKE。为了促进这种转变,我需要能够解析遗留服务的名称。

假设 networking/VPN 是一个已解决的问题。

目前有没有办法用 GKE 做到这一点?

实际上我正在尝试向每个 /etc/resolv.conf

添加一个 NS

有效没有

如果您修改节点的 resolv.conf,pods 将继承更改。

但是,glibc 禁止使用超过 3 个名称服务器或超过 6 个搜索记录。

GCE VM 使用 2 个名称服务器和 3 个搜索来访问节点元数据和项目网络。 GKE 使用 1 个名称服务器和 3 个搜索。 剩下 0 个名称服务器和 0 个搜索。

看到这个问题:https://github.com/kubernetes/kubernetes/issues/9079 这个问题:https://github.com/kubernetes/kubernetes/issues/9132

我想对 Eric 所说的内容进行补充,并对其进行一些修改。

我们在 kubernetes 1.1 "settling period" 期间的一个认识是 resolv.conf 和解析器行为等方面并没有真正的规范。不同的解析器库做不同的事情,这给我们的用户带来了痛苦。

具体来说,一些常见的解析器假定所有 nameserver 都是可替代的,如果您有处理 DNS 命名空间不同部分的名称服务器,它们就会中断。我们决定,对于 kube 1.2,我们不会将多个 nameserver 行传递到容器中。相反,我们只传递 kube-dns 服务器,它处理 cluster.local 查询并将任何其他查询转发到 "upstream" 名称服务器。

我们怎么知道 "upstream" 是什么?我们使用节点的nameservers。每个 pod 都有一个 dnsPolicy 字段来管理这个选择。最终结果是容器在我们拥有的 resolv.conf 中看到一个 nameserver,并且该名称服务器处理整个 DNS 命名空间。

这实际上意味着您没有很好的钩子来插入您自己的名称服务器。您可以将 --cluster-dns 标志更改为 kubelets 以指向您自己的 DNS 服务器,然后该服务器将转发到 kube-dns,然后再转发到 "upstream"。问题是 GKE 并不真正支持以这种方式更改标志。 If/when 节点已更新,标志将消失以支持默认值。

可能的解决方案:

  • 让 kubelet 从集群内配置中读取它们的标志。这已经是记录计划,但不在 v1.2

  • 让 kube-dns 带一个标志来指示 "upstream" 是什么。 Kube-dns 是一个 "cluster addon",因此最终用户并不真正可变(我们将使用您的集群更新它并丢失您的更改)。

  • 让 kube-dns 从集群内配置中读取其标志,并获取一个指示 "upstream" 是什么的标志。这是一个可行的想法,但可能不适用于 v1.2(为时已晚)。 可能可以将其修补到 v1 中。2.x但这并不是真正的错误修复,而是一个功能。

  • 将您自己的 DNS 服务器放入每个节点上的 resolv.conf,以便 kube-dns 将您用作上游。我不认为 GKE 有办法配置这个不会在节点升级时丢失。您可以编写一个控制器,定期通过 SSH 连接到 VM 并将其写出,然后检查您的 kube-dns 容器是否正确。漂白

我认为正确的答案是使用集群内配置映射来通知 kubelet 或 DNS(或两者)。如果您认为这些可能是可行的答案(尽管存在时间问题),那么如果您打开一个 GitHub 问题进行讨论会很棒。它将在那里获得更多知名度。

我通过在 k8s 集群中设置 dnsmasq 服务并将除 dnsmasq 之外的所有 pods 名称服务器指向 dnsmasq 服务来解决这个问题。
dnsmasq 将根据域后缀将请求转发到正确的名称服务器。 因此内部和外部 vpn 查找都将起作用。

  1. 设置 dnsmasq 服务。
    pods 可以看起来像这样,确保它至少有 2 pods 因为它需要是 HA。

    apiVersion: v1
    kind: Pod
    metadata:
      name: dnsmasq
    spec:
      containers:
      - name: dnsmasq
        image: "andyshinn/dnsmasq:2.76"
        ports:
        - containerPort: 53
          hostPort: 53
          protocol: UDP
        - containerPort: 53
          hostPort: 53
          protocol: TCP
        args: [
          "-S", "/consul/10.3.20.86",
          "-S", "/consul/10.3.20.88",
          "-S", "/consul/10.3.20.90",
          "-S", "/your-vpn-domain.dom/10.3.128.22",
          "-S", "/your-vpn-domain.dom/10.3.128.23"
        ]
        securityContext:
          capabilities:
            add:
            - NET_ADMIN
    
  2. 添加 resolv-conf 配置映射。

    #!/bin/bash
    
    DNS_IP=$(kubectl get svc --template '{{.spec.clusterIP}}' dnsmasq)
    DNS_POD=$(kubectl get pod -n kube-system | grep -v kube-dns-autoscaler | grep ^kube-dns  | head -1 | awk '{ print ; }')
    DOMAIN=$(kubectl describe -n kube-system pod/${DNS_POD} | grep -- --domain= | sed -Ee 's/.*--domain=(.*)\..*//')
    SEARCH=$(kubectl exec -n kube-system  ${DNS_POD} -c kubedns -- cat /etc/resolv.conf | grep ^search | cut -d' '  -f2-)
    VPN_SEARCH="your-vpn-domain.dom"
    
    kubectl create -f - <<EOF
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: resolv-conf
    data:
      resolv.conf: |
        # This file is created by resolv-conf config map and points to the dnsmasq service.
        search default.svc.${DOMAIN} svc.${DOMAIN} ${DOMAIN} ${SEARCH} ${VPN_SEARCH}
        nameserver ${DNS_IP}
        ndots:5
    EOF
    
  3. 在您的 services/pods 中安装 cfgmap。 将此添加到您的 pods

      volumeMounts:
      - mountPath: /etc/resolv.conf
        name: resolv-conf
        subPath: resolv.conf
        readOnly: true
    volumes:
      - name: resolv-conf
        configMap:
          name: resolv-conf
    

这个解决方案可能会被认为有点丑陋,但目前没有太多其他选择。将来我希望看到 Google Cloud 或 kube-dns 的 dns 转发功能。

Google Cloud 不为指定的 domains/zones 提供 DNS 转发功能,这有点疯狂。