这是一种向kube-dns添加任意记录的方法吗?

hir*_*shi 11 kubernetes google-kubernetes-engine

我将使用非常具体的方式来解释问题,但我认为这比抽象问题更具体...

比如,在kubernetes集群之外但在网络中有一个mongo db副本集.副本集的所有成员的IP地址由app服务器和数据库服务器中的/ etc/hosts解析.

在实验/过渡阶段,我需要从kubernetes pod访问那些mongo db服务器.但是,kubernetes似乎不允许在pods /容器中向/ etc/hosts添加自定义条目.

mongo db副本集已经在处理大型数据集,因此无法在群集中创建新的副本集.

Becaseu我使用GKE,我想应该避免更改kube-dns命名空间中的任何资源.配置或替换kube-dns以适合我的需要是最后一件事.

是一种解决kubernetes集群中自定义主机名的IP地址的方法吗?

这只是一个想法,但是如果kube2sky可以读取一些configmap的条目并将它们用作dns记录,那么它就会很棒.例如repl1.mongo.local: 192.168.10.100.

编辑:我从https://github.com/kubernetes/kubernetes/issues/12337引用了这个问题

Stu*_*ham 27

@OxMH 的答案非常棒,可以为了简洁而简化。CoreDNS 允许您直接在主机插件中指定主机(https://coredns.io/plugins/hosts/#examples)。

因此,可以像这样编辑 ConfigMap:

$ kubectl edit cm coredns -n kube-system 


apiVersion: v1
kind: ConfigMap
data:
  Corefile: |
    .:53 {
        errors
        health {
          lameduck 5s
        }
        hosts {
          10.10.1.1 mongo-en-1.example.org
          10.10.1.2 mongo-en-2.example.org
          10.10.1.3 mongo-en-3.example.org
          10.10.1.4 mongo-en-4.example.org
          fallthrough
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . "/etc/resolv.conf"
        cache 30
        loop
        reload
        loadbalance
    }
Run Code Online (Sandbox Code Playgroud)

您仍然需要重新启动 coredns,以便它重新读取配置:

$ kubectl rollout restart -n kube-system deployment/coredns
Run Code Online (Sandbox Code Playgroud)

内联主机文件的内容消除了从配置映射映射主机文件的需要。两种方法都达到相同的结果,具体取决于您想要在哪里定义主机的个人喜好。


小智 12

访问kubernetes之外的主机或ips需要一种外部名称.

以下对我有用.

{
    "kind": "Service",
    "apiVersion": "v1",
    "metadata": {
        "name": "tiny-server-5",
        "namespace": "default"
    },
    "spec": {
        "type": "ExternalName",
        "externalName": "192.168.1.15",
        "ports": [{ "port": 80 }]
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不要使用这个!externalName 应该只指向外部名称,例如 DNS 记录。请参阅 K8S 文档中的注释:“ExternalName 接受 IPv4 地址字符串,但作为由数字组成的 DNS 名称,而不是 IP 地址。CoreDNS 或 ingress-nginx 不会解析类似于 IPv4 地址的 ExternalNames,因为 ExternalName 旨在指定一个规范的 DNS 名称。要硬编码 IP 地址,请考虑无头服务。” (https://kubernetes.io/docs/concepts/services-networking/service/#externalname)morallo 的回答是正确的。 (3认同)

Moh*_*med 8

这个问题现在有两种可能的解决方案:

  1. Pod-wise(将更改添加到解析这些域所需的每个 Pod)
  2. 集群方式(将更改添加到所有 pod 都可以访问的中心位置,在我们的例子中是DNS

让我们从 pod-wise 解决方案开始:

从 Kunbernetes 1.7 开始,现在可以/etc/hosts直接使用.spec.hostAliases

例如:要解决foo.localbar.local127.0.0.1foo.remotebar.remote10.1.2.3,你可以为下一个吊舱配置HOSTALIASES .spec.hostAliases

apiVersion: v1
kind: Pod
metadata:
  name: hostaliases-pod
spec:
  restartPolicy: Never
  hostAliases:
  - ip: "127.0.0.1"
    hostnames:
    - "foo.local"
    - "bar.local"
  - ip: "10.1.2.3"
    hostnames:
    - "foo.remote"
    - "bar.remote"
  containers:
  - name: cat-hosts
    image: busybox
    command:
    - cat
    args:
    - "/etc/hosts"
Run Code Online (Sandbox Code Playgroud)

Cluster-wise 解决方案:

从 Kubernetes v1.12 开始,CoreDNS是推荐的 DNS Server,替换掉kube-dns.如果您的集群最初使用的是kube-dns,您可能仍然kube-dns部署了而不是CoreDNS. 我将假设您使用的CoreDNS是 K8S DNS。

在 CoreDNS 中,可以在集群域内添加任意条目,这样所有 pod 将直接从 DNS 解析这些条目,而无需更改每个/etc/hostspod 中的每个文件。

第一的:

让我们更改 coreos ConfigMap 并添加所需的更改:

kubectl edit cm coredns -n kube-system 

apiVersion: v1
kind: ConfigMap
data:
  Corefile: |
    .:53 {
        errors
        health {
          lameduck 5s
        }
        hosts /etc/coredns/customdomains.db example.org {
          fallthrough
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . "/etc/resolv.conf"
        cache 30
        loop
        reload
        loadbalance
    }
  customdomains.db: |
    10.10.1.1 mongo-en-1.example.org
    10.10.1.2 mongo-en-2.example.org
    10.10.1.3 mongo-en-3.example.org
    10.10.1.4 mongo-en-4.example.org
Run Code Online (Sandbox Code Playgroud)

基本上我们添加了两件事:

  1. hosts在之前的插件kubernetes插件,使用fallthrough该选项的hosts插件来满足我们的情况。

    为该fallthrough选项提供更多信息。任何给定的后端通常是其区域的最终词——它要么返回结果,要么为查询返回 NXDOMAIN。但是,有时这不是所需的行为,因此某些插件支持一个fallthrough选项。当fallthrough启用的,而不是返回时找不到记录NXDOMAIN,插件将向下传递链中的请求。链下游的后端有机会处理请求,在我们的例子中,后端是kubernetes.

  2. 我们向 ConfigMap ( customdomains.db)添加了一个新文件,并在其中添加了我们的自定义域 ( mongo-en-*.example.org)。

最后一件事是记住将customdomains.db文件添加到config-volumeCoreDNS pod 模板:

kubectl edit -n kube-system deployment coredns
Run Code Online (Sandbox Code Playgroud)
volumes:
        - name: config-volume
          configMap:
            name: coredns
            items:
            - key: Corefile
              path: Corefile
            - key: customdomains.db
              path: customdomains.db
Run Code Online (Sandbox Code Playgroud)

最后向 CoreDNS 发出信号以正常重新加载(每个 pod 正在运行):

$ kubectl -n kube-system exec coredns-461002909-7mp96 -- kill -SIGUSR1 1
Run Code Online (Sandbox Code Playgroud)

  • 我刚刚发布了一个基于您的答案,但内联主机而不是在不同的文件中定义它们。我想知道您是否考虑过这种方法,以及是否有任何原因您更喜欢在单独的文件中定义主机。 (2认同)

hir*_*shi 5

更新:2017-07-03 Kunbernetes 1.7现在支持使用HostAliases将条目添加到Pod / etc / hosts中


解决方案不是关于kube-dns,而是/ etc / hosts。无论如何,到目前为止,以下技巧似乎仍然有效...

编辑:更改/ etc / hosts可能与kubernetes系统发生竞争。让它重试。

1)创建一个configMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: db-hosts
data:
  hosts: |
    10.0.0.1  db1
    10.0.0.2  db2
Run Code Online (Sandbox Code Playgroud)

2)添加名为的脚本ensure_hosts.sh

#!/bin/sh                                                                                                           
while true
do
    grep db1 /etc/hosts > /dev/null || cat /mnt/hosts.append/hosts >> /etc/hosts
    sleep 5
done
Run Code Online (Sandbox Code Playgroud)

别忘了chmod a+x ensure_hosts.sh

3)为start.sh图像添加包装脚本

#!/bin/sh
$(dirname "$(realpath "$0")")/ensure_hosts.sh &
exec your-app args...
Run Code Online (Sandbox Code Playgroud)

别忘了 chmod a+x start.sh

4)使用configmap作为卷并运行start.sh

apiVersion: extensions/v1beta1
kind: Deployment
...
spec:
  template:
    ...
    spec:
      volumes:
      - name: hosts-volume
        configMap:
          name: db-hosts
      ...
      containers:
        command:
        - ./start.sh
        ...
        volumeMounts:
        - name: hosts-volume
          mountPath: /mnt/hosts.append
        ...
Run Code Online (Sandbox Code Playgroud)

  • 对于临时部署来说,这是一个令人满意的技巧,可以进行快速而肮脏的更新。其他答案更好,尤其是@0xMH的答案 (2认同)

小智 5

作为记录,对于那些不检查引用的github问题的人,提供一个替代解决方案。

您可以通过不指定任何选择器或ClusterIP在Kubernetes中定义“外部”服务。您还必须定义一个指向您的外部IP的相应端点。

Kubernetes文档中

{
    “ kind”:“服务”,
    “ apiVersion”:“ v1”,
    “元数据”:{
        “名称”:“我的服务”
    },
    “规范”:{
        “端口”:[
            {
                “ protocol”:“ TCP”,
                “端口”:80,
                “ targetPort”:9376
            }
        ]
    }
}
{
    “ kind”:“端点”,
    “ apiVersion”:“ v1”,
    “元数据”:{
        “名称”:“我的服务”
    },
    “子集”:[
        {
            “地址”:[
                {“ ip”:“ 1.2.3.4”}
            ],
            “端口”:[
                {“端口”:9376}
            ]
        }
    ]
}

这样,您可以将您的应用指向容器内my-service:9376,并将流量转发至1.2.3.4:9376

局限性:

  • 使用的DNS名称只需是字母,数字或破折号。您不能使用多级名称(something.like.this)。这意味着您可能必须修改您的应用程序以使其指向your-service而不是yourservice.domain.tld
  • 您只能指向特定的IP,而不能指向DNS名称。为此,您可以使用ExternalName服务类型定义一种DNS别名。