このドキュメントでは、NodeLocal DNSCache を使用して DNS ルックアップのレイテンシを短縮し、Google Kubernetes Engine(GKE)クラスタでアプリケーションのパフォーマンスを改善する方法について説明します。
NodeLocal DNSCache は、各クラスタノードで DNS キャッシュを DaemonSet として直接実行することで、DNS のパフォーマンスを向上させる GKE アドオンです。Pod が DNS リクエストを行うと、そのリクエストはまず同じノードのローカル キャッシュに送信されます。リクエストをローカルで処理すると、DNS ルックアップの平均時間が大幅に短縮され、kube-dns や Cloud DNS for GKE などのクラスタの中央 DNS プロバイダの負荷が軽減されます。DNS アーキテクチャと NodeLocal DNSCache のメリットの詳細については、サービス ディスカバリについてをご覧ください。
GKE Autopilot クラスタでは、NodeLocal DNSCache はデフォルトで有効になっており、無効にすることはできません。バージョン 1.33.1 以降を実行している GKE Standard クラスタでは、NodeLocal DNSCache はデフォルトで有効になっていますが、無効にすることもできます。
このドキュメントは、デベロッパー、管理者、アーキテクトなどの GKE ユーザーを対象としています。 Google Cloudの一般的なロールとタスクの例の詳細については、一般的な GKE Enterprise ユーザーのロールとタスクをご覧ください。
このドキュメントは、次の内容を理解していることを前提としています。
アーキテクチャ
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-upstreamService を使用してkube-dnsPod にアクセスします。 - カスタムスタブ ドメインまたはアップストリーム ネームサーバー: クエリは NodeLocal DNSCache Pod から直接転送されます。
- Cloud DNS: 他のすべてのクエリは、クエリの送信元と同じノードで実行されるローカル メタデータ サーバーに転送されます。ローカル メタデータ サーバーは 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をバイパスします。 - ローカル DNS キャッシュは、スタブドメインのカスタム リゾルバの追加セクションで指定されているスタブドメインとアップストリーム ネームサーバーを自動的に選択します。
要件と制限事項
- NodeLocal DNSCache は、クラスタの各ノードでコンピューティング リソースを消費します。
- NodeLocal DNSCache は Windows Server ノードプールではサポートされていません。
- NodeLocal DNSCache には GKE バージョン 1.15 以降が必要です。
- NodeLocal DNSCache は、TCP を使用して
kube-dnsPod にアクセスします。 - 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 でリッスンします。
他の
hostNetworkPod を実行するか、これらのポートで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 の問題の診断に関する一般的な情報については、Debugging DNS Resolution をご覧ください。
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-dnsService の IP アドレスを表示します。kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"出力は
kube-dnsの IP アドレスです(例:10.0.0.10)。Pod でシェル セッションを開きます。
kubectl exec -it POD_NAME -- /bin/bashPod シェル セッションで、
/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 Service の IP アドレスに置き換えます。kube-dns Service の IP アドレスを取得するには、次のコマンドを使用します。
kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"
既知の問題
このセクションでは、NodeLocal DNSCache の既知の問題について説明します。
NodeLocal DNSCache と GKE Dataplane V2 を使用する場合の ClusterFirstWithHostNet dnsPolicy での DNS タイムアウト
GKE Dataplane V2 と NodeLocal DNSCache を使用するクラスタでは、hostNetwork フィールドが true に、dnsPolicy フィールドが ClusterFirstWithHostNet に設定されている Pod はクラスタの DNS バックエンドに到達できません。DNS ログには、次のようなエントリが含まれている場合があります。
dnslookup: 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:
- NAMESPACE.svc.cluster.local
- svc.cluster.local
- cluster.local
- c.PROJECT_ID.internal
- google.internal
options:
- name: ndots
value: "5"
次のように置き換えます。
NAMESPACE:hostNetworkPod の名前空間。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 のスケールアップ
nodesPerReplica フィールドに小さい値を使用すると、クラスタノードのスケールアップ時に kube-dns Pod がさらに作成されます。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))
ConfigMap で min フィールドと max フィールドを定義すると、レプリカはこれらの値によって制限されます。スケールアップするには、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 の使用方法を確認する。