Helmを使用してDigitalOcean KubernetesでNginx Ingressをセットアップする方法

著者は、Write for DOnationsプログラムの一部として寄付を受け取るためにFree and Open Source Fundを選択しました。

前書き

KubernetesIngressesは、クラスタを超えて内部のKubernetesサービスにトラフィックをルーティングする柔軟な方法を提供します。 入力Resourcesは、HTTPおよびHTTPSトラフィックをサービスにルーティングするためのルールを定義するKubernetesのオブジェクトです。 これらが機能するには、入力Controllerが存在する必要があります。その役割は、トラフィックを受け入れ(ほとんどの場合ロードバランサーを介して)、適切なサービスにルーティングすることでルールを実装することです。 ほとんどのイングレスコントローラーは、すべてのイングレスに対して1つのグローバルロードバランサーのみを使用します。これは、公開するサービスごとにロードバランサーを作成するよりも効率的です。

Helmは、Kubernetesを管理するためのパッケージマネージャーです。 KubernetesでHelm Chartsを使用すると、Kubernetesアプリケーションを更新、ロールバック、削除するための構成可能性とライフサイクル管理が提供されます。

このガイドでは、Helmを使用してKubernetesで維持されるNginx Ingress Controllerを設定します。 次に、ドメインからのトラフィックをサンプルのHello WorldバックエンドサービスにルーティングするIngressリソースを作成します。 Ingressを設定したら、Cert-Managerをクラスタにインストールして、Let's EncryptTLS証明書を自動的にプロビジョニングしてIngressを保護できるようにします。

前提条件

  • 接続構成がkubectlのデフォルトとして構成されたDigitalOceanKubernetesクラスター。 kubectlを構成する方法の説明は、クラスターの作成時に表示されるConnect to your Clusterステップの下に表示されます。 DigitalOceanでKubernetesクラスターを作成する方法については、Kubernetes Quickstartを参照してください。

  • ローカルマシンにインストールされたHelmパッケージマネージャー、およびクラスターにインストールされたTiller。 How To Install Software on Kubernetes Clusters with the Helm Package Managerチュートリアルのステップ1と2を完了します。

  • 2つの使用可能なAレコードを持つ完全に登録されたドメイン名。 このチュートリアルでは、全体を通してhw1.example.comhw2.example.comを使用します。 Namecheapでドメイン名を購入するか、Freenomで無料でドメイン名を取得するか、選択したドメインレジストラを使用できます。

[[step-1 -—- setting-up-hello-world-deployments]] ==ステップ1— HelloWorldデプロイメントのセットアップ

このセクションでは、Nginx Ingressをデプロイする前に、hello-kubernetesというHello Worldアプリをデプロイして、トラフィックをルーティングするサービスをいくつか用意します。 次の手順でNginx Ingressが適切に機能することを確認するために、ブラウザからアクセスしたときに表示される異なるウェルカムメッセージとともに、2回デプロイします。

ローカルコンピューターに展開構成を保存します。 最初のデプロイメント構成は、hello-kubernetes-first.yamlという名前のファイルにあります。 テキストエディタを使用して作成します。

nano hello-kubernetes-first.yaml

次の行を追加します。

hello-kubernetes-first.yaml

apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes-first
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes-first
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes-first
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes-first
  template:
    metadata:
      labels:
        app: hello-kubernetes-first
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.5
        ports:
        - containerPort: 8080
        env:
        - name: MESSAGE
          value: Hello from the first deployment!

この構成は、展開とサービスを定義します。 デプロイメントは、paulbouwer/hello-kubernetes:1.5イメージの3つのレプリカと、MESSAGEという名前の環境変数で構成されます。アプリにアクセスするとその値が表示されます。 ここでのサービスは、ポート80でクラスター内のデプロイメントを公開するように定義されています。

ファイルを保存して閉じます。

次に、次のコマンドを実行して、Kubernetesでhello-kubernetesアプリのこの最初のバリアントを作成します。

