在应用开发中,我们不应把远程服务的 ip 硬编码到应用中。有些同学习惯使用域名来标定远程服务,通过修改解析,来区分开发测试和生产环境,这是一个挺好的习惯。在 k8s 系统中,我们使用服务名来调用服务,并通过 coredns 来进行解析。但那些集群外的服务,并且已经被硬编码的域名如何访问呢?

此文拷贝自自己的旧文章,为防止知识过期,在 aws eks 上重新验证成功。

方法1:修改容器实例的 hosts

设想:把 hosts 文件内容存储在 ConfigMap 中,通过 volume 绑定到 /etc/hosts。但很不幸,/etc/hosts 被 k8s 征用了,无法修改。

但 K8S 给我们提供了 hostAliases 来解决此问题。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hosts-append
  labels: 
    app: hosts-append
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hosts-append
  template:
    metadata:
      labels:
        app: hosts-append
    spec:
      hostAliases:
      - ip: "127.0.0.1"
        hostnames:
        - "foo.local"
        - "bar.local"
      - ip: "10.1.2.3"
        hostnames:
        - "foo.remote"
        - "bar.remote"
      containers:
      - image: nginx:alpine
        name: hosts-append
        ports:
        - containerPort: 80
          protocol: TCP

部署后,pod 里面的 hosts 文件已经追加了解析记录。查看结果如下:

kubectl exec hosts-append-<your-id> -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.10.6.23 hosts-append-6f96d5449f-rldxr

# Entries added by HostAliases.
127.0.0.1 foo.local bar.local
10.1.2.3 foo.remote bar.remote

此方法的缺点是:不同环境下的域名映射是不一样的,必须为环境编写不同的 yaml 部署文件,并且给每一个 deployment 编写 hostAliases 会有点“侵入”。

方法2:使用内置 coredns 解析

K8S 内部默认已经安装了 coredns 服务,可以通过修改 coredns 的配置来达到内部解析的目的。

coredns 的配置写在了 configmap 的 kube-system 命名空间下的 coredns 配置节点了。只需要修改 hosts 配置节点内容就好。

编辑他:

kubectl edit cm -n kube-system coredns

配置示例(其中 hosts 节点是自定义的解析节点,如果没有 hosts 节点,可以增加一个):

    .:53 {
        errors
        health
        kubernetes cluster.local. in-addr.arpa ip6.arpa {
            pods insecure
            upstream
            fallthrough in-addr.arpa ip6.arpa
        }
        hosts {
          127.0.0.1 foo.local
          8.8.8.8 foo.remote
          fallthrough
        }
        prometheus :9153
        proxy . /etc/resolv.conf
        cache 30
        reload
        loadbalance
    }

修改完成后,要等等。配置下发完成即可生效。可以进入 pod 内部 ping 一下域名看看。

方法3. 使用自定义域名服务器解析

在 coredns 的 ConfigMap 中,还可以自定义 name server,配置类似:

apiVersion: v1
kind: ConfigMap
metadata:
  annotations:
  labels:
    eks.amazonaws.com/component: coredns
    k8s-app: kube-dns
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health
        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
    }
    domain-name:53 {
        errors
        cache 30
        forward . custom-dns-server
        reload
    }
  • domain-name:53 节点中可以定义 name server
  • 如果没有这个节点,可以增加一个,此节点与 .:53 平级。

下面以 aws route53 为例进行测试。

首选进入 route53 控制台,进入 创建托管区。如图:

Create 53 Private Zone

创建完成可以看到解析记录里 name server,地址类似如下:

ns-1536.awsdns-00.co.uk.
ns-0.awsdns-00.com.
ns-1024.awsdns-00.org.
ns-512.awsdns-00.net.

并添加一个新解析 A 记录,如下图:

DNS result

编辑 ConfigMap,参考上面的配置,修改 K8S/EKS 的 name server

kubectl edit cm -n kube-system coredns

domain-name:53 节点设置 forward . ns-1536.awsdns-00.co.uk. 即可。

设置完成,进入 EKS 的 任意 pod 测试,ping 或者 dig 一下,结果如下:

# dig www.youbug.cn

; <<>> DiG 9.16.33-Debian <<>> www.youbug.cn
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42026
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: d032981648385382 (echoed)
;; QUESTION SECTION:
;www.youbug.cn.   IN A

;; ANSWER SECTION:
www.youbug.cn.  30 IN A 192.168.0.1

;; Query time: 0 msec
;; SERVER: 172.20.0.10#53(172.20.0.10)
;; WHEN: Wed Dec 07 02:39:49 UTC 2022
;; MSG SIZE  rcvd: 83

可以看到已经生效了。

其他云厂商的或者自建域名服务器可以使用类似方法,不一一赘述了。

使用场景总结

名称 方法 适用场景
hostAliases 修改 pod 的 hosts 配置 K8S 集群内部分 workloads 需要单独解析。开发者临时测试没有 ConfigMap 权限等。A/B Test。
coredns 直接解析 修改 ConfigMap 直接解析 完整的 K8S 开发测试环境,UAT 环境等
自定义 dns server 修改 ConfigMap 配置以使用自定义域名服务器 多 K8S 集群,有非 K8S 负载,VPC 范围解析

当然,更好的做法是把 配置文件与应用解耦,所有的配置,包括远程服务的域名或 ip 都可以被远程修改