ブログ | NGINX

Kubernetes でセルフサービス DNS と証明書管理を有効にする

NGINX-F5 水平黒タイプ RGB の一部
ジェイソン・シュミット サムネイル
ジェイソン・シュミット
2022年11月1日公開

アプリケーション開発の最終的な目標は、もちろん、インターネット上でアプリケーションを公開することです。 開発者にとって、Kubernetes は、アプリケーションへのリクエストをルーティングするメカニズムとして Ingress コントローラーを提供することで、このプロセスをある程度簡素化します。 ただし、すべてが期待どおりにセルフサービスであるとは限りません。アプリのドメイン名を Ingress コントローラーの IP アドレスにマッピングするためのドメイン ネーム システム (DNS) のレコードと、HTTPS を使用して接続を保護するための TLS 証明書が必要です。 ほとんどの組織では、DNS や TLS を自分で所有していないため、それらを所有する運用グループ (または複数のグループ) と調整する必要があります。

オペレーターにとって物事は必ずしも簡単ではありません。 ほとんどの組織では、DNS レコードを更新する必要性はほとんどないため、手順(ビジネス ルールと実際の技術的な手順の両方)がほとんどないか、まったく存在しない傾向があります。 つまり、DNS レコードを追加する必要がある場合は、まずドキュメントを探すか、同僚に尋ねるか、(最悪の場合)自分で調べる必要があります。 また、企業のセキュリティ ルールに準拠していること、およびファイアウォールに対してイングレスが適切にタグ付けされていることを確認する必要があります。

幸いなことに、開発者とオペレーターの両方の生活を楽にする方法があります。 この記事では、オペレーターが Kubernetes デプロイメントを構成して、開発者が Kubernetes 環境で DNS レコードを更新し、TLS 証明書を生成できるようにセルフサービスを有効にする方法を説明します。 事前にインフラストラクチャを構築することで、必要なビジネス要件と技術要件がすべて満たされていることを保証できます。

概要と前提条件

ソリューションを導入すれば、開発者がアプリケーションをインターネットに公開するために必要なことは、Kubernetes インストールによって管理されるドメイン内の完全修飾ドメイン名 (FQDN) を含む提供されたテンプレートに従って Ingress コントローラーを作成することだけです。 Kubernetes はテンプレートを使用して Ingress コントローラーの IP アドレスを割り当て、FQDN を IP アドレスにマッピングする DNS Aレコードを作成し、FQDN の TLS 証明書を生成して Ingress コントローラーに追加します。 クリーンアップも同様に簡単です。Ingress が削除されると、DNS レコードがクリーンアップされます。

このソリューションでは、次のテクノロジーを活用しています (インストールと構成の手順については以下を参照してください)。

ソリューションを構成する前に、次のものが必要です。

  • 出力 ( LoadBalancer ) オブジェクトを備えた Kubernetes クラウド インストール。 このソリューションでは Linode を使用しますが、他のクラウド プロバイダーも機能します。
  • Cloudflareでホストされているドメイン名。cert-managerサポートされている DNS プロバイダーの 1 つであり、ExternalDNS (執筆時点ではベータ版) をサポートしているため、これを選択しました。 このドメインは、本番環境やその他の重要な目的には使用しないことを強くお勧めします。
  • 無料レベルに含まれる Cloudflare API へのアクセス。
  • Kubernetes をインストールおよびデプロイするためのHelm
  • Kubernetes のコマンドライン インターフェイスとしてのkubectl
  • オプションで、Kubernetes と対話するためのより構造化された方法を提供する、適切に構築されたタンジブル ユーザー インターフェイス (TUI) であるK9s も使用できます。

また、Kubernetes の基本的な知識 (マニフェストの適用方法、Helm チャートの使用方法、 kubectlコマンドを発行して出力を表示してトラブルシューティングする方法) があることも前提としています。 Let's Encrypt の基本的な概念を理解しておくと役立ちますが、必須ではありません。概要については、ブログをご覧ください。 また、 cert-manager がどのように機能するかを知る必要はありませんが、cert-manager (および一般的な証明書) が NGINX Ingress Controller でどのように機能するかに興味がある場合は、最近の投稿「Kubernetes 環境での証明書管理の自動化」を参照してください。

