KubernetesでDNSが詰まってしまったときにやったこと

jagaNikumanPosted by

SREの岩立です。
Google Kubernetes Engineを使用して負荷試験を行っていたところ、DNS解決が詰まって応答が帰ってこないことによりアプリケーションがエラーを吐くことがありました。そのため、本記事ではこの問題に対してやったことについて書きます。

NodeLocal DNSCacheの導入

kube-dnsが詰まっている様子だったので、こちらのスライドで知ったDNSのノードローカルキャッシュを導入してみることにしました。
NodeLocal DNSCacheはKubernetes 1.15から利用できる機能です。DaemonSetとしてcorednsが配置され、各ノード内のDNS解決を一旦引き受けてキャッシュがある場合はそのまま返し、無い場合はkube-dnsへ問い合わせてくれます。

前のパラグラフで説明されている、DNS リクエストのパスの図
引用: https://cloud.google.com/kubernetes-engine/docs/how-to/nodelocal-dns-cache

導入方法はドキュメントを見ればわかりますが、一応以下にやったことを書き出していきます。

GKEの場合はNodeLocal DNSCacheがアドオンとして用意されているため、下記コマンドでアドオンを有効にするだけで自動で既存のクラスタに対してNodeLocal DNSCacheを導入出来ます。

$ gcloud beta container clusters update cluster-name --update-addons=NodeLocalDNS=ENABLED

導入できたかの確認は、以下のコマンドでPodが立ち上がっているか確認します。

$ kubectl get pods -n kube-system -o wide | grep node-local-dns
node-local-dns-6m2hh    1/1    Running   0     32d    10.146.0.4     gke-test-cluster-default-pool-5db8c06f-fgq6   <none>     <none>
node-local-dns-d9p7x    1/1    Running   0     32d    10.146.0.2     gke-test-cluster-default-pool-5db8c06f-400h   <none>     <none>
node-local-dns-n7r5n    1/1    Running   0     2d1h   10.146.0.106   gke-test-cluster-preemptible-9fa61719-gwq4    <none>     <none>
node-local-dns-nssc8    1/1    Running   0     22h    10.146.0.105   gke-test-cluster-preemptible-9fa61719-jbzw    <none>     <none>
node-local-dns-sv26b    1/1    Running   0     32d    10.146.0.3     gke-test-cluster-default-pool-5db8c06f-9wsf   <none>     <none>

導入はこれで完了となります。
この状態で再度負荷試験を行ったところ、確かにkube-dnsが詰まる問題は緩和されましたが、まだ若干詰まってしまう様子が見受けられました。もともとの割合からすると10%程エラーログが出てしまっていました。
そのため、追加でkube-dns自体のpodを増やすことを試してみました。

kube-dns-autoscalerの設定変更

kube-dnsのスケールはHorizontal Pod Autoscalerで行っているわけではなくkube-dns-autoscalerが担当しています。そして、replica数の決定に用いられる指標は以下のconfigmapで管理されています。

$ kubectl get configmap kube-dns-autoscaler -n kube-system -o yaml
apiVersion: v1
data:
  linear: '{"coresPerReplica":256,"nodesPerReplica":16,"preventSinglePointFailure":true}'
kind: ConfigMap
metadata:
  省略...

coresPerReplicaがコア数を元に、nodesPerReplicaがノード数を元にreplica数を決定する場合に用いられる指標になります。どちらの指標が使われるかに関してですが、各指標で計算した結果replica数が多い方になります。
そのため、8coreのnodeが100台あった場合は、800cores 100nodesの構成になりますが、coresPerReplicaで計算すると800/256なので約3replica、nodesPerReplicaで計算すると100/16なので約6replicaになり、nodesPerReplicaの場合の方がreplica数が多いため結果用意されるreplica数は6になります。

今回はノード数よりもコア数でreplica数を用意したほうがノードあたりのコア数が変わったときにも柔軟に対応できると思い、coresPerReplicaの値を調整することにしました。調整は該当パラメータの数値を変えてconfigmapを更新するだけです。すると変更された値を元にkube-dns-autoscalerがkube-dnsのreplica数を変えてくれます。

これを踏まえてやったこととしては、名前解決のエラーがなくなるまでcoresPerReplicaを変更してkube-dnsのreplica数を増やしていきました。

今回のアプリケーションの負荷試験の場合ですが、coresPerReplicaを30にすることで、名前解決のエラーを吐かずに負荷に耐えられるようになりました。もともとは256だったので、replica数を約8倍ほどに上げたことになります。

まとめ

今回はKubernetes上でDNSによる名前解決が詰まった場合に対処した方法について書きました。
大まかにまとめるとLocalNode DNSCacheによりkube-dnsへの問い合わせ数の削減、kube-dns-autoscalerのパラメータ見直しによるkube-dnsのreplica数を増加により対応することが出来ました。
この記事が誰かの助けになると嬉しいなと思います。