kubectl create -f hello-kubernetes-first.yaml

次の出力が表示されます。

Outputservice/hello-kubernetes-first created
deployment.apps/hello-kubernetes-first created

サービスの作成を確認するには、次のコマンドを実行します。

kubectl get service hello-kubernetes-first

出力は次のようになります。

OutputNAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
hello-kubernetes-first   ClusterIP   10.245.85.236           80:31623/TCP   35s

新しく作成されたサービスにはClusterIPが割り当てられていることがわかります。これは、サービスが適切に機能していることを意味します。 そこに送信されたすべてのトラフィックは、ポート8080で選択されたデプロイメントに転送されます。 hello-kubernetesアプリの最初のバリアントをデプロイしたので、2番目のバリアントで作業します。

編集のためにhello-kubernetes-second.yamlというファイルを開きます。

nano hello-kubernetes-second.yaml

次の行を追加します。

hello-kubernetes-second.yaml

apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes-second
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes-second
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes-second
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes-second
  template:
    metadata:
      labels:
        app: hello-kubernetes-second
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.5
        ports:
        - containerPort: 8080
        env:
        - name: MESSAGE
          value: Hello from the second deployment!

ファイルを保存して閉じます。

このバリアントは、前の構成と同じ構造を持ちます。唯一の違いは、衝突とメッセージを回避するための展開名とサービス名です。

次のコマンドを使用してKubernetesで作成します。

kubectl create -f hello-kubernetes-second.yaml

出力は次のようになります。

Outputservice/hello-kubernetes-second created
deployment.apps/hello-kubernetes-second created

すべてのサービスをリストして、2番目のサービスが稼働中であることを確認します。

kubectl get service

出力は次のようになります。

OutputNAME                            TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
hello-kubernetes-first          ClusterIP      10.245.85.236              80:31623/TCP                 54s
hello-kubernetes-second         ClusterIP      10.245.99.130              80:30303/TCP                 12s
kubernetes                      ClusterIP      10.245.0.1                 443/TCP                      5m

hello-kubernetes-firsthello-kubernetes-secondの両方が一覧表示されます。これは、Kubernetesがそれらを正常に作成したことを意味します。

付随するサービスを使用して、hello-kubernetesアプリの2つのデプロイメントを作成しました。 それぞれにデプロイメント仕様に異なるメッセージセットがあり、テスト中にそれらを区別できます。 次のステップでは、Nginx Ingress Controller自体をインストールします。

[[step-2 -—- installing-the-kubernetes-nginx-ingress-controller]] ==ステップ2— Kubernetes Nginx IngressControllerのインストール

次に、Helmを使用してKubernetesで管理されているNginx Ingress Controllerをインストールします。 いくつかのNginx Ingressesがあることに注意してください。

Nginx Ingress Controllerは、ポッドとサービスで構成されています。 ポッドはコントローラーを実行します。コントローラーは、クラスターのAPIサーバー上の/ingressesエンドポイントを常にポーリングして、使用可能な入力リソースの更新を確認します。 サービスのタイプはLoadBalancerであり、DigitalOcean Kubernetesクラスターにデプロイしているため、クラスターは自動的にDigitalOcean Load Balancerを作成し、それを介してすべての外部トラフィックがコントローラーに流れます。 コントローラは、入力リソースで定義されているように、適切なサービスにトラフィックをルーティングします。

LoadBalancerサービスのみが、自動的に作成されたロードバランサーのIPアドレスを認識します。 一部のアプリ(ExternalDNSなど)はIPアドレスを知る必要がありますが、Ingressの構成のみを読み取ることができます。 コントローラは、helm installの間にcontroller.publishService.enabledパラメータをtrueに設定することにより、各入力でIPアドレスを公開するように構成できます。 ロードバランサーのIPアドレスに依存する可能性のあるアプリケーションをサポートするには、この設定を有効にすることをお勧めします。

