このページでは、NodeLocal DNSCache を使用して、Google Kubernetes Engine(GKE)クラスタの DNS ルックアップのレイテンシを改善する方法について説明します。
GKE Autopilot クラスタの場合、NodeLocal DNSCache はデフォルトで有効になっており、オーバーライドできません。
アーキテクチャ
NodeLocal DNSCache は、kube-dns に加えて実行できる GKE アドオンです。
GKE では、NodeLocal DNSCache はクラスタ内の各ノードで DNS キャッシュを実行する DaemonSet として実装されます。
Pod が DNS リクエストを行うと、そのリクエストは、Pod と同じノード上で実行されている DNS キャッシュに移動します。キャッシュで DNS リクエストを解決できない場合、キャッシュはクエリの宛先に基づいて次のいずれかの場所にリクエストを転送します。
- kube-dns: クラスタ DNS ドメイン(
cluster.local
)に対するクエリはすべて kube-dns に転送されます。node-local-dns Pod は、kube-dns-upstream Service を使用して kube-dns Pod にアクセスします。次の図では、kube-dns Service の IP アドレスは10.0.0.10:53
です。 - カスタムスタブ ドメインまたはアップストリーム ネームサーバー: クエリは NodeLocal DNSCache Pod から直接転送されます。
- Cloud DNS: 他のすべてのクエリは、クエリの送信元 Pod と同じノードで実行されるローカル メタデータ サーバーに転送されます。ローカル メタデータ サーバーは Cloud DNS にアクセスします。
既存のクラスタで NodeLocal DNSCache を有効にすると、ノードのアップグレード プロセスに従って、GKE は GKE バージョン 1.15 以降を実行しているすべてのクラスタノードを再作成します。
ノードが再作成されると、GKE が自動的にラベル addon.gke.io/node-local-dns-ds-ready=true
をノードに追加します。このラベルは、クラスタノードに手動で追加しないでください。
NodeLocal DNSCache のメリット
NodeLocal DNSCache には次のメリットがあります。
- 平均 DNS ルックアップ時間が短縮される
- Pod からローカル キャッシュへの接続によって、conntrack テーブル エントリは作成されません。これにより、conntrack テーブルの消耗や競合状態による接続のドロップや拒否が回避されます。
- NodeLocal DNSCache は GKE 向け Cloud DNS で使用できます。
- 外部 URL(クラスタ リソースを参照しない URL)に対する DNS クエリは、kube-dns をバイパスして、ローカル Cloud DNS メタデータ サーバーに直接転送されます。
- ローカル DNS キャッシュは、スタブドメインのカスタム リゾルバの追加セクションで指定されているスタブドメインとアップストリーム ネームサーバーを自動的に選択します。
要件と制限事項
- NodeLocal DNSCache は、クラスタの各ノードでコンピューティング リソースを消費します。
- NodeLocal DNSCache は Windows Server ノードプールではサポートされていません。
- NodeLocal DNSCache には GKE バージョン 1.15 以降が必要です。
- NodeLocal DNSCache は、TCP を使用して kube-dns Pod にアクセスします。
- NodeLocal DNSCache は、GKE バージョン 1.18 以降で TCP と UDP を使用して
upstreamServers
とstubDomains
にアクセスします。DNS サーバーは、TCP と UDP を使用して到達可能である必要があります。 - DNS レコードは、次の期間キャッシュに保存されます。
- レコードの有効期間(TTL)。または、TTL が 30 秒を超える場合は 30 秒。
- DNS レスポンスが
NXDOMAIN
の場合は 5 秒。
- NodeLocal DNSCache Pod は、ノードのポート 53、9253、9353、8080 でリッスンします。他の
hostNetwork
Pod を実行するか、これらのポートでhostPorts
を構成した場合、NodeLocal DNSCache が失敗し、DNS エラーが発生します。GKE Dataplane V2 を使用して GKE 向け Cloud DNS は使用しない場合、NodeLocal DNSCache Pod はhostNetwork
モードを使用しません。 - ローカル DNS キャッシュは、GKE バージョン 1.15 以降を実行しているノードプールでのみ実行されます。これよりも前のバージョンを実行しているノードを持つクラスタで NodeLocal DNSCache を有効にすると、それらのノード上の Pod は kube-dns を使用します。
始める前に
作業を始める前に、次のタスクが完了していることを確認してください。
- Google Kubernetes Engine API を有効にする。 Google Kubernetes Engine API の有効化
- このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化する。すでに gcloud CLI をインストールしている場合は、
gcloud components update
コマンドを実行して最新のバージョンを取得します。以前のバージョンの gcloud CLI では、このドキュメントのコマンドを実行できない場合があります。
- 既存の Autopilot クラスタまたは Standard クラスタがあることを確認します。必要な場合は、Autopilot クラスタを作成します。Autopilot クラスタの場合、NodeLocal DNSCache はデフォルトで有効になっており、オーバーライドできません。
NodeLocal DNSCache を有効にする
Standard クラスタの場合、Google Cloud CLI または Google Cloud コンソールを使用して NodeLocal DNSCache を有効にできます。
gcloud
既存のクラスタで NodeLocal DNSCache を有効にするには、引数 NodeLocalDNS=ENABLED
を指定して --update-addons
フラグを使用します。
gcloud container clusters update CLUSTER_NAME \
--location=COMPUTE_LOCATION \
--update-addons=NodeLocalDNS=ENABLED
次のように置き換えます。
CLUSTER_NAME
: クラスタの名前。COMPUTE_LOCATION
: クラスタの Compute Engine のロケーション。
コンソール
新しいクラスタで NodeLocal DNSCache を有効にするには、次の手順を行います。
Google Cloud コンソールで [Google Kubernetes Engine] ページに移動します。
変更するクラスタの名前をクリックします。
[ネットワーキング] の [DNS プロバイダ] フィールドで、edit [DNS プロバイダを編集] をクリックします。
[NodeLocal DNSCache を有効にする] チェックボックスをオンにします。
[変更を保存] をクリックします。
この変更を行うにはノードの再作成が必要になり、実行中のワークロードが中断する可能性があります。この変更について詳しくは、ノード アップグレード戦略に従ってノードを再作成し、メンテナンス ポリシーを遵守する手動変更の表で対応する行をご覧ください。ノードの更新の詳細については、ノードの更新による中断の計画をご覧ください。
NodeLocal DNSCache が有効になっていることを確認する
node-local-dns
Pod を一覧表示して、NodeLocal DNSCache が実行されていることを確認できます。
kubectl get pods -n kube-system -o wide | grep node-local-dns
出力は次のようになります。
node-local-dns-869mt 1/1 Running 0 6m24s 10.128.0.35 gke-test-pool-69efb6b8-5d7m <none> <none>
node-local-dns-htx4w 1/1 Running 0 6m24s 10.128.0.36 gke-test-pool-69efb6b8-wssk <none> <none>
node-local-dns-v5njk 1/1 Running 0 6m24s 10.128.0.33 gke-test-pool-69efb6b8-bhz3 <none> <none>
GKE バージョン 1.15 以降を実行している各ノードの node-local-dns
Pod が出力に表示されます。
NodeLocal DNSCache を無効にする
NodeLocal DNSCache を無効にするには、次のコマンドを使用します。
gcloud container clusters update CLUSTER_NAME \
--location=COMPUTE_LOCATION \
--update-addons=NodeLocalDNS=DISABLED
次のように置き換えます。
CLUSTER_NAME
: 無効にするクラスタの名前。COMPUTE_LOCATION
: クラスタの Compute Engine のロケーション。
この変更を行うにはノードの再作成が必要になり、実行中のワークロードが中断する可能性があります。この変更について詳しくは、ノード アップグレード戦略に従ってノードを再作成し、メンテナンス ポリシーを遵守する手動変更の表で対応する行をご覧ください。ノードの更新の詳細については、ノードの更新による中断の計画をご覧ください。
NodeLocal DNSCache のトラブルシューティング
Kubernetes DNS の問題の診断に関する一般的な情報については、DNS 解決のデバッグをご覧ください。
NodeLocal DNSCache がすぐに有効にならない
既存のクラスタで NodeLocal DNSCache を有効にしても、クラスタにメンテナンスの時間枠または除外が構成されている場合は、GKE でノードがすぐに更新されないことがあります。詳細については、ノードの再作成とメンテナンスの時間枠に関する注意点をご覧ください。
待機しないようにするには、gcloud container clusters upgrade
コマンドを呼び出し、すでにノードプールが動作している GKE バージョンを指定した --cluster-version
フラグを渡すことで、ノードに変更を手動で適用できます。この対処法には、Google Cloud CLI を使用する必要があります。
Cloud DNS での NodeLocal DNSCache
Cloud DNS で NodeLocal DNSCache を使用する場合、次の図のように、クラスタはネームサーバー IP アドレス 169.254.20.10
を使用します。
その結果、kube-dns
Service の IP アドレスが、Pod が使用するネームサーバー IP アドレスと異なる場合があります。この IP アドレスの違いは想定内です。Cloud DNS が正しく機能するには、169.254.20.10
ネームサーバー IP アドレスが必要です。
IP アドレスを確認するには、次のコマンドを実行します。
kube-dns
Service の IP アドレスを表示します。kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"
出力は
kube-dns
の IP アドレスです(例:10.0.0.10:53
)。Pod でシェル セッションを開きます。
kubectl exec -it POD_NAME -- /bin/bash
Pod シェル セッションで、
/etc/resolv.conf
ファイルの内容を読み取ります。cat /etc/resolv.conf
出力は
169.254.20.10
です。
NodeLocal DNSCache を使用したネットワーク ポリシー
NodeLocal DNSCache でネットワーク ポリシーを使用し、Cloud DNS または GKE Dataplane V2 を使用していない場合、ワークロードと node-local-dns
Pod が DNS クエリを送信できるようにルールを構成する必要があります。
マニフェストの ipBlock
ルールを使用して、Pod と kube-dns 間の通信を許可します。
次のマニフェストは、ipBlock
ルールを使用するネットワーク ポリシーを記述しています。
spec:
egress:
- ports:
- port: 53
protocol: TCP
- port: 53
protocol: UDP
to:
- ipBlock:
cidr: KUBE_DNS_SVC_CLUSTER_IP/32
podSelector: {}
policyTypes:
- Egress
KUBE_DNS_SVC_CLUSTER_IP
は、kube-dns サービスの IP アドレスに置き換えます。kube-dns サービスの IP アドレスを取得するには、次のコマンドを使用します。
kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"
既知の問題
NodeLocal DNSCache と GKE Dataplane V2 を使用する場合の ClusterFirstWithHostNet dnsPolicy での DNS タイムアウト
GKE Dataplane V2 と NodeLocal DNSCache を使用するクラスタでは、hostNetwork
が true
に、dnsPolicy
が ClusterFirstWithHostNet
に設定されている Pod はクラスタの DNS バックエンドに到達できません。DNS ログには、次のようなエントリが含まれている場合があります。
nslookup: write to 'a.b.c.d': Operation not permitted
;; connection timed out; no servers could be reached
出力には、DNS リクエストがバックエンド サーバーに到達できないことが示されています。
この問題を回避するには、hostNetwork
Pod に dnsPolicy
と dnsConfig
を設定します。
spec:
dnsPolicy: "None"
dnsConfig:
nameservers:
- KUBE_DNS_UPSTREAM
searches:
- cluster.local
- svc.cluster.local
- NAMESPACE.svc.cluster.local
- c.PROJECT_ID.internal
- google.internal
options:
- name: ndots
value: "5"
次のように置き換えます。
NAMESPACE
:hostNetwork
Pod の名前空間。PROJECT_ID
: 実際の Google Cloud プロジェクト ID。KUBE_DNS_UPSTREAM
: アップストリーム kube-dns サービスの ClusterIP。この値は、次のコマンドで取得できます。kubectl get svc -n kube-system kube-dns-upstream -o jsonpath="{.spec.clusterIP}"
これで、Pod からの DNS リクエストが kube-dns に到達し、NodeLocal DNSCache をバイパスできるようになります。
NodeLocal DNSCache タイムアウト エラー
NodeLocal DNSCache が有効になっているクラスタでは、ログに次のようなエントリが含まれていることがあります。
[ERROR] plugin/errors: 2 <hostname> A: read tcp <node IP: port>-><kubedns IP>:53: i/o timeout
出力には、kube-dns-upstream
クラスタ IP サービスの IP アドレスが含まれます。この例では、DNS リクエストに対するレスポンスを kube-dns から 2 秒以内に受信していません。原因としては次のいずれかが考えられます。
- 使用しているネットワーク接続の問題。
- ワークロードからの DNS クエリ、またはノードプールのアップスケーリングにより、DNS クエリが大幅に増加した。
その結果、既存の kube-dns
Pod では、すべてのリクエストを時間内に処理できなくなります。回避策は、自動スケーリングのパラメータを調整して kube-dns レプリカの数を増やすことです。
kube-dns のスケールアップ
クラスタノードがスケールアップしたときに kube-dns Pod をさらに作成するには、nodesPerReplica
に小さい値を使用します。Kubernetes API を監視する kube-dns Pod が多いことが原因で GKE コントロール プレーン仮想マシン(VM)が過負荷状態にならないように、明示的な max
値を設定することを強くおすすめします。
max
にクラスタ内のノード数を設定できます。クラスタのノード数が 500 を超える場合は、max
に 500 を設定します。
Standard クラスタの場合、kube-dns-autoscaler
ConfigMap を編集して、kube-dns レプリカの数を変更できます。この構成は、Autopilot クラスタでサポートされていません。
kubectl edit configmap kube-dns-autoscaler --namespace=kube-system
出力は次のようになります。
linear: '{"coresPerReplica":256, "nodesPerReplica":16,"preventSinglePointFailure":true}'
kube-dns レプリカの数は、次の数式で計算されます。
replicas = max( ceil( cores × 1/coresPerReplica ) , ceil( nodes × 1/nodesPerReplica ), maxValue )
スケールアップするには、nodesPerReplica
の値を小さくし、max
値を設定します。
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"preventSinglePointFailure":true}'
この構成ファイルでは、クラスタ内の 8 ノードごとに 1 つの kube-dns Pod を作成します。24 ノードクラスタは 3 つのレプリカを持ち、40 ノードクラスタでは 5 つのレプリカになります。クラスタが 120 ノードを超えても、kube-dns レプリカの数は 15(max
値)を超えることはありません。
クラスタで DNS の可用性のベースライン レベルを確保するには、kube-dns の最小レプリカ数を設定します。
min
フィールドを含む kube-dns-autoscaler
ConfigMap の出力は次のようになります。
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"min": 5,"preventSinglePointFailure":true}'
次のステップ
- GKE がマネージド DNS を提供する方法の概要を確認する。
- Kubernetes クラスタで DNS が使用される方法の概要について、Service と Pod の DNS で確認する。
- GKE 向け Cloud DNS の使用方法を確認する。