有没有办法向 kube-dns 添加任意记录?
Is there a way to add arbitrary records to kube-dns?
我会用一种非常具体的方式来解释我的问题,但我认为这比用抽象的方式解释更好...
比如说,在 Kubernetes 集群之外但在网络中有一个 MongoDB 副本集。副本集所有成员的 ip 地址由应用服务器和数据库服务器中的 /etc/hosts 解析。
在 experiment/transition 阶段,我需要从 kubernetes pods 访问那些 mongo 数据库服务器。
但是,kubernetes 似乎不允许在 pods/containers.
中向 /etc/hosts 添加自定义条目
MongoDB 副本集已经在处理大型数据集,因此无法在集群中创建新的副本集。
因为我使用 GKE,所以我想应该避免更改 kube-dns 命名空间中的任何资源。配置或替换 kube-dns 以适合我的需要是最后一件事。
有没有办法在 Kubernetes 集群中解析自定义主机名的 IP 地址?
这只是一个想法,但如果kube2sky可以读取configmap的一些条目并将它们用作dns记录,那就太好了。
例如repl1.mongo.local: 192.168.10.100
.
中引用了这个问题
更新:2017-07-03 Kunbernetes 1.7 现在支持 Adding entries to Pod /etc/hosts with HostAliases。
解决方案不是关于 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
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
别忘了chmod a+x ensure_hosts.sh
。
3) 添加包装器脚本start.sh
你的图片
#!/bin/sh
$(dirname "$(realpath "[=12=]")")/ensure_hosts.sh &
exec your-app args...
别忘了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
...
使用 configMap 似乎是设置 DNS 的更好方法,但是当只添加几条记录时(在我看来)它有点重。所以我通过 docker CMD
.
执行的 shell 脚本将记录添加到 /etc/hosts
例如:
Docker 文件
...(ignore)
COPY run.sh /tmp/run.sh
CMD bash /tmp/run.sh
run.sh
#!/bin/bash
echo repl1.mongo.local 192.168.10.100 >> /etc/hosts
# some else command...
注意,如果你的运行一个pod中有多个容器,你必须在每个容器中添加脚本,因为kubernetes随机启动容器,/etc/hosts
可能会被另一个容器覆盖(稍后启动)。
作为记录,对于那些不检查引用 github issue 的人的替代解决方案。
您可以在 Kubernetes 中定义一个 "external" 服务,无需指定任何选择器或 ClusterIP。您还必须定义一个指向您的外部 IP 的相应端点。
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "my-service"
},
"spec": {
"ports": [
{
"protocol": "TCP",
"port": 80,
"targetPort": 9376
}
]
}
}
{
"kind": "Endpoints",
"apiVersion": "v1",
"metadata": {
"name": "my-service"
},
"subsets": [
{
"addresses": [
{ "ip": "1.2.3.4" }
],
"ports": [
{ "port": 9376 }
]
}
]
}
有了这个,您可以将容器内的应用程序指向 my-service:9376
,流量应该被转发到 1.2.3.4:9376
限制:
- 使用的 DNS 名称必须只能是字母、数字或破折号。您不能使用 multi-level 个名称 (
something.like.this
)。这意味着您可能必须修改您的应用程序以仅指向 your-service
,而不是 yourservice.domain.tld
.
- 您只能指向特定的 IP,不能指向 DNS 名称。为此,您可以定义一种具有
ExternalName
类型服务的 DNS 别名。
访问 kubernetes 之外的主机或 ips 需要一种外部名称。
以下对我有用。
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "tiny-server-5",
"namespace": "default"
},
"spec": {
"type": "ExternalName",
"externalName": "192.168.1.15",
"ports": [{ "port": 80 }]
}
}
这个问题现在有 2 种可能的解决方案:
- Pod-wise(将更改添加到解析这些域所需的每个 pod)
- 集群方式(将更改添加到所有 pods 都可以访问的中心位置,在我们的例子中是
DNS
)
让我们从 pod-wise 解决方案开始:
从 Kunbernetes 1.7 开始,现在可以直接使用 .spec.hostAliases
将条目添加到 Pod 的 /etc/hosts
例如:将foo.local
、bar.local
解析为127.0.0.1
和foo.remote
,
bar.remote
到 10.1.2.3
,您可以为 Pod 配置 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"
集群解决方案:
从 Kubernetes v1.12 开始,CoreDNS
是推荐的 DNS 服务器,替换 kube-dns.
如果您的集群最初使用 kube-dns
,您可能仍然部署了 kube-dns
而不是 CoreDNS
。我假设您使用 CoreDNS
作为您的 K8S DNS。
在 CoreDNS 中,可以在集群域内添加任意条目,这样所有 pods 将直接从 DNS 解析此条目,而无需更改每个 /etc/hosts
文件每个豆荚。
第一个:
让我们更改 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
基本上我们添加了两件事:
在kubernetes
插件之前的hosts
插件和使用hosts
插件的fallthrough
选项来满足我们的情况。
进一步阐明 fallthrough
选项。任何给定的后端通常是其区域的最终词 - 它要么是 returns 结果,要么是 returns NXDOMAIN
询问。然而,有时这不是我们想要的行为,因此一些插件支持 fallthrough
选项。
当启用 fallthrough
时,当没有找到记录时,插件不会返回 NXDOMAIN,而是通过
请求链下。链下游的后端有机会处理请求,在我们的例子中,后端是 kubernetes
.
我们向 ConfigMap (customdomains.db
) 添加了一个新文件,并在其中添加了我们的自定义域 (mongo-en-*.example.org
)。
最后一件事是记住将 customdomains.db
文件添加到 CoreDNS pod 模板的 config-volume
中:
kubectl edit -n kube-system deployment coredns
volumes:
- name: config-volume
configMap:
name: coredns
items:
- key: Corefile
path: Corefile
- key: customdomains.db
path: customdomains.db
最后让 kubernetes 重新加载 CoreDNS(每个 pod 运行):
$ kubectl rollout restart -n kube-system deployment/coredns
@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
}
您仍然需要重新启动 coredns,以便它重新读取配置:
$ kubectl rollout restart -n kube-system deployment/coredns
内联主机文件的内容消除了从 configmap 映射主机文件的需要。两种方法都达到相同的结果,至于要定义主机的位置取决于个人喜好。
我会用一种非常具体的方式来解释我的问题,但我认为这比用抽象的方式解释更好...
比如说,在 Kubernetes 集群之外但在网络中有一个 MongoDB 副本集。副本集所有成员的 ip 地址由应用服务器和数据库服务器中的 /etc/hosts 解析。
在 experiment/transition 阶段,我需要从 kubernetes pods 访问那些 mongo 数据库服务器。 但是,kubernetes 似乎不允许在 pods/containers.
中向 /etc/hosts 添加自定义条目MongoDB 副本集已经在处理大型数据集,因此无法在集群中创建新的副本集。
因为我使用 GKE,所以我想应该避免更改 kube-dns 命名空间中的任何资源。配置或替换 kube-dns 以适合我的需要是最后一件事。
有没有办法在 Kubernetes 集群中解析自定义主机名的 IP 地址?
这只是一个想法,但如果kube2sky可以读取configmap的一些条目并将它们用作dns记录,那就太好了。
例如repl1.mongo.local: 192.168.10.100
.
更新:2017-07-03 Kunbernetes 1.7 现在支持 Adding entries to Pod /etc/hosts with HostAliases。
解决方案不是关于 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
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
别忘了chmod a+x ensure_hosts.sh
。
3) 添加包装器脚本start.sh
你的图片
#!/bin/sh
$(dirname "$(realpath "[=12=]")")/ensure_hosts.sh &
exec your-app args...
别忘了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
...
使用 configMap 似乎是设置 DNS 的更好方法,但是当只添加几条记录时(在我看来)它有点重。所以我通过 docker CMD
.
/etc/hosts
例如:
Docker 文件
...(ignore)
COPY run.sh /tmp/run.sh
CMD bash /tmp/run.sh
run.sh
#!/bin/bash
echo repl1.mongo.local 192.168.10.100 >> /etc/hosts
# some else command...
注意,如果你的运行一个pod中有多个容器,你必须在每个容器中添加脚本,因为kubernetes随机启动容器,/etc/hosts
可能会被另一个容器覆盖(稍后启动)。
作为记录,对于那些不检查引用 github issue 的人的替代解决方案。
您可以在 Kubernetes 中定义一个 "external" 服务,无需指定任何选择器或 ClusterIP。您还必须定义一个指向您的外部 IP 的相应端点。
{ "kind": "Service", "apiVersion": "v1", "metadata": { "name": "my-service" }, "spec": { "ports": [ { "protocol": "TCP", "port": 80, "targetPort": 9376 } ] } } { "kind": "Endpoints", "apiVersion": "v1", "metadata": { "name": "my-service" }, "subsets": [ { "addresses": [ { "ip": "1.2.3.4" } ], "ports": [ { "port": 9376 } ] } ] }
有了这个,您可以将容器内的应用程序指向 my-service:9376
,流量应该被转发到 1.2.3.4:9376
限制:
- 使用的 DNS 名称必须只能是字母、数字或破折号。您不能使用 multi-level 个名称 (
something.like.this
)。这意味着您可能必须修改您的应用程序以仅指向your-service
,而不是yourservice.domain.tld
. - 您只能指向特定的 IP,不能指向 DNS 名称。为此,您可以定义一种具有
ExternalName
类型服务的 DNS 别名。
访问 kubernetes 之外的主机或 ips 需要一种外部名称。
以下对我有用。
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "tiny-server-5",
"namespace": "default"
},
"spec": {
"type": "ExternalName",
"externalName": "192.168.1.15",
"ports": [{ "port": 80 }]
}
}
这个问题现在有 2 种可能的解决方案:
- Pod-wise(将更改添加到解析这些域所需的每个 pod)
- 集群方式(将更改添加到所有 pods 都可以访问的中心位置,在我们的例子中是
DNS
)
让我们从 pod-wise 解决方案开始:
从 Kunbernetes 1.7 开始,现在可以直接使用 .spec.hostAliases
/etc/hosts
例如:将foo.local
、bar.local
解析为127.0.0.1
和foo.remote
,
bar.remote
到 10.1.2.3
,您可以为 Pod 配置 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"
集群解决方案:
从 Kubernetes v1.12 开始,CoreDNS
是推荐的 DNS 服务器,替换 kube-dns.
如果您的集群最初使用 kube-dns
,您可能仍然部署了 kube-dns
而不是 CoreDNS
。我假设您使用 CoreDNS
作为您的 K8S DNS。
在 CoreDNS 中,可以在集群域内添加任意条目,这样所有 pods 将直接从 DNS 解析此条目,而无需更改每个 /etc/hosts
文件每个豆荚。
第一个:
让我们更改 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
基本上我们添加了两件事:
在
kubernetes
插件之前的hosts
插件和使用hosts
插件的fallthrough
选项来满足我们的情况。进一步阐明
fallthrough
选项。任何给定的后端通常是其区域的最终词 - 它要么是 returns 结果,要么是 returns NXDOMAIN 询问。然而,有时这不是我们想要的行为,因此一些插件支持fallthrough
选项。 当启用fallthrough
时,当没有找到记录时,插件不会返回 NXDOMAIN,而是通过 请求链下。链下游的后端有机会处理请求,在我们的例子中,后端是kubernetes
.我们向 ConfigMap (
customdomains.db
) 添加了一个新文件,并在其中添加了我们的自定义域 (mongo-en-*.example.org
)。
最后一件事是记住将 customdomains.db
文件添加到 CoreDNS pod 模板的 config-volume
中:
kubectl edit -n kube-system deployment coredns
volumes:
- name: config-volume
configMap:
name: coredns
items:
- key: Corefile
path: Corefile
- key: customdomains.db
path: customdomains.db
最后让 kubernetes 重新加载 CoreDNS(每个 pod 运行):
$ kubectl rollout restart -n kube-system deployment/coredns
@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
}
您仍然需要重新启动 coredns,以便它重新读取配置:
$ kubectl rollout restart -n kube-system deployment/coredns
内联主机文件的内容消除了从 configmap 映射主机文件的需要。两种方法都达到相同的结果,至于要定义主机的位置取决于个人喜好。