k8s运维:设置Pod的集群内DNS方法

在k8s集群,我们通常通过 svc 做负载均衡来访问背后的 pod 实体,如果需要直接访问 pod 除了直接通过 pod IP 的方式还有什么方法呢?

首先我们需要知道,哪些对象具有DNS名字。

在k8s集群中每个Service都会有一个DNS名称,Services 包括两种,一种是普通的service服务,一种是 headless services。
普通的service 的DNS会解析到一个服务的集群IP,headless services 则会直接解析到所包含的pod的IP。

DNS 命名可以参考:https://github.com/kubernetes/dns/blob/master/docs/specification.md

service DNS 命名一般是:
<服务名>.<命名空间>.svc.cluster.local

下面是个案例:

apiVersion: v1
kind: Service
metadata:
name: nginx-test-headless
labels:
app: nginx-test
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx-test
---
apiVersion: v1
kind: Service
metadata:
name: nginx-test
labels:
app: nginx-test
spec:
ports:
- port: 80
name: web
type: ClusterIP
selector:
app: nginx-test
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx-test
statefulset.kubernetes.io/pod-name: web-test
name: web-test
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
name: web
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
hostname: web-test01
subdomain: nginx-test-headless

创建了一个headless service和一个普通的services,我们可以通过 kubectl 查看:

$ kubectl get svc | grep nginx-test
nginx-test ClusterIP 10.247.89.84 <none> 80/TCP 2m
nginx-test-headless ClusterIP None <none> 80/TCP 2m
$ kubectl get po web-test -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-test 1/1 Running 0 2m 10.0.2.156 10.213.20.91 <none> <none>

我们在集群内通过dig测试一下:

$ dig nginx-test.default.svc.cluster.local

; <<>> DiG 9.16.1-Ubuntu <<>> nginx-test.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18201
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 87477d087ad94e3a (echoed)
;; QUESTION SECTION:
;nginx-test.default.svc.cluster.local. IN A

;; ANSWER SECTION:
nginx-test.default.svc.cluster.local. 5 IN A 10.247.89.84

;; Query time: 0 msec
;; SERVER: 10.247.3.10#53(10.247.3.10)
;; WHEN: Wed Mar 10 13:16:03 UTC 2021
;; MSG SIZE rcvd: 129

$ dig nginx-test-headless.default.svc.cluster.local

; <<>> DiG 9.16.1-Ubuntu <<>> nginx-test-headless.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37124
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 38ab01af006bccc0 (echoed)
;; QUESTION SECTION:
;nginx-test-headless.default.svc.cluster.local. IN A

;; ANSWER SECTION:
nginx-test-headless.default.svc.cluster.local. 5 IN A 10.0.2.156

;; Query time: 0 msec
;; SERVER: 10.247.3.10#53(10.247.3.10)
;; WHEN: Wed Mar 10 13:15:56 UTC 2021
;; MSG SIZE rcvd: 147

可以看到访问 nginx-test-headless.default.svc.cluster.local 的域名被解析到 pod 的ip,nginx-test.default.svc.cluster.local 解析的是 service 分配的集群IP。

如果service 对应的多个pod,那么如何定位到具体的pod呢,这里可以通过 pod 的hostnamesubdomain两个字段实现。
比如再加入一个pod:

apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx-test
statefulset.kubernetes.io/pod-name: web-test
name: web-test02
namespace: default
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
name: web
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
hostname: web-test02
subdomain: nginx-test-headless

通过 dig 查看:

$ dig nginx-test-headless.default.svc.cluster.local

; <<>> DiG 9.16.1-Ubuntu <<>> nginx-test-headless.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23884
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 97fb1608fcf0bdf7 (echoed)
;; QUESTION SECTION:
;nginx-test-headless.default.svc.cluster.local. IN A

;; ANSWER SECTION:
nginx-test-headless.default.svc.cluster.local. 5 IN A 10.0.2.156
nginx-test-headless.default.svc.cluster.local. 5 IN A 10.0.1.232

;; Query time: 0 msec
;; SERVER: 10.247.3.10#53(10.247.3.10)
;; WHEN: Wed Mar 10 13:57:22 UTC 2021
;; MSG SIZE rcvd: 208

发现被解析到两个 POD 的 IP, hostnamesubdomain会在 service 下面构建子域名,通过<hostname>.<subdomain>.<命名空间>.svc.cluster.local访问:

$ dig web-test01.nginx-test-headless.default.svc.cluster.local

; <<>> DiG 9.16.1-Ubuntu <<>> web-test01.nginx-test-headless.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23896
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 2213905f5ac299da (echoed)
;; QUESTION SECTION:
;web-test01.nginx-test-headless.default.svc.cluster.local. IN A

;; ANSWER SECTION:
web-test01.nginx-test-headless.default.svc.cluster.local. 5 IN A 10.0.2.157

;; Query time: 0 msec
;; SERVER: 10.247.3.10#53(10.247.3.10)
;; WHEN: Wed Mar 10 14:10:02 UTC 2021
;; MSG SIZE rcvd: 169

$ dig web-test02.nginx-test-headless.default.svc.cluster.local

; <<>> DiG 9.16.1-Ubuntu <<>> web-test02.nginx-test-headless.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7948
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 71b4649549ed2014 (echoed)
;; QUESTION SECTION:
;web-test02.nginx-test-headless.default.svc.cluster.local. IN A

;; ANSWER SECTION:
web-test02.nginx-test-headless.default.svc.cluster.local. 5 IN A 10.0.1.241

;; Query time: 0 msec
;; SERVER: 10.247.3.10#53(10.247.3.10)
;; WHEN: Wed Mar 10 14:09:11 UTC 2021
;; MSG SIZE rcvd: 169
$ ping nginx-test-headless.default.svc.cluster.local
PING nginx-test-headless.default.svc.cluster.local (10.0.2.156) 56(84) bytes of data.
64 bytes from 10-0-2-156.nginx-test-headless.default.svc.cluster.local (10.0.2.156): icmp_seq=1 ttl=64 time=0.129 ms
64 bytes from 10-0-2-156.nginx-test-headless.default.svc.cluster.local (10.0.2.156): icmp_seq=2 ttl=64 time=0.154 ms

k8s重的 statfulset 就是这种方法来指定具体的 pod,通过创建带 hostname 和 subdomain 的 pod,再配合 headless service 实现指向具体的pod

statefulset DNS命名示例:

集群域名 命名空间 服务名 StatefulSet StatefulSet DNS Pod 主机名 Pod DNS
cluster.local default nginx web nginx.default.svc.cluster.local web-0 web-0.nginx.default.svc.cluster.local
kube.local rcmd nginx web nginx.rcmd.svc.kube.local web-0 web-0.nginx.rcmd.svc.kube.local

pod的DNS

除了通过svc的方式访问 pod 外,Pod 会对应如下 DNS 名字解析:

<pod ip地址>.<命名空间>.pod.cluster.local

比如一个pod ip 是 172.26.3.7 的pod,在命名空间rcmd,DNS解析为172-26-3-7.rcmd.pod.cluster.local

不过这种 DNS 实用性比较低,因为如果有了 IP地址了,也不需要 DNS了。

shikanon wechat
欢迎您扫一扫,订阅我滴↑↑↑的微信公众号!