Nginx Ingress Controllerをクラスターにインストールするには、次のコマンドを実行します。

helm install stable/nginx-ingress --name nginx-ingress --set controller.publishService.enabled=true

このコマンドは、stableチャートリポジトリからNginx Ingress Controllerをインストールし、Helmリリースにnginx-ingressという名前を付け、publishServiceパラメーターをtrueに設定します。

出力は以下のようになります。

OutputNAME:   nginx-ingress
LAST DEPLOYED: ...
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                      DATA  AGE
nginx-ingress-controller  1     0s

==> v1/Pod(related)
NAME                                            READY  STATUS             RESTARTS  AGE
nginx-ingress-controller-7658988787-npv28       0/1    ContainerCreating  0         0s
nginx-ingress-default-backend-7f5d59d759-26xq2  0/1    ContainerCreating  0         0s

==> v1/Service
NAME                           TYPE          CLUSTER-IP     EXTERNAL-IP  PORT(S)                     AGE
nginx-ingress-controller       LoadBalancer  10.245.9.107       80:31305/TCP,443:30519/TCP  0s
nginx-ingress-default-backend  ClusterIP     10.245.221.49         80/TCP                      0s

==> v1/ServiceAccount
NAME           SECRETS  AGE
nginx-ingress  1        0s

==> v1beta1/ClusterRole
NAME           AGE
nginx-ingress  0s

==> v1beta1/ClusterRoleBinding
NAME           AGE
nginx-ingress  0s

==> v1beta1/Deployment
NAME                           READY  UP-TO-DATE  AVAILABLE  AGE
nginx-ingress-controller       0/1    1           0          0s
nginx-ingress-default-backend  0/1    1           0          0s

==> v1beta1/Role
NAME           AGE
nginx-ingress  0s

==> v1beta1/RoleBinding
NAME           AGE
nginx-ingress  0s

NOTES:
...

Helmは、チャートインストールの一部として作成したKubernetesのリソースをログに記録しました。

以下を実行することにより、Load Balancerが利用可能になるのを見ることができます。

kubectl get services -o wide -w nginx-ingress-controller

Kubernetesコミュニティが管理するNginx Ingressをインストールしました。 HTTPおよびHTTPSトラフィックをロードバランサーから、イングレスリソースで構成された適切なバックエンドサービスにルーティングします。 次のステップでは、Ingressリソースを使用してhello-kubernetesアプリのデプロイを公開します。

[[step-3 -—- exposed-the-app-using-an-ingress]] ==ステップ3—Ingressを使用してアプリを公開する

次に、入力リソースを作成し、それを使用して、目的のドメインでのhello-kubernetesアプリのデプロイを公開します。 次に、ブラウザからアクセスしてテストします。

Ingressをhello-kubernetes-ingress.yamlという名前のファイルに保存します。 エディターを使用して作成します。

nano hello-kubernetes-ingress.yaml

ファイルに次の行を追加します。

hello-kubernetes-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: hw1.example.com
    http:
      paths:
      - backend:
          serviceName: hello-kubernetes-first
          servicePort: 80
  - host: hw2.example.com
    http:
      paths:
      - backend:
          serviceName: hello-kubernetes-second
          servicePort: 80

上記のコードでは、hello-kubernetes-ingressという名前の入力リソースを定義します。 次に、2つのホストルールを指定して、hw1.example.comhello-kubernetes-firstサービスにルーティングされ、hw2.example.comが2番目の展開(hello-kubernetes-second)からサービスにルーティングされるようにします。

強調表示されたドメインを自分のドメインに置き換えてから、ファイルを保存して閉じてください。

次のコマンドを実行してKubernetesで作成します。

kubectl create -f hello-kubernetes-ingress.yaml

次に、2つのドメインがAレコードを介してロードバランサーを指していることを確認する必要があります。 これは、DNSプロバイダーを介して行われます。 DigitalOceanでDNSレコードを構成するには、How to Manage DNS Recordsを参照してください。

