k8s StatefulSet における Pod IP が DNS から引けない条件
概要
とある要件で Pod の host, ip を固定・指定する必要が出てきたので k8s StatefulSet を使って実現しようとしたところ、特定の条件下で DNS 名での解決が出来ない現象に出くわしたのでメモとして残しておきます。
問題
StatefulSet で管理している Pod に対して Stable Network ID を用いて DNS での名前解決を行おうとしていました。
このときに Service の metadata.name
と StatefulSet の spec.serviceName
に対して異なる値が設定されていました。
この場合、 各 Pod から StatefulSet の Pod 名から IP を探すことができなくなります。
検証
k8s 公式の nginx の StatefulSet を用いて動作確認を行ってみます。
環境
▶ kubectl version
Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.0", GitCommit:"cb303e613a121a29364f75cc67d3d580833a7479", GitTreeState:"clean", BuildDate:"2021-04-08T21:15:16Z", GoVersion:"go1.16.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"19+", GitVersion:"v1.19.13-gke.1900", GitCommit:"ee714a7b695ca42b9bd0c8fe2c0159024cdcba5e", GitTreeState:"clean", BuildDate:"2021-08-11T09:19:42Z", GoVersion:"go1.15.13b5", Compiler:"gc", Platform:"linux/amd64"}
正常動作確認
この manifest をそのまま k8s にデプロイして Pod の IP を dig
で調べてみます。
manifest を k8s にデプロイした後、 Pod に exec してから以下のコマンドを実行します。
root@web-0:/# apt update && apt install -y dnsutils # dig をインストールする
root@web-0:/# dig web-1.nginx.default.svc.cluster.local # 別 Pod の IP を DNS 名から解決する
; <<>> DiG 9.10.3-P4-Ubuntu <<>> web-1.nginx.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15409
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;web-1.nginx.default.svc.cluster.local. IN A
;; ANSWER SECTION:
web-1.nginx.default.svc.cluster.local. 30 IN A 10.8.1.14
;; Query time: 1 msec
;; SERVER: 10.75.0.10#53(10.75.0.10)
;; WHEN: Thu Oct 28 06:02:16 UTC 2021
;; MSG SIZE rcvd: 71
サンプルをそのまま用いると DNS 名から Pod の IP を解決することが出来ました。
DNS 名解決出来ないパターン
先程の manifest を一部改変します。
StatefulSet の spec.serviceName
を Service の metadata.name
と異なる値を設定します。
*** 17,23 ****
metadata:
name: web
spec:
! serviceName: nginx
replicas: 2
selector:
matchLabels:
--- 17,23 ----
metadata:
name: web
spec:
! serviceName: nginx-sts
replicas: 2
selector:
matchLabels:
この状態で先程と同じ様にデプロイし、 Pod に exec して DNS 名での解決を試してみます。
root@web-0:/# apt update && apt install -y dnsutils # dig をインストールする
root@web-0:/# dig web-1.nginx.default.svc.cluster.local # 別 Pod の IP を DNS 名から解決する
; <<>> DiG 9.10.3-P4-Ubuntu <<>> web-1.nginx.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 64656
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;web-1.nginx.default.svc.cluster.local. IN A
;; AUTHORITY SECTION:
cluster.local. 60 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1635400800 28800 7200 604800 60
;; Query time: 1 msec
;; SERVER: 10.75.0.10#53(10.75.0.10)
;; WHEN: Thu Oct 28 06:07:31 UTC 2021
;; MSG SIZE rcvd: 148
ANSER SECTION
が空っぽになり、 DNS による名前解決が出来なくなりました。
解決方法
Service の metadata.name
と StatefulSet の spec.serviceName
を一致させる必要がある。
GitHub でも議論されています。
DNS entries not exposed for StatefulSet and headless service in Kubernetes 1.8 or 1.9
Discussion