このソリューションは macOS と Linux の両方でテストされています。 Windows Subsystem for Linuxバージョン 2 (WSL2) ではテストしていませんが、問題は発生しないと思われます。

注記: このソリューションは概念実証のサンプルとして提供されており、実稼働環境での使用を目的としたものではありません。 特に、運用とセキュリティに関するベストプラクティスがすべて組み込まれているわけではありません。 これらのトピックの詳細については、 cert-managerおよびExternalDNS のドキュメントを参照してください。

ソリューションの導入

ソリューションを展開するには、次のセクションの手順に従います。

ソフトウェアをダウンロード
  1. Cloudflare API トークンをダウンロードします。
  2. NGINX Ingress Controller リポジトリをクローンします。

    $ git clone https://github.com/nginxinc/kubernetes-ingress.git 'kubernetes-ingress' にクローンしています... リモート: オブジェクトの列挙: 45176、完了。リモート: オブジェクトのカウント: 100% (373/373)、完了。リモート: オブジェクトの圧縮: 100% (274/274)、完了。リモート: 合計 45176 (差分 173)、再利用 219 (差分 79)、パック再利用 44803 受信オブジェクト: 100% (45176/45176)、60.45 MiB | 26.81 MiB/s、完了。
    デルタの解決: 100% (26592/26592)、完了。
  3. Kubernetes クラスターに接続できることを確認します。

    $ kubectl cluster-info Kubernetes コントロール プレーンは https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443 で実行されています。KubeDNS は https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy で実行されています。クラスターの問題をさらにデバッグして診断するには、「kubectl cluster-info dump」を使用します。

NGINX Ingress Controller をデプロイする

  1. Helm を使用して、NGINX Ingress Controller をデプロイします。 3 つの非標準構成オプションを追加していることに注意してください。

    • controller.enableCustomResources – NGINX VirtualServer および VirtualServerRouteカスタム リソースの作成に使用されるカスタム リソース定義 (CRD) をインストールするように Helm に指示します。
    • controller.enableCertManager – NGINX Ingress Controller がcert-managerコンポーネントと通信するように構成します。
    • controller.enableExternalDNS – Ingress コントローラーが ExternalDNS コンポーネントと通信するように構成します。
    $ helm install nginx-kic nginx-stable/nginx-ingress --namespace nginx-ingress --set controller.enableCustomResources=true --create-namespace --set controller.enableCertManager=true --set controller.enableExternalDNS=true名前: nginx-kic 最終デプロイ日: 日 月 DD hh : mm : ss YYYY名前空間: nginx-ingress ステータス: デプロイ済み リビジョン: 1 テストスイート: なし 注記:
    NGINX Ingress Controller がインストールされました。
  2. NGINX Ingress Controller が実行中であることを確認し、 EXTERNAL-IPフィールドの値をメモします。これは、NGINX Ingress Controller の IP アドレスです (ここではwww.xxx.yyy.zzz )。 読みやすくするために、出力は 2 行に分割されます。

    $ kubectl get services --namespace nginx-ingress NAME TYPE CLUSTER-IP ... nginx-kic-nginx-ingress LoadBalancer 10.128.152.88 ... ... 外部 IP ポートの年齢 ... www.xxx.yyy.zzz 80:32457/TCP、443:31971/TCP 3 時間 8 分

cert-manager をデプロイする

