TT Lab
はじめる
学ぶ 学習パス コース

Kubernetesネットワーク — 本物のクラスタで

短い名前はタダではない

TT Labで続きを見る

一言でいうと

短い名前が便利な分の代償は、外へ出ていく名前を探すときに請求されます。ドットが5個未満の名前は、すべてsearchを先に回るからです。

Kubernetesでは、webとだけ書いても、同じネームスペースのServiceを見つけられます。便利です。ところが、その便利さには代償があり、その代償は、外へ出ていく名前を探すときに請求されます。

searchとndots

Podの/etc/resolv.confは、このような形です。

search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.43.0.10
options ndots:5

searchは、短い名前の後ろに順番に付けてみるサフィックスで、ndots:5は、ドットが5個未満の名前は、まだ完成した名前ではないかもしれないので、先にsearchを試すという意味です。

webはドットが0個なので、当然searchを使います。問題はexample.comです。ドットが1つだけなので、これも5未満で、そのため、この順序で問い合わせます。

example.com.default.svc.cluster.local   → NXDOMAIN
example.com.svc.cluster.local           → NXDOMAIN
example.com.cluster.local               → NXDOMAIN
example.com.                            → 드디어 응답

1回のリクエストで往復が4回、そのうち3回は捨てられます。

なぜメトリクスに現れないのか

DNSのルックアップは、アプリケーションコードではなく、その下のライブラリで行われます。そのため、アプリケーションのトレースにスパンが現れないことが多く、ユーザーには「少し遅いリクエスト」としか見えません。CoreDNSの負荷だけが静かに上がっていき、Podの数が増えたある日、限界に達します。

直せるが、無料ではない

Podごとに、dnsConfigでndotsを下げられます。ただし、そのPodは、短い名前でクラスターのServiceを見つけられなくなります。そのため、外へ出ていくリクエストが多いPodにだけ設定するのが正解です。クラスター内の通信が多いPodに設定すると、かえって損です。

なぜ往復が4回なのか

Podの/etc/resolv.confは、このような形です。

search labhub-prod.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

ndots:5は、ドットが5個未満の名前は、完成した名前ではないと見て、先にsearchを付けてみるという意味です。api.example.comはドットが2個なので、ここに引っかかります。

1. api.example.com.labhub-prod.svc.cluster.local  → NXDOMAIN
2. api.example.com.svc.cluster.local              → NXDOMAIN
3. api.example.com.cluster.local                  → NXDOMAIN
4. api.example.com                                → 응답    ← 네 번째에 성공

IPv6が有効なら、各クエリでAとAAAAを一緒に問い合わせるので、実際のクエリは8個です。外部のAPIを頻繁に呼ぶサービスで、CoreDNSの負荷の大半が、これです。

3つの対応と、それぞれの代償

方法 効果 代償
名前の末尾にドット(example.com.) searchを完全にスキップします コードを直す必要があります
Podにndots: 1 そのPodのすべての名前に適用されます 短い名前が使えなくなります
NodeLocal DNSCache ノードでキャッシュし、CoreDNSの負荷が急減します インストールと運用の負担があります

1行目が最も安く、安全です。ndotsをグローバルに下げない理由は、kubectlで確認できます。短い名前でServiceを呼ぶコードが、すべて壊れます。

# 파드 단위로만, 그 파드가 짧은 이름을 안 쓴다는 것을 확인하고
spec:
  dnsConfig:
    options:
      - name: ndots
        value: "1"

DNSの問題を診断するコマンド

# 파드 안에서 — 어느 단계에서 실패하는지 본다
nslookup api.example.com
nslookup api.example.com.        # 끝점을 찍으면 되는가?

# search 가 실제로 어떻게 붙는지
dig +search +short api.example.com

# CoreDNS 가 무엇을 받고 있나
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50 | grep NXDOMAIN

CoreDNSのログが空なら、Corefileにlogプラグインがないということです。調査するときだけ有効にして、無効に戻します。有効にしておくと、ログの量が多くなります。

症状別に見ると、こうなります。断続的な失敗は、たいていconntrackやUDPパケットの損失で、すべて失敗は、CoreDNSかネットワークポリシーで、遅いだけのものは、上のsearchの往復です。

実務で本当に大切なこと

外部のドメインを頻繁に呼ぶ場所には、末尾にドットを打ちます。example.com.のようにピリオドを付けると、完成した名前として扱われ、searchを丸ごとスキップします。コード1文字で往復が4回から1回になり、ndotsには触れないので、短い名前もそのまま使えます。

シグナルは、CoreDNSのクエリ数で探します。無駄なクエリも正常な応答(NXDOMAIN)なので、エラー率は上がりません。クエリ数がサービス呼び出し数より何倍も多ければ、それがこのコストを払っているという意味です。

ndotsは、絶対にグローバルには下げません。短い名前でクラスター内のServiceを呼ぶコードが、すべて壊れます。変えるなら、Pod単位で、そのPodが短い名前を使っていないことを確認してから行います。

トレードオフを知ることが、このテーマのすべてです。次のラボでクエリ数を自分で数えてみれば、この話が数字で手に取れます。