• 给 Pod 添加 DNS 记录


    我们都知道 StatefulSet 中的 Pod 是拥有单独的 DNS 记录的,比如一个 StatefulSet 名称为 etcd,而它关联的 Headless SVC 名称为 etcd-headless,那么 CoreDNS 就会为它的每个 Pod 解析如下的 A 记录:

    • etcd-0.etcd-headless.default.svc.cluster.local
    • etcd-1.etcd-headless.default.svc.cluster.local
    • ……

    那么除了 StatefulSet 管理的 Pod 之外,其他的 Pod 是否也可以生成 DNS 记录呢?

    如下所示,我们这里只有一个 Headless 的 SVC,并没有 StatefulSet 管理的 Pod,而是 ReplicaSet 管理的 Pod,我们可以看到貌似也生成了类似于 StatefulSet 中的解析记录。

    这是怎么做到的呢?按照我们常规的理解会认为这是一个 StatefulSet 管理的 Pod,但其实这里是不同的 ReplicaSet 而已。这里的实现其实是因为 Pod 自己本身也是可以有自己的 DNS 记录的,所以我们是可以去实现一个类似于 StatefulSet 的 Pod 那样的解析记录的。

    首先我们来部署一个 Deployment 管理的普通应用,其定义如下:

    1. # nginx.yaml
    2. apiVersion: apps/v1
    3. kind: Deployment
    4. metadata:
    5. name: nginx
    6. spec:
    7. selector:
    8. matchLabels:
    9. app: nginx
    10. replicas: 2
    11. template:
    12. metadata:
    13. labels:
    14. app: nginx
    15. spec:
    16. containers:
    17. - name: nginx
    18. image: nginx:1.7.9
    19. ports:
    20. - containerPort: 80

    部署后创建了两个 Pod:

    1. $ kubectl apply -f nginx.yaml
    2. deployment.apps/nginx created
    3. $ kubectl get pod -l app=nginx -o wide
    4. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    5. nginx-5d59d67564-2cwdz 1/1 Running 0 19s 10.244.1.68 node1 <none> <none>
    6. nginx-5d59d67564-bp5br 1/1 Running 0 19s 10.244.2.209 node2 <none> <none>

    然后定义如下的 Headless Service:

    1. # service.yaml
    2. apiVersion: v1
    3. kind: Service
    4. metadata:
    5. name: nginx
    6. spec:
    7. clusterIP: None
    8. ports:
    9. - name: http
    10. port: 80
    11. protocol: TCP
    12. selector:
    13. app: nginx
    14. type: ClusterIP

    创建该 service,并尝试解析 service DNS:

    1. $ kubectl apply -f ervice.yaml
    2. service/nginx created
    3. $ kubectl get svc
    4. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    5. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 38d
    6. nginx ClusterIP None <none> 80/TCP 7s
    7. $ dig @10.96.0.10 nginx.default.svc.cluster.local
    8. ; <<>> DiG 9.9.4-RedHat-9.9.4-73.el7_6 <<>> @10.96.0.10 nginx.default.svc.cluster.local
    9. ; (1 server found)
    10. ;; global options: +cmd
    11. ;; Got answer:
    12. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2573
    13. ;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
    14. ;; WARNING: recursion requested but not available
    15. ;; OPT PSEUDOSECTION:
    16. ; EDNS: version: 0, flags:; udp: 4096
    17. ;; QUESTION SECTION:
    18. ;nginx.default.svc.cluster.local. IN A
    19. ;; ANSWER SECTION:
    20. nginx.default.svc.cluster.local. 30 IN A 10.244.2.209
    21. nginx.default.svc.cluster.local. 30 IN A 10.244.1.68
    22. ;; Query time: 19 msec
    23. ;; SERVER: 10.96.0.10#53(10.96.0.10)
    24. ;; WHEN: Wed Nov 25 11:44:41 CST 2020
    25. ;; MSG SIZE rcvd: 154

    然后我们对 nginx 的 FQDN 域名进行 dig 操作,可以看到返回了多条 A 记录,每一条对应一个 Pod。上面 dig 命令中使用的 10.96.0.10 就是 kube-dns 的 cluster IP,可以在 kube-system namespace 中查看:

    1. $ kubectl -n kube-system get svc
    2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    3. kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 52m

    接下来我们试试在 service 名字前面加上 Pod 名字交给 kube-dns 做解析:

    1. $ dig @10.96.0.10 nginx-5d59d67564-bp5br.nginx.default.svc.cluster.local
    2. ; <<>> DiG 9.9.4-RedHat-9.9.4-73.el7_6 <<>> @10.96.0.10 nginx-5d59d67564-bp5br.nginx.default.svc.cluster.local
    3. ; (1 server found)
    4. ;; global options: +cmd
    5. ;; Got answer:
    6. ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 10485
    7. ;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
    8. ;; WARNING: recursion requested but not available
    9. ;; OPT PSEUDOSECTION:
    10. ; EDNS: version: 0, flags:; udp: 4096
    11. ;; QUESTION SECTION:
    12. ;nginx-5d59d67564-bp5br.nginx.default.svc.cluster.local. IN A
    13. ;; AUTHORITY SECTION:
    14. cluster.local. 30 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1606275807 7200 1800 86400 30
    15. ;; Query time: 4 msec
    16. ;; SERVER: 10.96.0.10#53(10.96.0.10)
    17. ;; WHEN: Wed Nov 25 11:47:31 CST 2020
    18. ;; MSG SIZE rcvd: 176

    可以看到并没有得到解析结果。官方文档中有一段 Pod’s hostname and subdomain fields 说明:

    Pod 规约中包含一个可选的 hostname 字段,可以用来指定 Pod 的主机名。 当这个字段被设置时,它将优先于 Pod 的名字成为该 Pod 的主机名。 举个例子,给定一个 hostname 设置为 “my-host” 的 Pod, 该 Pod 的主机名将被设置为 “my-host”。Pod 规约还有一个可选的 subdomain 字段,可以用来指定 Pod 的子域名。 举个例子,某 Pod 的 hostname 设置为 “foo”,subdomain 设置为 “bar”, 在名字空间 “my-namespace” 中对应的完全限定域名(FQDN)为 “foo.bar.my-namespace.svc.cluster-domain.example”

    现在我们编辑一下 nginx.yaml 加上 subdomain 测试下看看:

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. name: nginx
    5. spec:
    6. selector:
    7. matchLabels:
    8. app: nginx
    9. replicas: 2
    10. template:
    11. metadata:
    12. labels:
    13. app: nginx
    14. spec:
    15. subdomain: nginx
    16. containers:
    17. - name: nginx
    18. image: nginx:1.7.9
    19. ports:
    20. - containerPort: 80

    更新部署再尝试解析 Pod DNS:

    1. $ kubectl apply -f nginx.yaml
    2. $ kubectl get pod -l app=nginx -o wide
    3. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    4. nginx-78f58d8bcb-6kctm 1/1 Running 0 8s 10.244.2.210 node2 <none> <none>
    5. nginx-78f58d8bcb-6tbnv 1/1 Running 0 15s 10.244.1.69 node1 <none> <none>
    6. $ dig @10.96.0.10 nginx-78f58d8bcb-6kctm.nginx.default.svc.cluster.local
    7. ; <<>> DiG 9.9.4-RedHat-9.9.4-73.el7_6 <<>> @10.96.0.10 nginx-78f58d8bcb-6kctm.nginx.default.svc.cluster.local
    8. ; (1 server found)
    9. ;; global options: +cmd
    10. ;; Got answer:
    11. ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 34172
    12. ;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
    13. ;; WARNING: recursion requested but not available
    14. ;; OPT PSEUDOSECTION:
    15. ; EDNS: version: 0, flags:; udp: 4096
    16. ;; QUESTION SECTION:
    17. ;nginx-78f58d8bcb-6kctm.nginx.default.svc.cluster.local. IN A
    18. ;; AUTHORITY SECTION:
    19. cluster.local. 30 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1606276303 7200 1800 86400 30
    20. ;; Query time: 2 msec
    21. ;; SERVER: 10.96.0.10#53(10.96.0.10)
    22. ;; WHEN: Wed Nov 25 11:52:18 CST 2020
    23. ;; MSG SIZE rcvd: 176

    可以看到依然不能解析,那就试试官方文档中的例子 ,不用 Deployment 直接创建 Pod 吧。第一步先将 hostname 和 subdomain 注释掉:

    1. # individual-pods-example.yaml
    2. apiVersion: v1
    3. kind: Service
    4. metadata:
    5. name: default-subdomain
    6. spec:
    7. selector:
    8. name: busybox
    9. clusterIP: None
    10. ports:
    11. - name: foo # Actually, no port is needed.
    12. port: 1234
    13. targetPort: 1234
    14. ---
    15. apiVersion: v1
    16. kind: Pod
    17. metadata:
    18. name: busybox1
    19. labels:
    20. name: busybox
    21. spec:
    22. hostname: busybox-1
    23. subdomain: default-subdomain
    24. containers:
    25. - image: busybox:1.28
    26. command:
    27. - sleep
    28. - "3600"
    29. name: busybox
    30. ---
    31. apiVersion: v1
    32. kind: Pod
    33. metadata:
    34. name: busybox2
    35. labels:
    36. name: busybox
    37. spec:
    38. hostname: busybox-2
    39. subdomain: default-subdomain
    40. containers:
    41. - image: busybox:1.28
    42. command:
    43. - sleep
    44. - "3600"
    45. name: busybox

    部署然后尝试解析 Pod DNS (注意这里 hostname 和 pod 的名字有区别,中间多了减号):

    1. $ kubectl apply -f individual-pods-example.yaml
    2. $ $ dig @10.96.0.10 busybox-1.default-subdomain.default.svc.cluster.local
    3. ; <<>> DiG 9.11.3-1ubuntu1.5-Ubuntu <<>> @10.96.0.10 busybox-1.default-subdomain.default.svc.cluster.local
    4. ; (1 server found)
    5. ;; global options: +cmd
    6. ;; Got answer:
    7. ;; WARNING: .local is reserved for Multicast DNS
    8. ;; You are currently testing what happens when an mDNS query is leaked to DNS
    9. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12636
    10. ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    11. ;; OPT PSEUDOSECTION:
    12. ; EDNS: version: 0, flags:; udp: 4096
    13. ; COOKIE: 5499ded915cf1ff2 (echoed)
    14. ;; QUESTION SECTION:
    15. ;busybox-1.default-subdomain.default.svc.cluster.local. IN A
    16. ;; ANSWER SECTION:
    17. busybox-1.default-subdomain.default.svc.cluster.local. 5 IN A 10.44.0.6
    18. ;; Query time: 0 msec
    19. ;; SERVER: 10.96.0.10#53(10.96.0.10)
    20. ;; WHEN: Fri Apr 19 15:27:38 CST 2019
    21. ;; MSG SIZE rcvd: 163

    现在我们看到有 ANSWER 记录回来了,hostname 和 subdomain 二者都必须显式指定,缺一不可。一开始我们的截图中的实现方式其实也是这种方式。

    现在我们修改一下之前的 nginx deployment 加上 hostname,重新解析:

    1. $ dig @10.96.0.10 nginx.nginx.default.svc.cluster.local
    2. ; <<>> DiG 9.9.4-RedHat-9.9.4-73.el7_6 <<>> @10.96.0.10 nginx.nginx.default.svc.cluster.local
    3. ; (1 server found)
    4. ;; global options: +cmd
    5. ;; Got answer:
    6. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21127
    7. ;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
    8. ;; WARNING: recursion requested but not available
    9. ;; OPT PSEUDOSECTION:
    10. ; EDNS: version: 0, flags:; udp: 4096
    11. ;; QUESTION SECTION:
    12. ;nginx.nginx.default.svc.cluster.local. IN A
    13. ;; ANSWER SECTION:
    14. nginx.nginx.default.svc.cluster.local. 30 IN A 10.244.2.211
    15. nginx.nginx.default.svc.cluster.local. 30 IN A 10.244.1.70
    16. ;; Query time: 1 msec
    17. ;; SERVER: 10.96.0.10#53(10.96.0.10)
    18. ;; WHEN: Wed Nov 25 11:55:37 CST 2020
    19. ;; MSG SIZE rcvd: 172

    可以看到解析成功了,但是因为 Deployment 中无法给每个 Pod 指定不同的 hostname,所以两个 Pod 有同样的 hostname,解析出来两个 IP,跟我们的本意就不符合了。

    不过知道了这种方式过后我们就可以自己去写一个 Operator 去直接管理 Pod 了,给每个 Pod 设置不同的 hostname 和一个 Headless SVC 名称的 subdomain,这样就相当于实现了 StatefulSet 中的 Pod 解析。

  • 相关阅读:
    buildAdmin 后端控制器的代码分析
    reticulate | R-python调用 | 安装及配置 | conda文件配置
    【Linux】时间同步
    word页脚设置,页脚显示第几页共有几页设置步骤
    JPBC的使用
    【opencv-c++】windows10系统安装OpenCV4.6.0
    排序算法详解(java代码实现)
    前端页面项目——博客系统
    INA 238 linux 驱动
    ECU-TEST 快速入门
  • 原文地址:https://blog.csdn.net/zfw_666666/article/details/126123711