基于 DNS 的 Kubernetes 服务发现的规范

概述

概述

参考:

任何基于 DNS 的以实现 Kubernetes 服务发现的实现工具,必须提供本规范描述的 Resource Record

DNS Records 类型包含以下几种:A/AAAA、SRV、PTR、CHAME。不同的 k8s 资源,其可用的 Record Type 也不相同。

Resource Records 规范

在下面的描述中,有几个占位符,表示如下含义:

  • <service> # service 对象的名字

  • <ns> # namesapce 的名字

  • <zone> # 集群域名(默认为 cluster.local)。

    • 集群域名可以通过 kubelet 的配置文件 clusterDomain 字段定义。
  • <ttl> # 一条 Record 的标准 DNS 存活时间

ClusterIP 类型 Service 的 RR 格式

参考:官方文档

现在假定一个 Service 对象名为 <service>,在名为 <ns> 名称空间,该 Service 对象的 CLUSTER-IP 为 <cluster-ip>。则 DNS 实现程序必须具有下列几种类型的 Records(记录)。

A/AAAA Record

如果 <service> 对象具有 <cluster-ip> 且为 IPv4 地址。

A 记录 格式<service>.<ns>.svc.<zone>. <ttl> IN A <cluster-ip>

  • 请求样例:
    • kubernetes.default.svc.cluster.local. IN A
  • 响应样例:
    • kubernetes.default.svc.cluster.local. 4 IN A 10.3.0.1

如果 <service> 对象具有 <cluster-ip> 且为 IPv6 地址。

AAAA 记录 格式<service>.<ns>.svc.<zone>. <ttl> IN AAAA <cluster-ip>

  • 请求样例:
    • kubernetes.default.svc.cluster.local. IN AAAA
  • 响应样例:
    • kubernetes.default.svc.cluster.local. 4 IN AAAA 2001:db8::1

SRV Record

PTR Record

总结

Service 域名与 Service 的 CLUSTER-IP 具有关联关系

Headless 类型的 Service 的 RR 格式

参考:官方文档 现在假定一个 Headless 类型的 Service 对象名为 <service>,在名为 <ns> 名称空间,没有 CLUSTER-IP,Service 关联的每个 Pod 的主机名为 <hostname>,每个 Pod 的 IP 地址为 <endpoint-ip>。则 DNS 实现程序必须具有下列几种类型的 Records(记录)。

A/AAAA Record

对于 Headless 类型的 Service,Service 对应的每个 endpoint 的 <endpoint-ip>(也就是 Pod 的 IP),都必须有一个 A 记录。如果 endpoint 不存在,则 DNS-Rcode 应该是 NXDOMAIN。并且,<endpoint-ip> 会对应两种 A 记录

  • 通过 Service 名称解析到 endpoint-ip 的 Record

  • 通过 Pod 主机名解析到 endpoint-ip 的 Record。注意,该记录只有在 Statefulset 生成的 Pod 才有效果。

针对 Service 名称的 A 记录格式<service>.<ns>.svc.<zone>. <ttl> IN A <endpoint-ip>

  • 请求样例:
    • headless.default.svc.cluster.local. IN A
  • 响应样例:
    • headless.default.svc.cluster.local. 4 IN A 10.3.0.1
    • headless.default.svc.cluster.local. 4 IN A 10.3.0.2
    • headless.default.svc.cluster.local. 4 IN A 10.3.0.3
    • ….. 有多少个 endpoint 就有多少个响应

注意:Headless 与 ClusterIP 类型的 Service 最大的不同在于下面的 Resource Record。说白了就是多了个子域名

除了上面的 A 记录,还必须要有这样一种 A 记录。Service 对应的 endpoint 的 <endpoint-ip>(也就是 Pod 的 IP),还必须有另一个 A 记录,该记录是 <endpoint-ip> 与 包含 <hostname>(也就是 Pod 的主机名) 的域名的对应关系。如果一个给定的 hostname 具有多个 IPv4 地址,则每个 IP 都要有一个 A 记录。

针对 Pod 主机名的 A 记录格式<hostname>.<service>.<ns>.svc.<zone>. <ttl> IN A <endpoint-ip>

  • 请求样例:
    • my-pet.headless.default.svc.cluster.local. IN A
  • 响应样例:
    • my-pet.headless.default.svc.cluster.local. 4 IN A 10.3.0.100

AAAA 记录格式