これで、ブラウザでhw1.example.comに移動できます。 以下が表示されます。

Hello Kubernetes - First Deployment

2番目のバリアント(hw2.example.com)は、異なるメッセージを表示します。

Hello Kubernetes - Second Deployment

これで、Ingress Controllerがリクエストを正しくルーティングすることを確認できました。この場合、2つのドメインから2つの異なるサービスへ。

ドメインでhello-kubernetesアプリのデプロイを提供するための入力リソースを作成して構成しました。 次のステップでは、Cert-Managerをセットアップします。これにより、Let’s Encryptからの無料のTLS証明書でIngressリソースを保護できます。

[[step-4 -—- securing-the-ingress-using-cert-manager]] ==ステップ4—Cert-Managerを使用して入力を保護する

Ingressリソースを保護するには、Cert-Managerをインストールし、実稼働用のClusterIssuerを作成し、TLS証明書を利用するようにIngressの構成を変更します。 ClusterIssuersは、TLS証明書をプロビジョニングするKubernetesの証明書マネージャーリソースです。 インストールして構成すると、アプリはHTTPSの背後で実行されます。

Helmを介してCert-Managerをクラスターにインストールする前に、次のコマンドを実行して、jetstack / cert-managerリポジトリから必要なCRDs(カスタムリソース定義)を手動で適用します。

kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.8/deploy/manifests/00-crds.yaml

次の出力が表示されます。

Outputcustomresourcedefinition.apiextensions.k8s.io/certificates.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/challenges.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/issuers.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/orders.certmanager.k8s.io created

これは、Kubernetesがcert-managerに必要なカスタムリソースを適用したことを示しています。

[。注意]##

Note:このチュートリアルと前提条件に従っている場合は、cert-managerというKubernetes名前空間を作成していないため、このノートブロックでコマンドを実行する必要はありません。 ただし、この名前空間がクラスターに存在する場合は、次のコマンドでCert-Managerに検証しないよう通知する必要があります。

kubectl label namespace cert-manager certmanager.k8s.io/disable-validation="true"

The Webhook component of Cert-Managerは、KubernetesAPIサーバーと安全に通信するためにTLS証明書を必要とします。 Cert-Managerが初めて証明書を生成するには、デプロイされているネームスペースでリソース検証を無効にする必要があります。 そうしないと、無限ループに陥ります。 APIに接続できず、TLS証明書を生成できません。

出力は次のようになります。

Outputnamespace/cert-manager labeled

次に、Cert-ManagerチャートをホストするHelmにJetstack Helm repositoryを追加する必要があります。 これを行うには、次のコマンドを実行します。

helm repo add jetstack https://charts.jetstack.io

Helmは次の出力を表示します。

Output"jetstack" has been added to your repositories

最後に、Cert-Managerをcert-manager名前空間にインストールします。

helm install --name cert-manager --namespace cert-manager jetstack/cert-manager

次の出力が表示されます。

OutputNAME:   cert-manager
LAST DEPLOYED: ...
NAMESPACE: cert-manager
STATUS: DEPLOYED

RESOURCES:
==> v1/ClusterRole
NAME                                    AGE
cert-manager-edit                       3s
cert-manager-view                       3s
cert-manager-webhook:webhook-requester  3s

==> v1/Pod(related)
NAME                                     READY  STATUS             RESTARTS  AGE
cert-manager-5d669ffbd8-rb6tr            0/1    ContainerCreating  0         2s
cert-manager-cainjector-79b7fc64f-gqbtz  0/1    ContainerCreating  0         2s
cert-manager-webhook-6484955794-v56lx    0/1    ContainerCreating  0         2s

...

NOTES:
cert-manager has been deployed successfully!

In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).

More information on the different types of issuers and how to configure them
can be found in our documentation:

https://docs.cert-manager.io/en/latest/reference/issuers.html

For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:

https://docs.cert-manager.io/en/latest/reference/ingress-shim.html

