Ingress Nginx Controller で Kubernetes アプリケーションアクセスを最適化する

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

クイックスタート: 初めての Kubernetes アプリを公開する (5分でセットアップ)

Kubernetes クラスターの外部からアプリケーションにアクセスできるようにするのは、迷路を進むように感じるかもしれません。Service は内部ロードバランシングを提供しますが、それだけでは不十分な場合はどうでしょうか?高度なルーティング、SSL 終端、または複数のアプリケーションに対する単一のエントリポイントが必要な場合はどうでしょうか?

そこで登場するのが Ingress Nginx Controller です。これは Kubernetes 用の特殊なロードバランサーです。Nginx を活用してクラスターのサービスへの外部アクセスを管理します。これはクラスターの交通整理係と考えるとよいでしょう。外部からのリクエストを正しい内部サービスに誘導します。

実際に動作を見るために、基本的なセットアップを行ってみましょう。

ステップ1: Nginx Ingress Controller をデプロイする

まず、Ingress Nginx Controller 自体をインストールする必要があります。推奨される方法は Helm を使用することです。これによりデプロイが大幅に簡素化されます。


# ingress-nginx Helm リポジトリを追加
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# Ingress Nginx Controller をインストール
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace

このコマンドは、Nginx Ingress Controller を独自の ingress-nginx ネームスペースにデプロイします。Pod が起動し、LoadBalancer サービスが外部 IP を取得するまでに1〜2分かかる場合があります。

ステップ2: Controller のデプロイを確認する

コントローラーが実行中であり、外部 IP を持っているかどうかを確認できます。


kubectl get services -n ingress-nginx

ingress-nginx-controller サービスを探してください。これには EXTERNAL-IP が表示されているはずです。これがアプリケーションにアクセスするために使用する IP アドレスです。

ステップ3: サンプルアプリケーションをデプロイする

この例では、シンプルな Nginx ウェブサーバーアプリケーションをデプロイしてみましょう。nginx-app.yaml という名前のファイルを作成します。


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

これをクラスターに適用します。


kubectl apply -f nginx-app.yaml

ステップ4: Ingress リソースを作成する

次に、Ingress Nginx Controller に nginx-service へのトラフィックをルーティングする方法を指示しましょう。nginx-ingress.yaml という名前のファイルを作成します。


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  ingressClassName: nginx # これは Nginx Ingress Controller にリンクします
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

この Ingress リソースを適用します。


kubectl apply -f nginx-ingress.yaml

ステップ5: アプリケーションにアクセスする

ingress-nginx-controller サービスの EXTERNAL-IP を再度取得します。


kubectl get services -n ingress-nginx

ウェブブラウザを開き、http://<EXTERNAL-IP> にアクセスしてください。Nginx のデフォルトのウェルカムページが表示されるはずです!

これでクイックスタートは完了です。Ingress Nginx Controller を使用して、Kubernetesアプリケーションを正常に公開できました。このセットアップは、Kubernetes を扱うすべての人にとって不可欠です。ほとんどのプロダクションアプリケーションがアクセスされる方法の基礎を形成します。

詳細解説: Kubernetes Ingress と Nginx Controller を理解する

何かが動作するようになったので、何が起こっているのかを掘り下げてみましょう。Ingress とは正確には何であり、なぜ Nginx Controller はこれほど人気があるのでしょうか?

問題: サービスの公開

Kubernetes では、Pod は一時的であり、内部 IP アドレスを持ちます。Service は、一連の Pod に対して安定した IP と DNS 名を提供します。しかし、ClusterIP タイプの Service はクラスター内からしかアクセスできません。外部アクセスの場合、通常は NodePortLoadBalancer サービスのような選択肢があります。

  • NodePort: 各 Node の IP 上の静的ポートで Service を公開します。シンプルですが、ポートを消費し、本番環境には理想的ではありません。
  • LoadBalancer: Service 用に外部のクラウドロードバランサーをプロビジョニングします。シンプルな公開には優れていますが、コストがかかる可能性があり、Service ごとに1つの LoadBalancer が割り当てられるため、多数のアプリケーションの管理オーバーヘッドが増大します。