略,把 A 改为 AAAA,IPv4 改为 IPv6,与 ClusterIP 类型的 Service 的 A 和 AAAA 记录的对应关系一样。

SRV Record

PTR Record

总结

Service 域名 与 Service 关联的后端 Pod 的 IP 具有解析关系。

带主机名的域名与 Service 关联的后端 Pod 的 IP 具有解析关系

ExternalName 类型的 Service 的 RR 格式

  • CNAME Record:<service>.<ns>.svc.<zone>. <ttl> IN CNAME <ExtName>.
    • 请求样例:foo.default.svc.cluster.local. IN A
    • 响应样例:

示例:

# 在default名称空间中有一个名为 myapp 的 servcie ,ip 为 10.108.255.155
[root@master-1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        239d
myapp        NodePort    10.108.255.155   <none>        80:52202/TCP   6d10h
# 这个 default 名称空间下的 myapp 的 service,在coredns中记录的域名为 myapp.default.svc.cluster.local ,对应的ip为 10.108.255.155
[root@master-1 ~]# kubectl exec -it -n test myapp-5ccfc89896-zxljh -- /bin/bash
[root@myapp-5ccfc89896-zxljh /]# ping myapp.default
PING myapp.default.svc.cluster.local (10.108.255.155) 56(84) bytes of data.
64 bytes from myapp.default.svc.cluster.local (10.108.255.155): icmp_seq=1 ttl=64 time=0.030 ms

有两种类型的控制器,各自有两种类型的 Service。

root@desistdaydream:~# kubectl get svc -n logging
NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
log-bj-test-grafana            ClusterIP   10.103.6.159    <none>        80/TCP     2d4h
log-bj-test-grafana-headless   ClusterIP   None            <none>        80/TCP     4h37m
log-bj-test-loki               ClusterIP   10.102.159.19   <none>        3100/TCP   2d4h
log-bj-test-loki-headless      ClusterIP   None            <none>        3100/TCP   2d4h
root@desistdaydream:~# kubectl get pod -n logging -o wide
NAME                                   READY   STATUS    RESTARTS   AGE    IP             NODE               NOMINATED NODE   READINESS GATES
log-bj-test-grafana-7764f5b4d7-28ngk   2/2     Running   0          2d4h   10.244.2.129   master-3.bj-test   <none>           <none>
log-bj-test-loki-0                     1/1     Running   0          2d4h   10.244.1.211   master-2.bj-test   <none>           <none>

首先实验 ClusterIP 类型的 Service

~ # nslookup log-bj-test-grafana.logging.svc.cluster.local
......
Name: log-bj-test-grafana.logging.svc.cluster.local
Address: 10.103.6.159
~ # nslookup log-bj-test-loki.logging.svc.cluster.local
......
Name: log-bj-test-loki.logging.svc.cluster.local
Address: 10.102.159.19

实验 Headless 类型的 Service

# 解析 Service 名
~ # nslookup log-bj-test-grafana-headless.logging.svc.cluster.local
......
Name: log-bj-test-grafana-headless.logging.svc.cluster.local
Address: 10.244.2.129
~ # nslookup log-bj-test-loki-headless.logging.svc.cluster.local
......
Name: log-bj-test-loki-headless.logging.svc.cluster.local
Address: 10.244.1.211
# 解析主机名
~ # nslookup log-bj-test-grafana-7764f5b4d7-28ngk.log-bj-test-grafana-headless.logging.svc.cluster.local
......
** server can't find log-bj-test-grafana-7764f5b4d7-28ngk.log-bj-test-grafana-headless.logging.svc.cluster.local: NXDOMAIN
** server can't find log-bj-test-grafana-7764f5b4d7-28ngk.log-bj-test-grafana-headless.logging.svc.cluster.local: NXDOMAIN
~ # nslookup log-bj-test-loki-0.log-bj-test-loki-headless.logging.svc.cluster.local
......
Name: log-bj-test-loki-0.log-bj-test-loki-headless.logging.svc.cluster.local
Address: 10.244.1.211

SRV 记录

~ # nslookup _http-metrics._tcp.log-bj-test-loki-headless.logging.svc.cluster.local
......
Name: _http-metrics._tcp.log-bj-test-loki-headless.logging.svc.cluster.local
Address: 10.244.1.211

最后修改 May 13, 2024: tailscale, jq, clearup (4e49da16)