出力は、インストールが成功したことを示しています。 出力のNOTESにリストされているように、TLS証明書を発行するように発行者を設定する必要があります。

次に、Let's Encrypt証明書を発行する証明書を作成し、その構成をproduction_issuer.yamlという名前のファイルに保存します。 作成して編集用に開きます。

nano production_issuer.yaml

次の行を追加します。

production_issuer.yaml

apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: your_email_address
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod
    # Enable the HTTP-01 challenge provider
    http01: {}

この構成では、証明書を発行するためにLet's Encryptに接続するClusterIssuerを定義します。 証明書のセキュリティと有効期限に関する緊急の通知を受け取るには、your_email_addressをメールアドレスに置き換える必要があります。

ファイルを保存して閉じます。

kubectlでロールアウトします。

kubectl create -f production_issuer.yaml

次の出力が表示されます。

Outputclusterissuer.certmanager.k8s.io/letsencrypt-prod created

Cert-Managerをインストールしたら、前の手順で定義したIngressリソースに証明書を導入する準備が整いました。 編集のためにhello-kubernetes-ingress.yamlを開きます。

nano hello-kubernetes-ingress.yaml

強調表示された行を追加します。

hello-kubernetes-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - hw1.example.com
    - hw2.example.com
    secretName: letsencrypt-prod
  rules:
  - host: hw1.example.com
    http:
      paths:
      - backend:
          serviceName: hello-kubernetes-first
          servicePort: 80
  - host: hw2.example.com
    http:
      paths:
      - backend:
          serviceName: hello-kubernetes-second
          servicePort: 80

specの下のtlsブロックは、サイトの証明書(hostsの下にリストされている)が証明書を格納するシークレットを定義します。これは、letsencrypt-prodClusterIssuerが発行します。 これは、作成するIngressごとに異なる必要があります。

hw1.example.comhw2.example.comを独自のドメインに置き換えることを忘れないでください。 編集が終了したら、ファイルを保存して閉じます。

次のコマンドを実行して、この構成をクラスターに再適用します。

kubectl apply -f hello-kubernetes-ingress.yaml

次の出力が表示されます。

Outputingress.extensions/hello-kubernetes-ingress configured

Let's Encryptサーバーがドメインの証明書を発行するまで数分待つ必要があります。 それまでの間、次のコマンドの出力を調べることで進捗を追跡できます。

kubectl describe certificate letsencrypt-prod

出力の最後は次のようになります。

OutputEvents:
  Type    Reason              Age   From          Message
  ----    ------              ----  ----          -------
  Normal  Generated           56s   cert-manager  Generated new private key
  Normal  GenerateSelfSigned  56s   cert-manager  Generated temporary self signed certificate
  Normal  OrderCreated        56s   cert-manager  Created Order resource "hello-kubernetes-1197334873"
  Normal  OrderComplete       31s   cert-manager  Order "hello-kubernetes-1197334873" completed successfully
  Normal  CertIssued          31s   cert-manager  Certificate issued successfully

出力の最後の行にCertificate issued successfullyが表示されたら、CTRL + Cを押して終了できます。 ブラウザでドメインの1つに移動してテストします。 ブラウザのアドレスバーの左側に南京錠が表示され、接続が安全であることを示します。

この手順では、Helmを使用してCert-Managerをインストールし、Let’s Encrypt ClusterIssuerを作成しました。 その後、イングレスリソースを更新して、発行者を利用してTLS証明書を生成しました。 最後に、ブラウザでドメインの1つに移動して、HTTPSが正しく機能することを確認しました。

結論

これで、Helmを使用してDigitalOcean KubernetesクラスターでNginx Ingress ControllerとCert-Managerを正常にセットアップできました。 これで、Let’s Encrypt TLS証明書を使用して保護された、ドメインでインターネットにアプリを公開できるようになりました。

Helmパッケージマネージャーの詳細については、このintroduction articleをお読みください。

Related