解決策: Kubernetes Ingress

Ingress は、クラスター内のサービスへの外部アクセスを管理する API オブジェクトであり、通常は HTTP です。リクエストのホストまたはパスに基づいて、HTTP および HTTPS ルーティングをサービスに提供します。Ingress を使用すると、Ingress Controller によって提供される単一の外部 IP アドレスの背後で、複数のサービスのルーティングルールを統合できます。

Ingress の主な利点:

  • 一元化されたルーティング: すべての外部ルートを1か所で管理します。
  • 単一のエントリポイント: 多数のアプリケーションに1つの外部 IP/LoadBalancer を使用します。
  • レイヤー7機能: パスベースのルーティング (例: /api vs. /blog)、ホストベースのルーティング (例: app.example.com vs. admin.example.com)。
  • SSL/TLS 終端: クラスターのエッジで HTTPS トラフィックを処理し、アプリケーションコードを簡素化します。
  • ロードバランシング: バックエンドサービス全体にトラフィックを分散します。

Nginx Ingress Controller: 仕組み

Ingress Controller は、Ingress リソースを実現するための特殊なソフトウェアです。Nginx Ingress Controller は、堅牢で高性能な Nginx ウェブサーバーを活用しているため、最も広く使用されているものの1つです。

  1. Ingress Nginx Controller は、クラスター内で Pod (高可用性の場合は複数の Pod) として動作します。
  2. 新しいまたは更新された Ingress リソースについて Kubernetes API を監視します。
  3. Ingress リソースが作成または変更されると、コントローラーはその設定を取得し、対応する Nginx 設定ファイルを生成します。
  4. その後、接続を切断することなく、新しい設定で Nginx をリロードします。
  5. 外部トラフィックは LoadBalancer Service (通常、Ingress Nginx Controller が公開するもの) に到達します。
  6. LoadBalancer は Ingress Nginx Controller Pod にトラフィックを転送します。
  7. Nginx は、生成された設定に基づいて、リクエストを正しい内部 Kubernetes Service にルーティングします。

私の経験では、Ingress リソースと Nginx Ingress Controller の間のこの相互作用を理解することは、Kubernetes を扱うすべての人にとって本当に重要なスキルです。この内部クラスターネットワークと外部世界との間の橋渡しにより、アプリケーションはアクセス可能で管理しやすくなります。

高度な使用法: 基本的なルーティングを超えて

Ingress Nginx Controller は、シンプルなパスベースのルーティング以上の多くの機能を提供します。いくつかの一般的な高度なパターンを見てみましょう。

ホストベースのルーティング

リクエストヘッダーのホスト名に基づいてトラフィックをルーティングできます。これは、異なるドメイン名を使用して同じ Ingress Controller から複数のアプリケーションを提供する場合に一般的です。


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multiple-hosts-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 80

これを機能させるには、DNS を設定して app.example.comadmin.example.com の両方を Ingress Nginx Controller の EXTERNAL-IP にポイントする必要があります。

Cert-Manager を使用した SSL/TLS 終端

HTTPS の処理は非常に重要です。Ingress Nginx Controller は SSL/TLS を終端できます。TLS 証明書用の Kubernetes Secret を手動で作成することもできますが、Let’s Encrypt を使用してプロセスを自動化するために Cert-Manager を使用するのが一般的で強く推奨されるアプローチです。


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

helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.11.0 \
  --set installCRDs=true

次に、Let’s Encrypt 用の ClusterIssuer を作成します (例: letsencrypt-prod.yaml)。


apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # ACME サーバーの URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # ACME 登録に使用するメールアドレス
    email: [email protected] # <-- ここを変更
    # ACME アカウントの秘密鍵を保存するために使用されるシークレットの名前
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
    - http01:
        ingress:
          class: nginx

これを適用します: kubectl apply -f letsencrypt-prod.yaml

