kube-dns の使用


このページでは、Google Kubernetes Engine(GKE)が、GKE クラスタのデフォルト DNS プロバイダである kube-dns を使用してサービス ディスカバリを実装する方法について説明します。

Autopilot クラスタの場合、デフォルトの kube-dns 構成は変更できません。

アーキテクチャ

クラスタを作成すると、GKE は kube-dns Pod を kube-system 名前空間に自動的にデプロイします。Pod は、対応する Service を介して kube-dns のデプロイメントにアクセスします。この Service は、kube-dns Pod をグループ化して、単一の IP アドレス(ClusterIP)を割り振ります。デフォルトでは、クラスタ内のすべての Pod がこの Service を使用して DNS クエリを解決します。次の図は、Pod と kube-dns Service の関係を示しています。

kube-dns Pod と kube-dns サービスとの関係

kube-dns は、クラスタの DNS 処理に対応できるようにスケーリングされます。このスケーリングは kube-dns-autoscaler で制御されます。デフォルトでは、この Pod がすべての GKE クラスタにデプロイされます。kube-dns-autoscaler は、クラスタ内のノードとコアの数に基づいて、kube-dns Deployment のレプリカの数を調整します。

kube-dns は、ヘッドレス サービスあたり最大 1,000 までのエンドポイントをサポートします。

Pod DNS の構成方法

各 Node で実行されている kubelet では、kube-dns サービスの ClusterIP を使用するように Pod の etc/resolv.conf が構成されています。次の構成例では、kube-dns サービスの IP アドレスが 10.0.0.10 になっています。この IP アドレスは他のクラスタと異なります。

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

kube-dns は、クラスタ ドメイン(cluster.local)の権威ネームサーバーで、外部名を再帰的に解決します。完全修飾でない短縮名(myservice など)は、最初にローカル検索パスで補完されます。

スタブドメインのカスタム リゾルバの追加

kube-dns の ConfigMap を変更して、クラスタ内の DNS インフラストラクチャの一部としてスタブドメインを設定できます。

スタブドメインを使用すると、これらのドメインを解決する際に kube-dns が特定のアップストリーム DNS サーバーに DNS リクエストを転送するように、ドメインごとにカスタム リゾルバを構成できます。

以下の例の kube-dns の ConfigMap マニフェストには、example.com ドメインのカスタム リゾルバを設定する stubDomains 構成が含まれています。

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",
        "1.1.1.1",
        "1.0.0.1"
      ]
    }

次のコマンドを実行して、テキスト エディタを開きます。

kubectl edit configmap kube-dns -n kube-system

このファイルの内容をマニフェストと置き換え、テキスト エディタを終了してマニフェストをクラスタに適用します。

アップストリーム ネームサーバー

kube-dns の ConfigMap を変更して upstreamNameservers を追加すると、kube-dns は *.cluster.local を除くすべての DNS リクエストをこれらのサーバーに転送します。これには、アップストリーム サーバーで解決できない metadata.internal*.google.internal が含まれます。

GKE 用 Workload Identity 連携、または metadata.internal 解決に依存するワークロードを有効にして、*.internal 名前解決を維持するには、stubDomain を ConfigMap に追加します。

data:
  stubDomains: |
    {
      "internal": [
        "169.254.169.254"
      ]
    }
  upstreamNameservers: |
    ["8.8.8.8"]

既知の問題

検索ドメインの上限

/etc/resolv.conf の DNS 検索ドメインの上限は 6 個です。6 個より多くの検索ドメインを定義すると、コマンド kubectl describe pod を実行するときに次の警告が表示されます。

Search Line limits were exceeded, some search paths have been omitted, the applied search line is: default.svc.cluster.local svc.cluster.local cluster.local c.<project ID>.internal google.internal

この警告は、Cloud Logging のコンテナログ セクションに記録されます。

この問題を解決するには、構成から追加の検索パスを削除します。

upstreamNameservers の上限を考慮する

Kubernetes で定義できる upstreamNameservers 値は 3 つまでです。3 つを超える upstreamNameservers を定義すると、Cloud Logging の kube-dns デプロイログに次のエラーが記録されます。

Invalid configuration: upstreamNameserver cannot have more than three entries (value was &TypeMeta{Kind:,APIVersion:,}), ignoring update

この場合、kube-dns は upstreamNameservers が未構成の場合と同じように動作します。この問題を解決するには、構成から余分な upstreamNameservers を削除します。

kube-dns によるパフォーマンスの制限

DNS ルックアップでレイテンシが高くなっていたり、デフォルトの kube-dns プロバイダで DNS の解決に失敗したりする場合は、次の原因が考えられます。

  • ワークロード内で DNS ルックアップの実行頻繁が高い
  • デプロイしている Pod のノードあたりの密度が高い
  • Spot VM またはプリエンプティブル VM で kube-dns を実行している。これにより、予期しないノード削除が発生し、それ以降、DNS 解決の問題が生じる可能性があります。

DNS ルックアップ時間を改善するには、次のいずれかのオプションを選択します。

  • Spot VM またはプリエンプティブル VM では、kube-dns などの重要なシステム コンポーネントを実行しないでください。DNS に Spot VM またはプリエンプティブル VM を使用すると、障害が発生し、クラスタが中断される可能性があります。
  • ベスト プラクティスとして、標準 VM(Spot またはプリエンプティブル以外の VM)で構成されたノードプールを 1 つ以上作成して、kube-dns などの重要なシステム コンポーネントをホストすることをおすすめします。重要なワークロードを信頼できるノードプールでのみスケジュールして、Spot VM またはプリエンプティブル VM で実行されないようにするには、Spot VM に taint と toleration を使用します。
  • NodeLocal DNSCache を有効にする。
  • kube-dns をスケールアップする
  • アプリケーションでは dns.lookup ベースの関数ではなく dns.resolve* ベースの関数を使用する(dns.lookup は同期的であるため)。dns.resolve* 関数は常に、ネットワークで非同期 DNS クエリを実行します。

Service の DNS レコード

kube-dns は、エンドポイントを持つ Service の DNS レコードのみを作成します。

DNS アップストリーム サーバーからの TTL が長い

kube-dns は、TTL が大きいまたは「無限」のアップストリーム DNS リゾルバから DNS レスポンスを受け取った場合、キャッシュ内の DNS エントリに対して、この TTL 値を保持します。エントリが期限切れになることはないため、エントリと、TTL の名前に対して解決された実際の IP アドレスが一致しない可能性があります。

GKE では、TTL が 30 秒を超える DNS レスポンスの最大 TTL 値を 30 秒に設定して、次のコントロール プレーン バージョンでこの問題を解決します。

  • 1.21.14-gke.9100
  • 1.22.15-gke.2100
  • 1.23.13-gke.500
  • 1.24.7-gke.500
  • 1.25.2-gke.500 以降

この動作は NodeLocal DNSCache と同様です。

次のステップ

  • GKE のクラスタ DNS の概要を読む。
  • Kubernetes クラスタで DNS が使用される方法の概要について、Service と Pod の DNS で確認する。