このソリューションでは、 cert-manager はTLS 証明書を取得するときにDNS-01チャレンジ タイプを使用します。これには、 ClusterIssuer リソースの作成中に Cloudflare API トークンを提供する必要があります。 このソリューションでは、API トークンは Kubernetes Secretとして提供されます。

  1. Helm を使用してcert-manager をデプロイします

    $ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.9.1 --set installCRDs=true名前: cert-manager 最終デプロイ日: 日 月 DD hh : mm : ss YYYY名前空間: cert-manager ステータス: デプロイ済み リビジョン: 1 テストスイート: なし 注記: cert-manager v1.9.1 が正常にデプロイされました。
  2. Cloudflare APIトークンをKubernetes Secretとしてデプロイし、 <API トークン>:

    $ kubectl apply -f - <<EOFapiバージョン: v1
    種類: シークレットメタデータ: 名前: Cloudflare-api-token-secret 名前空間: cert-manager タイプ: 不透明
    stringData:
    api-token: "<API トークン>「
    終了
    シークレット/Cloudflare-api-token-secret が作成されました
  3. トークンを取得する場所としてCloudflare-api-token-secret (前の手順で定義) を指定して、ClusterIssuer オブジェクトを作成します。 必要に応じて、 metadata.nameフィールドのexample-issuer (およびspec.acme.privateKeySecretRef.nameフィールドのexample-issuer-account-key ) を別の名前に置き換えることができます。

    $ kubectl apply -f - <<EOFapiバージョン: cert-manager.io/v1
    種類: ClusterIssuer メタデータ: 名前: example-issuer 名前空間: cert-manager 仕様: acme: 電子メール: example@example.com サーバー: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: 名前: example-issuer-account-key ソルバー: - dns01:
              Cloudflare: apiTokenSecretRef: 名前: Cloudflare-api-token-secret キー: api-token EOF clusterissuer.cert-manager.io/example-issuer が作成されました
  4. ClusterIssuer がデプロイされ、準備ができていることを確認します ( READYフィールドの値がTrueです)。

    $ kubectl get clusterissuer NAME READY AGE example-issuer True 3h9m

外部DNSを展開する

cert-manager と同様に、ExternalDNS プロジェクトでは DNS を管理するために Cloudflare API トークンが必要です。 両方のプロジェクトに同じトークンを使用できますが、必須ではありません。

  1. プロジェクト間の統合を可能にするために、NGINX Ingress Controller の ExternalDNS CRD を作成します。

    $ kubectl create -f ./kubernetes-ingress/deployments/common/crds/externaldns.nginx.org_dnsendpoints.yaml customresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org が作成されました
  2. 外部 DNS サービス ( external-dns ) を作成します。 マニフェストはかなり長いため、ここでは 2 つの部分に分割します。 最初の部分では、アカウント、ロール、および権限を構成します。

    • DNS を管理するためのすべての書き込みおよび更新操作を管理するために、 external-dnsという ServiceAccount オブジェクトを作成します。
    • 必要な権限を定義する ClusterRole オブジェクト ( external-dnsとも呼ばれます) を作成します。
    • ClusterRole を ServiceAccount にバインドします。
    $ kubectl apply -f - <<EOFapiバージョン: v1
    種類: ServiceAccount メタデータ: 名前: external-dns --- apiVersion: rbac.authorization.k8s.io/v1 種類: ClusterRole メタデータ: 名前: external-dns ルール: - apiGroups: [""] リソース: ["services","endpoints","pods"] 動詞: ["get","watch","list"] - apiGroups: ["extensions","networking.k8s.io"] リソース: ["ingresses"] 動詞: ["get","watch","list"] - apiGroups: ["externaldns.nginx.org"] リソース: ["dnsendpoints"] 動詞: ["get","watch","list"] - apiGroups: ["externaldns.nginx.org"] リソース: ["dnsendpoints/status"] 動詞: ["update"] - apiGroups: [""] リソース: ["nodes"] 動詞: ["list","watch"] --- apiVersion: rbac.authorization.k8s.io/v1 種類: ClusterRoleBinding メタデータ: 名前: external-dns-viewer roleRef: apiGroup: rbac.authorization.k8s.io 種類: ClusterRole 名: external-dns サブジェクト: - 種類: ServiceAccount 名: external-dns 名前空間: default EOF serviceaccount/external-dns が作成されました clusterrole.rbac.authorization.k8s.io/external-dns が作成されました clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer が作成されました

    マニフェストの 2 番目の部分では、ExternalDNS デプロイメントを作成します。

    • ドメイン フィルターを作成し、ExternalDNS がドメインを管理する際に発生する可能性のある損害の範囲を制限します。 たとえば、実稼働環境への変更を防ぐために、ステージング環境のドメイン名を指定することができます。 この例では、 domain-filter をexample.comに設定します。
    • CF_API_TOKEN環境変数を Cloudflare API トークンに設定します。 のために <API トークン>実際のトークンまたはトークンを含む Secret のいずれかを置き換えます。 後者の場合、環境変数を使用してSecret をコンテナーに投影する必要もあります。
    • FREE_TIER環境変数を「true」に設定します (有料の Cloudflare サブスクリプションがない限り適切です)。
    $  kubectl apply -f - <<EOF 
    ---
    apiVersion: apps/v1
    kind: デプロイメントメタデータ: 名前: external-dns 仕様: 戦略: タイプ: 再作成セレクタ: matchLabels: app: external-dns テンプレート: metadata: labels: app: external-dns spec: serviceAccountName: external-dns コンテナ: - name: external-dns イメージ: k8s.gcr.io/external-dns/external-dns:v0.12.0 引数: - --source=service - --source=ingress - --source=crd - --crd-source-apiversion=externaldns.nginx.org/v1 - --crd-source-kind=DNSEndpoint - --domain-filter=example.com - --provider=Cloudflare 環境: - name: CF_API_TOKEN
    値: "<API トークン>"
              - 名前: FREE_TIER 値: "true" EOF serviceaccount/external-dns が作成されました clusterrole.rbac.authorization.k8s.io/external-dns が作成されました clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer が作成されました deploy.apps/external-dns が作成されました