最後に、証明書を要求するように Ingress リソースを変更します。


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-tls-ingress
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.example.com # <-- ここを変更
    secretName: myapp-tls-secret
  rules:
  - host: myapp.example.com # <-- ここを変更
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

Cert-Manager は、SSL 証明書を自動的にプロビジョニングおよび更新します。secretName は自動的に作成されます。

基本認証

Ingress アノテーションを介して HTTP 基本認証でパスを直接保護できます。まず、htpasswd ファイルを生成します (オンラインジェネレーターまたは htpasswd -nb user password を使用できます)。


# 例: user:password は admin:password123 です
PASSWORD_HASH=$(printf "admin:$(echo -n 'password123' | openssl passwd -stdin -apr1)")
kubectl create secret generic basic-auth-secret --from-literal=auth=$PASSWORD_HASH

次に、Ingress を更新します。


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-auth-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth-secret
    nginx.ingress.kubernetes.io/auth-realm: "認証が必要です"
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: admin-service # 管理サービスがあると仮定
            port:
              number: 80

アノテーションによるカスタム Nginx 設定

Nginx Ingress Controller は、その動作を細かく調整するための多くの Nginx 固有のアノテーションをサポートしています。これらにより、コントローラーの基になる設定を直接変更することなく、カスタム Nginx ディレクティブを注入できます。

たとえば、カスタムクライアントボディサイズ制限を設定するには:


metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: 8m

Ingress Nginx Controller を管理するための実践的なヒント

モニタリングとロギング

Ingress Nginx Controller のモニタリングは常に有効にしてください。Prometheus と Grafana は、これに最適なツールです。コントローラーは、リクエストレート、エラーレート、応答時間に関する洞察を提供するメトリクスを公開します。ルーティングの問題やエラーについては、コントローラーのログ (kubectl logs -n ingress-nginx <controller-pod-name>) を確認してください。

一般的な問題のトラブルシューティング

  • 404 Not Found:
    • Ingress リソースが正しく適用されているか確認します (kubectl get ingress)。
    • ingressClassName: nginx が正しく設定されていることを確認します。
    • Ingress 内のバックエンドサービスとポート名が実際の Service リソースと一致しているか確認します。
    • Ingress Nginx Controller のログに Ingress 定義の解析エラーがないか確認します。
  • 503 Service Unavailable:
    • これは通常、Nginx がバックエンドサービスに到達できないことを意味します。
    • Service が正常な Pod を指しているか確認します (kubectl get pods -l app=<あなたのアプリのラベル> および kubectl describe service <あなたのサービス名>)。
  • SSL/TLS エラー:
    • Cert-Manager を使用している場合は、Certificate および CertificateRequest リソースのログとイベントを確認します (kubectl describe certificate <証明書名>)。
    • DNS A/CNAME レコードが Ingress Controller の外部 IP を指していることを確認します。
    • ClusterIssuer の設定を確認します。

特定の IngressClass の使用

クラスター内で複数の Ingress Controller (例: Nginx、Traefik、GKE Ingress) を実行している場合、それぞれに IngressClass リソースを定義します。Ingress リソースは、ingressClassName フィールドを使用して、どのコントローラーがそれらを処理するかを指定します。


apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx

これは、競合を防ぎ、Ingress リソースが正しいコントローラーによって取得されるようにするために重要です。

セキュリティに関する考慮事項

  • ネットワークポリシー: Kubernetes ネットワークポリシーを使用して、Ingress Controller と通信できるもの、およびコントローラーが内部で通信できるものを制限します。
  • 最小権限: Ingress Controller の ServiceAccount が必要な権限のみを持っていることを確認します。
  • 定期的な更新: セキュリティ修正と新機能の恩恵を受けるために、Ingress Nginx Controller を常に最新の状態に保ってください。

Nginx Ingress Controller を使用すると、アプリケーションの公開を細かく制御できます。これにより、Kubernetes 環境内でのセキュリティ、管理の容易さ、およびスケーラビリティが向上します。

Share: