⚙️

k8s StatefulSet における Pod IP が DNS から引けない条件

2021/10/28に公開

概要

とある要件で 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