サンプルアプリケーションをデプロイする

テスト目的で、 Cafeと呼ばれる標準の NGINX Ingress Controller サンプル アプリケーションを使用します。

  1. Cafe アプリケーションをデプロイします。

    $ kubectl apply -f ./kubernetes-ingress/examples/ingress-resources/complete-example/cafe.yamlデプロイメント.apps/coffee が作成されました。サービス/coffee-svc が作成されました。デプロイメント.apps/tea が作成されました。サービス/tea-svc が作成されました。
  2. Cafe アプリケーション用に NGINX Ingress Controller をデプロイします。 次の設定に注意してください。

    • 親切: VirtualServer – 標準の Kubernetes Ingress リソースではなく、NGINX VirtualServer カスタム リソースを使用しています。
    • spec.hostcafe.example.comを、デプロイするホストの名前に置き換えます。 ホストは、ExternalDNS で管理されているドメイン内にある必要があります。
    • spec.tls.cert-manager.cluster-issuer – この投稿で指定された値を使用している場合、これはexample-issuerです。 必要に応じて、 「cert‑manager の展開」手順 3で選択した名前を置き換えます。
    • spec.externalDNS.enable – 値true は、 ExternalDNS に DNS Aレコードを作成するように指示します。

    Kubernetes はプロバイダーの DNS API と対話するため、このステップが完了するまでの時間は DNS プロバイダーに大きく依存することに注意してください。

    $ kubectl apply -f - <<EOFapiバージョン: k8s.nginx.org/v1
    種類: VirtualServer メタデータ: 名前: cafe 仕様: ホスト: cafe.example.com tls: シークレット: cafe-secret 証明書マネージャー: クラスター発行者: example-issuer 外部 DNS: 有効化: true アップストリーム: - 名前: tea サービス: tea-svc ポート: 80 - 名前: コーヒー サービス: coffee-svc ポート: 80 ルート: - パス: /tea アクション: pass: tea - パス: /coffee アクション: pass: coffee EOF virtualserver.k8s.nginx.org/cafe が作成されました

