Standard クラスタでアプリケーションを実行している場合、kube-dns はサービス ディスカバリと通信を有効にするデフォルトの DNS プロバイダです。このドキュメントでは、kube-dns を使用して DNS を管理する方法について説明します。これには、アーキテクチャ、構成、GKE 環境内の DNS 解決を最適化するためのベスト プラクティスが含まれます。
このドキュメントは、GKE で DNS の管理を担当するデベロッパー、管理者、アーキテクトを対象としています。 Google Cloudの一般的なロールとタスクについては、一般的な GKE Enterprise ユーザーロールとタスクをご覧ください。
始める前に、Kubernetes Service と一般的な DNS のコンセプトを理解しておいてください。
kube-dns アーキテクチャについて
kube-dns は GKE クラスタ内で動作し、Pod と Service 間の DNS 解決を有効にします。
次の図は、Pod が kube-dns Service とどのように連携するかを示しています。
主要コンポーネント
kube-dns には、次の主要コンポーネントが含まれています。
kube-dnsPod: これらの Pod はkube-dnsサーバー ソフトウェアを実行します。これらの Pod の複数のレプリカがkube-systemNamespace で実行され、高可用性と冗長性が実現されます。kube-dnsService:ClusterIPタイプのこの Kubernetes Service は、kube-dnsPod をグループ化し、単一の安定したエンドポイントとして公開します。ClusterIPはクラスタの DNS サーバーとして機能し、Pod はこれを使用して DNS クエリを送信します。kube-dnsは、ヘッドレス サービスあたり最大 1,000 個のエンドポイントをサポートします。kube-dns-autoscaler: この Pod は、クラスタのサイズ(ノード数と CPU コア数を含む)に基づいてkube-dnsレプリカの数を調整します。このアプローチにより、kube-dnsがさまざまな DNS クエリ負荷を処理できるようになります。
内部 DNS の解決
Pod がクラスタのドメイン内(myservice.my-namespace.svc.cluster.local など)の DNS 名を解決する必要がある場合、次のプロセスが発生します。
- Pod DNS 構成: 各ノードの
kubeletは、Pod の/etc/resolv.confファイルを構成します。このファイルは、ネームサーバーとしてkube-dnsService のClusterIPを使用します。 - DNS クエリ: Pod が
kube-dnsService に DNS クエリを送信します。 - 名前解決:
kube-dnsがクエリを受信します。内部 DNS レコードで対応する IP アドレスを検索し、Pod に応答します。 - 通信: Pod は、解決された IP アドレスを使用してターゲット Service と通信します。
外部 DNS の解決
Pod が外部 DNS 名またはクラスタのドメイン外の名前を解決する必要がある場合、kube-dns は再帰リゾルバとして機能します。クエリは、ConfigMap ファイルで構成されているアップストリーム DNS サーバーに転送されます。特定のドメイン(スタブドメインとも呼ばれます)のカスタム リゾルバを構成することもできます。この構成により、kube-dns はこれらのドメインのリクエストを特定のアップストリーム DNS サーバーに転送します。
Pod DNS を構成する
GKE では、各ノードの kubelet エージェントが、そのノードで実行される Pod の DNS 設定を構成します。
/etc/resolv.conf ファイルを構成する
GKE が Pod を作成すると、kubelet エージェントが Pod の /etc/resolv.conf ファイルを変更します。このファイルは、名前解決用の DNS サーバーを構成し、検索ドメインを指定します。デフォルトでは、kubelet はクラスタの内部 DNS サービス kube-dns をネームサーバーとして使用するように Pod を構成します。また、ファイル内の検索ドメインも入力します。これらの検索ドメインを使用すると、DNS クエリで非修飾名を使用できます。たとえば、Pod が myservice をクエリする場合、Kubernetes はまず myservice.default.svc.cluster.local、次に myservice.svc.cluster.local、そして search リストの他のドメインを解決しようとします。
次の例は、デフォルトの /etc/resolv.conf 構成を示しています。
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local c.my-project-id.internal google.internal
options ndots:5
このファイルには次のエントリがあります。
nameserver:kube-dnsサービスのClusterIPを定義します。search: DNS ルックアップ時に完全修飾されていない名前に付加される検索ドメインを定義します。options ndots:5: GKE が名前を完全修飾と見なすしきい値を設定します。5 つ以上のドットを含む名前は、完全修飾名とみなされます。
hostNetwork: true 設定で構成された Pod は、ホストから DNS 構成を継承し、kube-dns を直接クエリしません。
kube-dns をカスタマイズ
kube-dns は、堅牢なデフォルトの DNS 解決を提供します。解決効率の向上や優先 DNS リゾルバの使用など、特定のニーズに合わせて動作を調整できます。スタブドメインとアップストリーム ネームサーバーの両方を構成するには、kube-system Namespace の kube-dns ConfigMap を変更します。
kube-dns ConfigMap を変更する
kube-dns ConfigMap を変更する手順は次のとおりです。
ConfigMap を開いて編集します。
kubectl edit configmap kube-dns -n kube-systemdataセクションで、stubDomainsフィールドとupstreamNameserversフィールドを次のように追加します。apiVersion: v1 kind: ConfigMap metadata: labels: addonmanager.kubernetes.io/mode: EnsureExists name: kube-dns namespace: kube-system data: stubDomains: | { "example.com": [ "8.8.8.8", "8.8.4.4" ], "internal": [ # Required if your upstream nameservers can't resolve GKE internal domains "169.254.169.254" # IP of the metadata server ] } upstreamNameservers: | [ "8.8.8.8", # Google Public DNS "1.1.1.1" # Cloudflare DNS ]ConfigMap を保存します。
kube-dnsは構成を自動的に再読み込みします。
スタブドメイン
スタブドメインを使用すると、特定のドメインのカスタム DNS リゾルバを定義できます。Pod がそのスタブ ドメイン内の名前をクエリすると、kube-dns はデフォルトの解決メカニズムを使用する代わりに、指定されたリゾルバにクエリを転送します。
kube-dns ConfigMap に stubDomains セクションを含めます。
このセクションでは、ドメインと対応するアップストリーム ネームサーバーを指定します。kube-dns は、そのドメイン内の名前に関するクエリを指定されたサーバーに転送します。たとえば、internal.mycompany.com のすべての DNS クエリを 192.168.0.10 にルーティングし、"internal.mycompany.com": ["192.168.0.10"] を stubDomains に追加できます。
example.com などのスタブドメインにカスタム リゾルバを設定すると、kube-dns は、*.example.com などのサブドメインを含む、そのドメインのすべての名前解決リクエストを指定されたサーバーに転送します。
アップストリーム ネームサーバー
カスタム アップストリーム ネームサーバーを使用して外部ドメイン名を解決するように kube-dns を構成できます。この構成では、クラスタの内部ドメイン(*.cluster.local)のリクエストを除くすべての DNS リクエストを指定されたアップストリーム サーバーに転送するように kube-dns に指示します。metadata.internal や *.google.internal などの内部ドメインは、カスタム アップストリーム サーバーで解決できない場合があります。Workload Identity Federation for GKE を有効にする場合、またはこれらのドメインに依存するワークロードがある場合は、ConfigMap に internal のスタブ ドメインを追加します。このスタブ ドメインのリゾルバとして、メタデータ サーバーの IP アドレスである 169.254.169.254 を使用します。
カスタム kube-dns Deployment を管理する
Standard GKE では、kube-dns は Deployment として実行されます。カスタム kube-dns デプロイとは、クラスタ管理者がデフォルトの GKE 提供のデプロイを使用するのではなく、デプロイを制御してニーズに合わせてカスタマイズできることを意味します。
カスタム デプロイの理由
次の理由から、カスタム kube-dns デプロイを検討してください。
- リソース割り当て:
kube-dnsPod の CPU とメモリリソースを微調整して、DNS トラフィックが多いクラスタのパフォーマンスを最適化します。 - イメージ バージョン: 特定のバージョンの
kube-dnsイメージを使用するか、CoreDNS などの代替 DNS プロバイダに切り替えます。 - 高度な構成: ロギングレベル、セキュリティ ポリシー、DNS キャッシュ保存動作をカスタマイズします。
カスタム Deployment の自動スケーリング
組み込みの kube-dns-autoscaler は、デフォルトの kube-dns Deployment で動作します。カスタム kube-dns Deployment を作成した場合、組み込みのオートスケーラーはそれを管理しません。そのため、カスタム Deployment のレプリカ数をモニタリングして調整するように特別に構成された別のオートスケーラーを設定する必要があります。このアプローチでは、クラスタに独自のオートスケーラー構成を作成してデプロイします。
カスタム Deployment を管理する場合は、オートスケーラー イメージを最新の状態に保つなど、すべてのコンポーネントを管理する必要があります。古いコンポーネントを使用すると、パフォーマンスの低下や DNS の障害につながる可能性があります。
独自の kube-dns デプロイを構成して管理する方法の詳細な手順については、カスタム kube-dns Deployment の設定をご覧ください。
トラブルシューティング
kube-dns のトラブルシューティングについては、次のページをご覧ください。
- GKE の
kube-dnsに関するアドバイスについては、GKE でのkube-dnsのトラブルシューティングをご覧ください。 - Kubernetes DNS の問題の診断に関する一般的な情報については、DNS 解決のデバッグをご覧ください。
DNS 解決を最適化する
このセクションでは、GKE での DNS 管理に関する一般的な問題とベスト プラクティスについて説明します。
Pod の dnsConfig 検索ドメインの上限
Kubernetes では、DNS 検索ドメインの数は 32 個に制限されています。Pod の dnsConfig で 32 個を超える検索ドメインを定義しようとすると、kube-apiserver は Pod を作成しません。次のようなエラーが発生します。
The Pod "dns-example" is invalid: spec.dnsConfig.searches: Invalid value: []string{"ns1.svc.cluster-domain.example", "my.dns.search.suffix1", "ns2.svc.cluster-domain.example", "my.dns.search.suffix2", "ns3.svc.cluster-domain.example", "my.dns.search.suffix3", "ns4.svc.cluster-domain.example", "my.dns.search.suffix4", "ns5.svc.cluster-domain.example", "my.dns.search.suffix5", "ns6.svc.cluster-domain.example", "my.dns.search.suffix6", "ns7.svc.cluster-domain.example", "my.dns.search.suffix7", "ns8.svc.cluster-domain.example", "my.dns.search.suffix8", "ns9.svc.cluster-domain.example", "my.dns.search.suffix9", "ns10.svc.cluster-domain.example", "my.dns.search.suffix10", "ns11.svc.cluster-domain.example", "my.dns.search.suffix11", "ns12.svc.cluster-domain.example", "my.dns.search.suffix12", "ns13.svc.cluster-domain.example", "my.dns.search.suffix13", "ns14.svc.cluster-domain.example", "my.dns.search.suffix14", "ns15.svc.cluster-domain.example", "my.dns.search.suffix15", "ns16.svc.cluster-domain.example", "my.dns.search.suffix16", "my.dns.search.suffix17"}: must not have more than 32 search paths.
kube-apiserver は、Pod の作成試行に対する応答としてこのエラー メッセージを返します。この問題を解決するには、構成から追加の検索パスを削除します。
kube-dns のアップストリーム nameservers の上限
kube-dns では、upstreamNameservers 値の数が 3 つに制限されます。3 つを超える数を定義すると、Cloud Logging に次のようなエラーが表示されます。
Invalid configuration: upstreamNameserver cannot have more than three entries (value was &TypeMeta{Kind:,APIVersion:,}), ignoring update
このシナリオでは、kube-dns は upstreamNameservers 構成を無視し、以前の有効な構成を引き続き使用します。この問題を解決するには、kube-dns ConfigMap から余分な upstreamNameservers を削除します。
スケールアップ kube-dns
Standard クラスタでは、クラスタノードがスケールアップしたときに kube-dns Pod がさらに作成されるように、nodesPerReplica に小さい値を使用できます。Kubernetes API を監視する kube-dns Pod が多いことが原因で GKE コントロール プレーン仮想マシン(VM)が過負荷状態にならないように、max フィールドに明示的な値を設定することを強くおすすめします。
max フィールドの値をクラスタ内のノード数に設定できます。クラスタのノード数が 500 を超える場合は、max フィールドの値を 500 に設定します。
kube-dns-autoscaler ConfigMap を編集することで、kube-dns レプリカの数を変更できます。
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 ) )
スケールアップするには、nodesPerReplica フィールドの値を小さくし、max フィールドの値を含めます。
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"preventSinglePointFailure":true}'
この構成では、クラスタ内の 8 ノードごとに 1 つの kube-dns Pod が作成されます。24 ノードクラスタには 3 つのレプリカがあり、40 ノードクラスタには 5 つのレプリカがあります。クラスタが 120 ノードを超えても、kube-dns レプリカの数は max フィールドの値である 15 を超えることはありません。
クラスタで DNS の可用性のベースライン レベルを確保するには、kube-dns フィールドの最小レプリカ数を設定します。
min フィールドが構成された kube-dns-autoscaler ConfigMap の出力は次のようになります。
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"min": 5,"preventSinglePointFailure":true}'
DNS ルックアップ時間を短縮する
デフォルトの kube-dns プロバイダで DNS ルックアップのレイテンシが高くなったり、DNS の解決に失敗したりする原因はいくつかあります。アプリケーションでは、これらの問題が getaddrinfo EAI_AGAIN エラーとして発生する可能性があります。これは、名前解決の一時的な失敗を示します。原因は次のとおりです。
- ワークロード内で DNS ルックアップの実行頻繁が高い。
- ノードあたりの Pod 密度が高い。
- Spot VM またはプリエンプティブル VM で
kube-dnsを実行している。これにより、予期しないノード削除が発生する可能性があります。 kube-dnsPod 内のdnsmasqインスタンスの容量を超える大量のクエリ。1 つのkube-dnsインスタンスの同時 TCP 接続数の上限は、GKE バージョン 1.31 以降では 200、GKE バージョン 1.30 以前では 20 です。
DNS ルックアップ時間を改善するには、次の操作を行います。
- Spot VM またはプリエンプティブル VM では、
kube-dnsなどの重要なシステム コンポーネントを実行しないでください。標準 VM を含み、Spot VM またはプリエンプティブル VM を含まないノードプールを 1 つ以上作成します。taint と toleration を使用して、重要なワークロードがこれらの信頼性の高いノードにスケジュールされるようにします。 - NodeLocal DNSCache を有効にします。NodeLocal DNSCache は、各ノードで DNS レスポンスを直接キャッシュに保存するため、レイテンシと
kube-dnsサービスの負荷が軽減されます。NodeLocal DNSCache を有効にして、デフォルト拒否ルールでネットワーク ポリシーを使用する場合は、ワークロードがnode-local-dnsPod に DNS クエリを送信できるようにポリシーを追加します。 kube-dnsをスケールアップします。- アプリケーションでは
dns.lookupベースの関数ではなくdns.resolve*ベースの関数を使用する(dns.lookupは同期的であるため)。 https://google.com/ではなく、完全修飾ドメイン名(FQDN)(例:https://google.com./)を使用します。
GKE クラスタのアップグレード中に、kube-dns などのコントロール プレーン コンポーネントの同時アップグレードにより、DNS 解決に失敗することがあります。通常、このような障害の影響を受けるノードはごく一部です。本番環境のクラスタに適用する前に、非本番環境でクラスタのアップグレードを徹底的にテストします。
Service の検出可能性を確保する
kube-dns は、エンドポイントを持つ Service の DNS レコードのみを作成します。Service にエンドポイントがない場合、kube-dns はその Service の DNS レコードを作成しません。
DNS TTL の不一致を管理する
TTL が大きいまたは無限のアップストリーム DNS リゾルバから DNS レスポンスを受け取った場合、kube-dns はこの TTL 値を保持します。この動作により、キャッシュに保存されたエントリと実際の IP アドレスの間に不一致が生じる可能性があります。
GKE は、1.21.14-gke.9100 以降、1.22.15-gke.2100 以降などの特定のコントロール プレーン バージョンでこの問題を解決します。これらのバージョンでは、TTL が大きい DNS レスポンスの最大 TTL 値を 30 秒に設定します。この動作は NodeLocal DNSCache と同様です。
kube-dns 指標を表示する
クラスタ内の DNS クエリに関する指標は、kube-dns Pod から直接取得できます。
kube-systemNamespace でkube-dnsPod を見つけます。kubectl get pods -n kube-system --selector=k8s-app=kube-dns出力は次のようになります。
NAME READY STATUS RESTARTS AGE kube-dns-548976df6c-98fkd 4/4 Running 0 48m kube-dns-548976df6c-x4xsh 4/4 Running 0 47mPod のいずれかを選択し、その Pod から指標にアクセスするようにポート転送を設定します。
- ポート
10055はkube-dns指標を公開します。 - ポート
10054はdnsmasq指標を公開します。
POD_NAMEは、選択した Pod の名前に置き換えます。POD_NAME="kube-dns-548976df6c-98fkd" # Replace with your pod name kubectl port-forward pod/${POD_NAME} -n kube-system 10055:10055 10054:10054出力は次のようになります。
Forwarding from 127.0.0.1:10054 -> 10054 Forwarding from 127.0.0.1:10055 -> 10055- ポート
新しいターミナル セッションで、
curlコマンドを使用して指標エンドポイントにアクセスします。# Get kube-dns metrics curl http://127.0.0.1:10055/metrics # Get dnsmasq metrics curl http://127.0.0.1:10054/metrics出力は次のようになります。
kubedns_dnsmasq_errors 0 kubedns_dnsmasq_evictions 0 kubedns_dnsmasq_hits 3.67351e+06 kubedns_dnsmasq_insertions 254114 kubedns_dnsmasq_max_size 1000 kubedns_dnsmasq_misses 3.278166e+06
次のステップ
- GKE のクラスタ DNS の概要を読む。
- Kubernetes クラスタで DNS が使用される方法の概要について、Service と Pod の DNS で確認する。
- NodeLocal DNSCache を設定する方法を確認する。
- カスタム kube-dns Deployment を設定する方法を学習する。