ソリューションを検証する

  1. DNS Aレコードを確認します。特に、 ANSWER SECTIONブロックで FQDN (ここではcafe.example.com ) が正しい IP アドレス ( www.xxx.yyy.zzz ) にマッピングされていることを確認します。

    $ dig cafe.example.com ; <<>> DiG 9.10.6 <<>> cafe.example.com ;; グローバル オプション: +cmd ;; 回答を取得しました: ;; ->>HEADER<<- オペコード: クエリ、ステータス: NOERROR、ID: 22633 ;; フラグ: qr rd ra; クエリ: 1、答え: 1、権限: 0、追加: 1 ;;オプト疑似セクション: ; EDNS: バージョン: 0、フラグ:; udp: 4096 ;; 質問セクション: ;cafe.example.com.		;; 回答セクション: cafe.example.com。	279 IN A www.xxx.yyy.zzz ;; クエリ時間: 1 ミリ秒 ;; サーバー: 2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359#53(2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359) ;; いつ: 日 月 DD hh : mm : ss TZ YYYY ;; 受信したMSGサイズ: 67
  2. 証明書が有効であることを確認します( READYフィールドの値がTrueです)。

    $ kubectl 証明書を取得NAME READY SECRET AGE cafe-secret True cafe-secret 8分51秒
  3. アプリケーションにアクセスできることを確認します。

    $ curl https://cafe.example.com/coffeeサーバーアドレス: 10.2.2.4:8080 サーバー名: coffee-7c86d7d67c-lsfs6 日付: DD/Mon/YYYY:hh:mm:ss +TZオフセット URI: /coffee リクエストID: 91077575f19e6e735a91b9d06e9684cd $ curl https://cafe.example.com/teaサーバーアドレス: 10.2.2.5:8080 サーバー名: tea-5c457db9-ztpns 日付: DD/Mon/YYYY:hh:mm:ss +TZオフセット URI: /tea リクエストID: 2164c245a495d22c11e900aa0103b00f

開発者がNGINX Ingress Controllerを導入すると何が起こるか

ソリューションが導入されると、裏では多くのことが起こります。 この図は、開発者が NGINX VirtualServer カスタム リソースを使用して NGINX Ingress Controller をデプロイした場合に何が起こるかを示しています。 一部の操作詳細は省略されていることに注意してください。

  1. 開発者はNGINX CRDを使用してVirtualServerリソースをデプロイします。
  2. KubernetesはNGINX Ingress Controllerを使用してVirtualServerを作成します。
  3. NGINX Ingress ControllerはExternalDNSを呼び出してDNS Aレコードを作成します。
  4. ExternalDNSはDNSにAレコードを作成します
  5. NGINX Ingress Controllerはcert-managerを呼び出してTLS証明書を要求します。
  6. cert-manager はDNS-01チャレンジ中に使用する DNS レコードを追加します
  7. cert-manager はチャレンジを完了するために Let’s Encrypt に連絡します
  8. Let’s EncryptはDNSに対するチャレンジを検証する
  9. Let’s EncryptがTLS証明書を発行
  10. cert-managerはNGINX Ingress ControllerにTLS証明書を提供します
  11. NGINX Ingress ControllerはTLSで保護された外部リクエストをアプリケーションポッドにルーティングします。

トラブルシューティング

Kubernetes の複雑さと使用しているコンポーネントを考慮すると、包括的なトラブルシューティング ガイドを提供することは困難です。 そうは言っても、問題を特定するのに役立つ基本的な提案がいくつかあります。

  • kubectl getコマンドとkubectl describeコマンドを使用して、デプロイされたオブジェクトの構成を検証します。
  • 使用してください kubectl ログ <コンポーネント> デプロイされたさまざまなコンポーネントのログ ファイルを表示するコマンド。
  • K9s を使用してインストールを検査します。ソフトウェアは問題を黄色または赤で強調表示し (重大度に応じて)、ログやオブジェクトの詳細にアクセスするためのインターフェイスを提供します。

それでも問題が解決しない場合は、 NGINXCommunity Slackで私たちを見つけてサポートを求めてください。 私たちのコミュニティは活気に満ちており、いつでも喜んで問題を解決します。

NGINX Plus をベースにした NGINX Ingress Controller を試すには、今すぐ30 日間の無料トライアルを開始するか、弊社にお問い合わせの上、使用事例についてご相談ください


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"