Kubernetes Ingress ControllerとしてのNginx入門 – 機能、設定、運用のすべて
はじめに
現代のアプリケーション開発において、コンテナ化とマイクロサービスアーキテクチャは広く普及しています。その中心的な役割を担うプラットフォームがKubernetesです。Kubernetesは、コンテナ化されたアプリケーションのデプロイ、スケーリング、管理を自動化するための強力なツールセットを提供します。
Kubernetesクラスター内で実行されるアプリケーション(Podとして動作し、Serviceによって抽象化される)に、外部からどのようにアクセスさせるかは重要な課題です。WebアプリケーションやAPIサービスを提供する場合、ユーザーからのHTTP/HTTPSリクエストをクラスター内の適切なサービスにルーティングする必要があります。この役割を担うのが、KubernetesのIngressリソースと、それを実装するIngress Controllerです。
Ingressは、クラスター内のサービスに対する外部からのアクセス(主にHTTP/HTTPS)を管理するためのAPIオブジェクトです。これは、ロードバランシング、SSL終端、名前ベースの仮想ホスティングなどを設定するための一元的な方法を提供します。しかし、Ingressリソース自体は定義に過ぎず、実際にその定義を読み取ってトラフィックを処理する実体が必要です。これがIngress Controllerです。
数多くのIngress Controllerが存在しますが、その中でも最も広く使われ、信頼されているのがNginx Ingress Controllerです。Nginxは高性能なWebサーバーおよびリバースプロキシとして知られており、その実績と柔軟性からKubernetes環境でも非常に人気があります。
この記事では、KubernetesにおけるNginx Ingress Controllerに焦点を当て、その機能、インストール方法、基本的な設定から高度な利用方法、運用上の考慮事項までを詳細に解説します。この記事を読むことで、Nginx Ingress Controllerを使ってKubernetes上のサービスを外部に公開する方法を完全に理解できるでしょう。
Kubernetes Ingressとは何か
Kubernetesでは、アプリケーションはPodとして実行され、Serviceによって抽象化され、内部からアクセスできるようになります。Serviceは、Podへの安定したアクセスエンドポイント(クラスタIP、ポート)を提供しますが、これは主にクラスター内部での通信や、限定的な外部公開(NodePortやLoadBalancer Service Type)に使用されます。
WebアプリケーションやAPIのように、インターネットからドメイン名(例: myapp.example.com
)やパス(例: /api/v1/users
)に基づいてリクエストをルーティングしたい場合、Serviceの機能だけでは不十分です。また、SSL/TLS終端、複数のホスト名の処理、パスベースのルーティング、ロードバランシング、認証、レート制限といった高度な機能も必要になることがよくあります。
Ingressは、このような外部からのアクセスを管理するための高レベルな抽象化レイヤーを提供します。Ingressリソースは、以下の主要な機能を定義できます。
- 仮想ホスティング(Virtual Hosting): 複数のドメイン名(例:
app1.example.com
,app2.example.com
)を一つのIPアドレスで処理し、それぞれのドメイン名に対応するサービスにトラフィックを振り分ける。 - パスベースのルーティング(Path-based Routing): 同じドメイン名でも、URLのパス(例:
/users
,/products
)によって異なるサービスにトラフィックを振り分ける。 - SSL/TLS終端(SSL/TLS Termination): クラスターの入口でSSL/TLS接続を終端し、後続のトラフィックを暗号化せずにサービスに転送する(または再暗号化する)。これにより、各マイクロサービスでの証明書管理が不要になる。
- ロードバランシング(Load Balancing): バックエンドのServiceに紐づくPod間でトラフィックを分散する。
- その他の機能: 認証、レート制限、ヘッダー操作、リライターなど、Ingress Controllerが提供する高度な機能を利用するためのインターフェース。
Ingressリソースはただの設定情報であり、それ自体がトラフィックを処理するわけではありません。Ingressリソースの定義を監視し、それを実際のロードバランシングやリバースプロキシの設定に変換して適用するコンポーネントが必要です。これがIngress Controllerです。
Ingress ControllerはKubernetesクラスター上でPodとして動作し、Kubernetes APIを通じてIngressリソースの変更を常に監視しています。Ingressリソースが作成、更新、削除されると、Ingress Controllerはその情報を読み取り、自身が管理するロードバランシングソフトウェア(Nginx, HAProxy, Envoyなど)の設定を動的に更新します。これにより、Ingressリソースで定義されたルーティングルールが実際に有効になります。
様々なベンダーやコミュニティが独自のIngress Controllerを提供しています。代表的なものとして、Nginx Ingress Controller(コミュニティ版およびNginx, Inc.版)、HAProxy Ingress, Traefik, Istio Gateway, そして主要なクラウドプロバイダーが提供するIngress Controller(GCE Ingress for Google Cloud, AWS ALB Ingress Controller for AWS, Azure Application Gateway Ingress Controller for Azure)などがあります。この記事では、その中でも最も普及しているNginx Ingress Controller (Kubernetes community maintained) に焦点を当てます。
Nginx Ingress Controllerの概要
Nginx Ingress Controller (kubernetes/ingress-nginx) は、Kubernetesコミュニティによってメンテナンスされている、Nginxをデータプレーンとして使用するIngress Controllerです。これは非常に人気があり、多くの本番環境で利用されています。
Nginx Ingress Controllerは、主に以下の2つの部分で構成されています。
- Controller: Kubernetes APIを監視し、Ingressリソース、Service、Endpoint、Secretなどの情報を取得します。これらの情報に基づいて、Nginxの設定ファイル(
nginx.conf
)を動的に生成します。設定ファイルが更新された場合、Nginxプロセスにリロードコマンドを送信して新しい設定を反映させます。この部分はGo言語で記述されたアプリケーションとして、Kubernetesクラスター上でPodとして動作します。 - Nginx: Controllerによって生成された設定ファイルに基づいて、実際のリクエストトラフィックを処理するWebサーバー/リバースプロキシです。これもController Pod内でサイドカーコンテナとして、あるいは同じPod内の別のプロセスとして実行されます。外部からのトラフィックはこのNginxプロセスによって受け付けられ、Ingressリソースの定義に従ってバックエンドのService Endpointに転送されます。
Nginx Ingress Controllerの特徴は、Nginxの持つ高性能と柔軟性をKubernetesのダイナミックな環境で活用できる点です。Nginxの設定は、Ingressリソースの標準フィールドに加えて、特定のAnnotationsを使用することで高度にカスタマイズできます。これにより、Nginxの豊富な機能をIngress経由で利用することが可能になります。
Nginx Ingress Controllerは通常、Service Type LoadBalancer
または NodePort
を持つKubernetes Serviceによって外部に公開されます。
- LoadBalancer: クラウド環境(GCP, AWS, Azureなど)では、Kubernetesクラスター外部のクラウドプロバイダーが提供するロードバランサー(例: AWS ALB/NLB, GCP GCLB, Azure Application Gateway)がプロビジョニングされ、Nginx Ingress Controller Serviceの前面に配置されます。外部トラフィックはこのロードバランサーを経由してIngress Controllerに到達します。最も一般的なプロダクション環境での構成です。
- NodePort: 各Worker Node上の指定されたポートでIngress Controller Serviceを公開します。外部からのトラフィックは、いずれかのWorker Nodeの指定ポートに到達すれば、Service ClusterIP経由でIngress Controller Podにルーティングされます。オンプレミス環境や、外部ロードバランサーを別途構築する場合によく利用されます。
- ClusterIP: クラスタ内部からのみアクセス可能にしたい場合や、外部ロードバランサー(ハードウェアL4/L7ロードバランサーなど)を別途用意し、そのターゲットとしてIngress Controller Pod群を指定する場合に使用します。
どのService Typeを選択するかは、Kubernetesが稼働している環境や要求される構成によって異なります。
Nginx Ingress Controllerのインストール
Nginx Ingress ControllerをKubernetesクラスターにインストールするには、いくつかの方法があります。
- YAML Manifests: 公式リポジトリに含まれるYAMLファイルを
kubectl apply
で直接適用する方法です。シンプルですが、カスタマイズやアップグレードの管理がやや面倒になることがあります。 - Helm: KubernetesのパッケージマネージャーであるHelmを使う方法です。設定のカスタマイズが容易で、アップグレードやロールバックの管理も効率的に行えます。公式ドキュメントでも推奨されており、最も一般的な方法です。
ここでは、Helmを使ったインストール手順を詳しく解説します。
前提条件:
- Kubernetesクラスターが構築済みであること。
kubectl
コマンドがクラスターに接続できること。- Helm v3がインストール済みであること。
Helmを使ったインストール手順:
-
Helmリポジトリの追加:
まず、Nginx Ingress ControllerのHelmリポジトリを追加します。bash
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update -
Nginx Ingress Controllerのインストール:
helm install
コマンドを使用してIngress Controllerをインストールします。インストール先のNamespace、リリース名、そしてService Typeなどの主要な設定を指定します。bash
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.service.type=LoadBalancer \
--set controller.replicaCount=2このコマンドの各オプションの意味は以下の通りです。
ingress-nginx
: リリース名です。任意の名前に変更できます。この名前は、インストールされるKubernetesリソース(Deployment, Service, Podなど)の名前にプレフィックスとして使われます。ingress-nginx/ingress-nginx
: インストールするチャート名です。ingress-nginx
リポジトリのingress-nginx
チャートを指定しています。--namespace ingress-nginx
: インストールするNamespaceを指定します。ingress-nginx
という名前のNamespaceが推奨されますが、任意に変更可能です。--create-namespace
: 指定したNamespaceが存在しない場合に新しく作成します。--set controller.service.type=LoadBalancer
: Controller ServiceのTypeをLoadBalancer
に設定します。これにより、クラウド環境では外部ロードバランサーが自動的にプロビジョニングされます。オンプレミス環境などでNodePortを使いたい場合は--set controller.service.type=NodePort
に、外部ロードバランサーを別途設定する場合は--set controller.service.type=ClusterIP
に変更します。--set controller.replicaCount=2
: Controller Podのレプリカ数を2に設定します。高可用性のために複数レプリカが推奨されます。
その他の設定項目は、
--set
オプションで複数指定するか、設定を記述したYAMLファイルを作成し--values your-values.yaml
オプションで指定することでカスタマイズ可能です。よくカスタマイズされる設定には以下のようなものがあります。controller.resources
: Controller Podに割り当てるCPUやメモリのリソース制限。controller.nodeSelector
,controller.tolerations
: 特定のノードにController Podを配置したい場合。controller.ingressClassResource.enabled
: IngressClassリソースを使用するかどうか(Kubernetes v1.18以降で推奨される方法)。controller.service.annotations
: プロビジョニングされるロードバランサーにクラウドプロバイダー固有のアノテーションを設定する場合(例: AWS NLBの設定など)。
-
インストールの確認:
インストールが完了したら、指定したNamespaceにPodやServiceがデプロイされているか確認します。bash
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
kubectl get ingressclass # Kubernetes v1.18+ の場合kubectl get svc -n ingress-nginx
の出力で、ingress-nginx-controller
ServiceのEXTERNAL-IPまたはPORTSを確認します。LoadBalancer
Typeの場合、EXTERNAL-IPが表示されるまでしばらく時間がかかることがあります。NodePort
Typeの場合、EXTERNAL-IPは<pending>
と表示されますが、PORTS列に80:<nodeport-http>/TCP,443:<nodeport-https>/TCP
のようにNodePortが表示されます。このNodePortを使って、クラスターのWorker NodeのIPアドレス経由でアクセスできます。ClusterIP
Typeの場合、EXTERNAL-IPは表示されず、CLUSTER-IPのみが表示されます。これはクラスター内部からのアクセス用です。 -
必要なRBACリソース:
Helmチャートには、Ingress ControllerがKubernetes APIを操作するために必要なRole, ClusterRole, ServiceAccount, RoleBinding, ClusterRoleBindingといったRBACリソースも含まれています。これらはインストール時に自動的に作成されるため、通常は手動で設定する必要はありません。
これで、Nginx Ingress ControllerがKubernetesクラスターにインストールされ、外部からのトラフィックを受け付ける準備ができました。
基本的なIngressリソースの作成と設定
Nginx Ingress Controllerがインストールされたら、次にIngressリソースを作成して、どのドメイン名やパスへのトラフィックをどのサービスにルーティングするかを定義します。
IngressリソースはKubernetesのAPIオブジェクトであり、YAMLファイルで定義します。基本的なIngressリソースの構造は以下のようになります。
“`yaml
apiVersion: networking.k8s.io/v1 # または extensions/v1beta1 (非推奨), networking.k8s.io/v1beta1 (非推奨)
kind: Ingress
metadata:
name: my-app-ingress
namespace: default # Ingressリソースとバックエンドサービスは同じNamespaceにあるのが一般的
annotations:
# Nginx Ingress Controller 固有の設定をここに記述
# nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
# IngressClass を指定する場合 (Kubernetes v1.18+ 推奨)
ingressClassName: nginx
# TLS 設定 (オプション)
# spec.tls が存在する場合、指定された Secret から証明書をロードし、TLS 終端を行う
tls:
– hosts:
– myapp.example.com
secretName: myapp-tls-secret # TLS 証明書を含む Secret の名前
# ルーティングルール
rules:
# ホストベースのルーティング (オプション)
– host: myapp.example.com
http:
paths:
# パスベースのルーティング
– path: / # “/” または “/api”, “/admin” など
pathType: Prefix # または Exact, ImplementationSpecific
backend:
service:
name: my-app-service # ルーティング先の Service 名
port:
number: 80 # ルーティング先の Service のポート番号
# デフォルトバックエンド (オプション) – 上記 rules にマッチしない場合に使われる
# defaultBackend:
# service:
# name: default-backend-service # デフォルトバックエンド用の Service 名
# port:
# number: 80
“`
各フィールドについて詳しく説明します。
-
apiVersion
,kind
,metadata
: Kubernetesリソースの標準フィールドです。kind: Ingress
は、これがIngressリソースであることを示します。metadata.name
: Ingressリソースの一意な名前を指定します。metadata.namespace
: Ingressリソースが所属するNamespaceを指定します。バックエンドとして指定するServiceも通常このNamespaceに存在します。metadata.annotations
: Ingress Controller固有の設定や追加機能を有効にするために使用します。Nginx Ingress Controllerは多くの独自のAnnotationを提供しています(後述)。
-
spec
: Ingressリソースの定義の本体です。ingressClassName
: (Kubernetes v1.18以降推奨) どのIngress ControllerがこのIngressリソースを処理するかを指定します。インストール時に作成されるIngressClassリソースの名前(Helmでインストールした場合のデフォルトはnginx
)を指定します。このフィールドがない場合、またはAnnotation (kubernetes.io/ingress.class
) で指定されている場合は、その指定が優先されます(ただしAnnotationは非推奨)。複数のIngress Controllerがクラスターにインストールされている場合に重要です。tls
: TLS/SSL終端に関する設定を行います。複数のエントリを持つことができ、それぞれ異なるホスト名と証明書Secretを指定できます。secretName
には、TLS証明書(tls.crt
)と秘密鍵(tls.key
)を含むKubernetes Secretの名前を指定します。Ingress ControllerはこのSecretを読み取ってTLS接続を終端します。-
rules
: 実際のルーティングルールを定義します。複数のルールを定義できます。rules.host
: このルールが適用されるホスト名(ドメイン名)を指定します。省略した場合、このルールは全てのホスト名に適用されます。ワイルドカードも使用できます(例:*.example.com
)。rules.http.paths
: HTTP/HTTPSリクエストのパスに関するルーティングを定義します。複数のパスエントリを持つことができます。paths.path
: マッチさせたいURLパスを指定します。paths.pathType
: パスのマッチング方法を指定します。Prefix
: 指定されたパスで始まる全てのURLにマッチします(例:/api
は/api
,/api/users
,/api/products
などにマッチ)。/
は全てのリクエストにマッチするデフォルトのパスとしてよく使われます。Exact
: 指定されたパスと完全に一致する場合のみマッチします(例:/users
は/users
にのみマッチ)。ImplementationSpecific
: Ingress Controllerの実装に依存するマッチング方法です。Nginx Ingress Controllerの場合、これはPrefixと似ていますが、正規表現なども利用できる場合があります(ただしAnnotationで指定するのが一般的)。通常はPrefix
またはExact
を使用します。
paths.backend
: マッチしたリクエストを転送するバックエンドサービスを指定します。backend.service.name
: 転送先のKubernetes Serviceの名前を指定します。backend.service.port.number
: 転送先のServiceのポート番号を指定します。
-
defaultBackend
: (オプション)rules
に定義されたどのホスト名やパスにもマッチしなかった場合に、リクエストを転送するデフォルトのバックエンドサービスを指定します。何も指定しない場合、通常は404 Not Foundエラーが返されます。
基本的なIngress設定例:
my-app-ingress.yaml
という名前でファイルを作成します。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
namespace: default
spec:
ingressClassName: nginx # インストール時に指定した IngressClass 名に合わせる
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service # 後で作成する Service の名前
port:
number: 80 # 後で作成する Service のターゲットポート
このIngressリソースを機能させるためには、バックエンドとなるKubernetes Serviceと、そのServiceに紐づくPod(Deploymentなど)が必要です。以下に簡単な例を示します。
my-app-service.yaml
“`yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-deployment
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
– name: my-app-container
image: nginxdemos/hello # ダミーの Web サーバーイメージ
ports:
– containerPort: 80
apiVersion: v1
kind: Service
metadata:
name: my-app-service
namespace: default
spec:
selector:
app: my-app
ports:
– protocol: TCP
port: 80 # Service のポート
targetPort: 80 # Pod のコンテナポート
“`
これらのリソースをクラスターに適用します。
bash
kubectl apply -f my-app-service.yaml
kubectl apply -f my-app-ingress.yaml
リソースが作成されたことを確認します。
bash
kubectl get deploy,svc,ing -n default
IngressリソースのSTATUS列にEXTERNAL-IP(LoadBalancer Typeの場合)が表示されていることを確認します。NodePort Typeの場合はNodePortが表示されます。
次に、このIngressに外部からアクセスできるようにDNSを設定します。LoadBalancer Typeの場合、取得したEXTERNAL-IPに対して、指定したホスト名 (myapp.example.com
) のAレコードをDNSサーバーに登録します。NodePort Typeの場合、クラスターのWorker NodeのいずれかのIPアドレスに対してAレコードを登録し、アクセス時にNodePortを指定します(通常は別途外部ロードバランサーやプロキシを設定してポート変換を行います)。
DNS設定が反映されたら、Webブラウザや curl
コマンドでアクセスして動作を確認します。
bash
curl http://myapp.example.com/
Nginx Ingress Controller経由で my-app-service
に紐づくPodにリクエストがルーティングされ、アプリケーションの応答が表示されるはずです。
高度なIngress設定(Annotationsの活用)
Nginx Ingress Controllerは、Ingressリソースの metadata.annotations
フィールドを使用して、Nginx固有の高度な設定を適用するための豊富なAnnotationセットを提供しています。これにより、標準のIngressリソースだけでは実現できない詳細な制御や機能を利用できます。
代表的なAnnotationsとその使用例をいくつか紹介します。
1. TLS終端とリダイレクト
nginx.ingress.kubernetes.io/ssl-redirect: "true"
: HTTPでアクセスがあった場合にHTTPSに自動的にリダイレクトします。spec.tls
セクションでTLSを設定した場合に有用です。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress-tls
namespace: default
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true" # HTTP を HTTPS にリダイレクト
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls-secret # TLS Secret の名前
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80 # バックエンドサービスは HTTP で動作
2. URL書き換え(Rewrite)
nginx.ingress.kubernetes.io/rewrite-target
: 受信したURLパスを書き換えてバックエンドサービスに転送します。正規表現と組み合わせることで柔軟なルーティングが可能です。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rewrite-ingress
namespace: default
annotations:
# /api/v1/.* のリクエストを /v1/ に書き換えて転送
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
# 正規表現を使用する場合、path は ImplementationSpecific にすることが推奨されるが、
# Prefix + rewrite-target の組み合わせも一般的
- path: /api/v1(/|$)(.*) # 正規表現のグループ化を使用
pathType: Prefix # または ImplementationSpecific
backend:
service:
name: api-v1-service
port:
number: 80
この例では、api.example.com/api/v1/users
へのリクエストは、バックエンドサービス api-v1-service
に対して /users
として転送されます。
3. 認証(Authentication)
外部認証サービスとの連携を設定できます。
nginx.ingress.kubernetes.io/auth-url
: 認証を行う外部サービスのURLを指定します。
nginx.ingress.kubernetes.io/auth-signin
: 認証失敗時にリダイレクトするURLを指定します。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auth-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/auth-url: http://auth-service.default.svc.cluster.local/auth
nginx.ingress.kubernetes.io/auth-signin: http://auth.example.com/login
nginx.ingress.kubernetes.io/auth-response-headers: X-Auth-Request-User # 認証サービスからのレスポンスヘッダーをバックエンドに転送
spec:
ingressClassName: nginx
rules:
- host: protected.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: protected-app-service
port:
number: 80
4. レート制限(Rate Limiting)
特定のパスやホストに対するリクエストレートや接続数を制限できます。
nginx.ingress.kubernetes.io/limit-rps
: 秒間あたりのリクエスト数制限。
nginx.ingress.kubernetes.io/limit-connections
: 同時接続数制限。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ratelimit-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/limit-rps: "10" # 1秒間に10リクエストまで
nginx.ingress.kubernetes.io/limit-connections: "50" # 同時接続数50まで
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /limited-api
pathType: Prefix
backend:
service:
name: limited-api-service
port:
number: 80
5. CORS設定
Cross-Origin Resource Sharing (CORS) を有効にできます。
nginx.ingress.kubernetes.io/enable-cors: "true"
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cors-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: my-api-service
port:
number: 80
6. ヘッダー操作
リクエスト/レスポンスヘッダーを追加したり変更したりできます。
nginx.ingress.kubernetes.io/add-headers
: バックエンドに転送する際にリクエストヘッダーを追加。ConfigMapを指定します。
nginx.ingress.kubernetes.io/configuration-snippet
: Nginx設定ファイルに直接Nginxディレクティブを挿入できます(強力ですが、注意して使用する必要があります)。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: header-ingress
namespace: default
annotations:
# X-Forwarded-Proto は通常自動的に追加されるが、他のヘッダーを追加する場合
nginx.ingress.kubernetes.io/add-headers: default/my-custom-headers # ConfigMap の namespace/name
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
この例では、default
Namespaceの my-custom-headers
という名前のConfigMapの内容がヘッダーとして追加されます。ConfigMapのデータはキーがヘッダー名、値がヘッダー値となります。
これらのAnnotationsはNginx Ingress Controllerが提供する機能の一部です。他にも多数のAnnotationsが存在し、Nginxの詳細な動作を制御できます。公式ドキュメントで最新かつ完全なリストを確認することをお勧めします。Annotationを使う際は、対象のIngressリソースにAnnotationを追加/変更し、kubectl apply
で適用するだけで、Ingress Controllerが自動的にNginx設定を更新してくれます。
TLS/SSLの設定
Webアプリケーションのセキュリティと信頼性を確保するためには、HTTPSによる通信が不可欠です。Nginx Ingress Controllerは、IngressレベルでのTLS終端をサポートしており、バックエンドサービスがHTTPSをサポートしていなくても安全な通信を提供できます。
TLS終端を設定するには、以下の2つのステップが必要です。
- TLS証明書と秘密鍵をKubernetes Secretとして保存する。
- Ingressリソースの
spec.tls
セクションでそのSecretを指定する。
1. TLS Secretの作成
TLS証明書(.crt
ファイル)と秘密鍵(.key
ファイル)が必要です。これらのファイルは、認証局(CA)から発行されたものや、自己署名証明書など、どのようなものでも構いません。本番環境では、Let’s Encryptのような無料のCAや商用CAから発行された証明書を使用するのが一般的です。cert-managerのようなツールを使うと、Let’s Encrypt証明書の取得と更新を自動化できます。
手動でSecretを作成する場合、以下のように kubectl create secret tls
コマンドを使用します。
bash
kubectl create secret tls myapp-tls-secret \
--cert /path/to/myapp.crt \
--key /path/to/myapp.key \
--namespace default # Ingressリソースと同じ Namespace に作成するのが一般的
myapp-tls-secret
: 作成するSecretの名前です。--cert /path/to/myapp.crt
: 公開証明書ファイルへのパスを指定します。--key /path/to/myapp.key
: 秘密鍵ファイルへのパスを指定します。--namespace default
: Secretを作成するNamespaceを指定します。
このコマンドにより、指定したNamespaceに myapp-tls-secret
という名前のSecretが作成されます。Secretのデータには tls.crt
と tls.key
というキーで証明書と秘密鍵がBase64エンコードされて保存されます。
Secretが作成されたことを確認します。
bash
kubectl get secret myapp-tls-secret -n default
2. IngressリソースでのSecretの指定
作成したTLS SecretをIngressリソースの spec.tls
セクションで参照します。
“`yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress-tls
namespace: default
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: “true” # オプション: HTTP -> HTTPS リダイレクト
spec:
ingressClassName: nginx
tls:
– hosts:
– myapp.example.com # このホスト名に対する TLS 設定
– anotherapp.example.com # 複数のホスト名を同じ Secret で指定可能 (SAN 証明書の場合)
secretName: myapp-tls-secret # 使用する TLS Secret の名前
rules:
# myapp.example.com に対するルール
– host: myapp.example.com
http:
paths:
– path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80 # 通常、バックエンドサービスは HTTP で十分
# anotherapp.example.com に対するルール (必要に応じて)
– host: anotherapp.example.com
http:
paths:
– path: /
pathType: Prefix
backend:
service:
name: another-app-service
port:
number: 80
“`
このIngressリソースを適用すると、Nginx Ingress Controllerは指定されたSecretから証明書と秘密鍵を読み込み、myapp.example.com
および anotherapp.example.com
へのHTTPSトラフィックに対してTLS終端を行います。バックエンドのサービス (my-app-service
, another-app-service
) には通常、暗号化されていないHTTPトラフィックとして転送されます。
ワイルドカード証明書:
*.example.com
のようなワイルドカード証明書を使用する場合も同様です。Secretにはワイルドカード証明書と秘密鍵を保存し、Ingressリソースの hosts
フィールドに *.example.com
と指定します。
複数のホストに対するTLS設定:
異なるホスト名に対して異なる証明書を使用したい場合は、spec.tls
セクションに複数のエントリを追加し、それぞれの hosts
と secretName
を指定します。
yaml
spec:
tls:
- hosts:
- app1.example.com
secretName: app1-tls-secret
- hosts:
- app2.example.com
secretName: app2-tls-secret
rules:
- host: app1.example.com
http:
paths: ...
- host: app2.example.com
http:
paths: ...
このように設定することで、Nginx Ingress ControllerはServer Name Indication (SNI) を利用して、接続してきたホスト名に応じて適切な証明書をクライアントに提示し、TLS終端を行います。
TLS証明書の有効期限管理は重要です。手動で管理する場合は、証明書が期限切れになる前に新しい証明書でSecretを更新する必要があります。cert-managerのようなツールを導入すると、このプロセスを自動化でき、運用負荷を大幅に軽減できます。
Nginx Ingress Controllerのカスタマイズとチューニング
Nginx Ingress Controllerは、IngressリソースのAnnotations以外にも、Controller自身のグローバルな設定や、Nginxの設定をカスタマイズするための方法を提供しています。
ConfigMapによるグローバル設定:
Ingress Controllerの起動時の引数や、Nginx全体の挙動に影響を与えるグローバル設定は、特定のConfigMapを使用して行うことができます。Helmでインストールした場合、通常 ingress-nginx-controller
(リリース名がデフォルトの場合) という名前のConfigMapが作成されます。このConfigMapのデータセクションにキーと値を追記することで、Nginxの設定ディレクティブを適用できます。
ConfigMapの名前は、Helmのインストール時に controller.configMap
パラメータで指定されます。デフォルトでは <release-name>-controller
です。
以下は、ConfigMapを使ってNginxのProxy設定をカスタマイズする例です。
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller # またはカスタム指定した ConfigMap 名
namespace: ingress-nginx # Controller がデプロイされている Namespace
data:
# proxy-connect-timeout, proxy-send-timeout, proxy-read-timeout を設定
proxy-connect-timeout: "10" # バックエンド接続タイムアウト (秒)
proxy-send-timeout: "15" # バックエンドへの送信タイムアウト (秒)
proxy-read-timeout: "15" # バックエンドからの応答読み取りタイムアウト (秒)
# large-client-header-buffers を設定
large-client-header-buffers: "4 16k" # large_client_header_buffers 4 16k;
このConfigMapを編集し (kubectl edit cm ingress-nginx-controller -n ingress-nginx
) 適用すると、Nginx Ingress ControllerはConfigMapの変更を検知し、Nginxの設定ファイル (nginx.conf
) にこれらの設定を反映させます。ConfigMapで設定可能なパラメータの完全なリストは、Nginx Ingress Controllerの公式ドキュメントを参照してください。
パフォーマンスチューニング:
Nginxのパフォーマンスは、設定によって大きく変わります。Ingress Controllerのパフォーマンスチューニングは、主に以下の点に焦点を当てます。
- Controller Podのリソース制限: Controller Podに十分なCPUとメモリを割り当てることで、Nginx設定の再読み込み処理などをスムーズに行えます。Helmインストール時の
controller.resources
で設定します。 - Controller Podのレプリカ数: アクセス負荷が高い場合や高可用性を確保するために、Controller Podのレプリカ数を増やします。Helmインストール時の
controller.replicaCount
で設定します。 - Nginx Worker Processes: Nginxがリクエストを処理するワーカープロセスの数を調整します。デフォルトではCPUコア数に合わせて自動調整されますが、ConfigMapの
worker-processes
で明示的に指定することも可能です。 - Nginx Connection Limits: 各ワーカープロセスが同時に処理できる接続数を調整します。ConfigMapの
worker-connections
で設定します。
これらの設定は、システムの規模、トラフィックパターン、利用可能なリソースに基づいて適切に調整する必要があります。過度な設定は逆効果になる場合もあるため、監視を通じて効果を確認しながら進めることが重要です。
監視とトラブルシューティング
Ingress Controllerは、Kubernetesクラスターへの外部からのアクセスの玄関口となるため、その安定稼働とパフォーマンスを常に監視することが不可欠です。また、問題発生時に迅速に原因を特定し解決するためのトラブルシューティング能力も重要です。
監視:
Nginx Ingress Controllerは、監視のための様々なメトリクスを提供しています。これらのメトリクスは通常、Prometheusのような監視システムで収集し、Grafanaのようなダッシュボードツールで可視化します。
- Prometheus Exporter: Nginx Ingress Controller Podには、Nginxのメトリクス(リクエスト数、接続数、エラー率、レイテンシなど)をPrometheus形式で公開するExporterが含まれています。通常、
/metrics
パスで公開されます。 - Kubernetes Metrics: Controller Pod自体のCPU、メモリ、ネットワーク使用量などのリソースメトリクスは、Metrics Serverを通じてKubernetes標準の方法で取得できます。
- Ingress Controller固有のメトリクス: Ingress Controllerが処理したIngressリソースの数、設定リロードの成功/失敗回数、Nginxワーカープロセスの状態などのメトリクスも提供されます。
これらのメトリクスを監視することで、以下のような状況を検知できます。
- トラフィック量の変化
- エラー率の上昇(例: 5xxエラー)
- リクエストレイテンシの増加
- Nginxワーカープロセスの問題
- Controller Podのリソース不足
- 設定リロードの失敗
ログ:
Ingress Controller Podからは、Controllerの動作ログとNginxのアクセスログ/エラーログが出力されます。これらのログを確認することは、問題発生時の原因特定に非常に役立ちます。
- Controllerログ: Ingressリソースの変更検知、Nginx設定の生成、リロード処理などの情報が出力されます。設定変更がNginxに反映されない場合などに確認します。
bash
kubectl logs <ingress-controller-pod-name> -n ingress-nginx controller
(Pod名とNamespaceは環境に合わせて置き換えてください) - Nginxアクセスログ: 受信した各HTTP/HTTPSリクエストに関する情報(IPアドレス、タイムスタンプ、メソッド、URL、ステータスコード、レスポンスサイズ、ユーザーエージェントなど)が出力されます。誰がいつどのようなリクエストを送り、どのような結果になったかを確認できます。
bash
kubectl logs <ingress-controller-pod-name> -n ingress-nginx nginx - Nginxエラーログ: Nginxプロセス自身のエラー(設定ファイルのエラー、バックエンドへの接続エラー、TLSハンドシェイクエラーなど)が出力されます。問題発生時にはまずこのログを確認します。
bash
# エラーログは通常、アクセスログと同じストリームに出力されるか、
# Pod内の特定ファイルに出力される場合があります。
# 公式ドキュメントや ConfigMap 設定を確認してください。
デフォルトのHelmインストールでは、Nginxログはstdout/stderrに出力され、kubectl logs
で確認できます。
トラブルシューティング:
問題が発生した場合、以下のステップでトラブルシューティングを行います。
- リソースの状態確認: 問題のIngressリソース、バックエンドService、Deployment、そしてNginx Ingress ControllerのPodとServiceの状態を確認します。
bash
kubectl get ing,svc,deploy,po -n <namespace>
kubectl get all -n ingress-nginx # Controller リソースの確認 - Ingressリソースの詳細確認: 問題のIngressリソースの詳細情報を確認し、
Events
セクションにエラーが記録されていないか確認します。
bash
kubectl describe ingress <ingress-name> -n <namespace>
例えば、TLS Secretが見つからない、Serviceが見つからないなどのエラーが表示されることがあります。 - Controller Podの詳細確認: Ingress Controller Podの詳細情報を確認し、
Events
やStatus
に異常がないか確認します。
bash
kubectl describe pod <ingress-controller-pod-name> -n ingress-nginx - Controllerログの確認: Controller Podのログを見て、Ingressリソースの処理やNginx設定のリロードに関するエラーが出力されていないか確認します。「failed to sync」や設定ファイルのパースエラーなどが出ている場合があります。
- Nginxエラーログの確認: Nginxのエラーログを見て、バックエンドへの接続エラー、TLSエラー、設定ファイルのエロードエラーなどが出力されていないか確認します。
- Nginx設定ファイルの確認: 必要であれば、Controller Podに入り、Nginxが現在使用している設定ファイルを確認します。これにより、IngressリソースやConfigMapの設定が正しくNginx設定に反映されているか確認できます。
bash
kubectl exec -it <ingress-controller-pod-name> -n ingress-nginx -- cat /etc/nginx/nginx.conf - Service Endpointの確認: バックエンドServiceが実際にPodに接続できているか、Endpointリソースを確認します。
bash
kubectl get ep <service-name> -n <namespace>
Endpointリストが空の場合、ServiceのSelectorがPodのLabelにマッチしていないか、PodがRunning状態になっていない可能性があります。 - ネットワーク接続の確認: クライアントからIngress Controller Serviceへのネットワーク経路が正常か確認します。クラウドロードバランサーやNodePortへの接続、ファイアウォール設定などをチェックします。クラスター内部からバックエンドServiceへの接続も確認します(例:
kubectl exec
でPodに入ってcurl <service-name>.<namespace>.svc.cluster.local
)。
よくあるトラブルシューティングシナリオとしては、IngressClassの不一致、TLS Secretが存在しない/内容が間違っている、バックエンドServiceが存在しない/Selectorが間違っている、Service Port/Target Portの設定ミス、Annotationsの記述ミス、DNS設定の誤りなどがあります。
Nginx Ingress Controllerの運用
Nginx Ingress Controllerを安定して運用するためには、日々の監視に加えて、以下の点に注意が必要です。
- バージョンのアップグレード: Ingress Controllerや基盤となるNginxには、セキュリティパッチや新機能の追加、バグ修正が含まれた新しいバージョンが定期的にリリースされます。これらのアップデートを適用することは重要ですが、互換性の問題や設定変更の必要がないか、リリースノートをよく確認してから慎重に行う必要があります。Helmを使っている場合、
helm upgrade
コマンドを使用します。事前にdry-runオプション (--dry-run
) やdiffオプション (--atomic --cleanup-on-fail
) を使って変更内容を確認することが推奨されます。 - 高可用性: 本番環境では、Controller Podを複数レプリカで稼働させることが必須です(Helmインストール時の
controller.replicaCount
)。これにより、Controller Podが停止しても、他のPodがトラフィックを処理し続けられます。また、Ingress Controller Podが分散するように、異なるノードに配置されるようにPod Anti-Affinityを設定することも有効です。 - リソース管理: Controller Podのリソース使用量(CPU、メモリ)を監視し、適切にリソース制限を設定します。リソース不足はパフォーマンス低下や不安定性の原因となります。
- セキュリティ:
- TLS終端を常に利用し、安全な暗号スイートを設定します。
- 不要なAnnotationsは使用せず、ConfigMapによるカスタマイズも最小限に留めます。
- DoS攻撃などに対する対策として、レート制限(AnnotationsやNginx設定)やWAF(Web Application Firewall)との連携を検討します。
- Nginx自体のセキュリティパッチも適用されるため、Controllerのバージョンは最新に近い状態を維持することが望ましいです。
- DNS設定: 外部からのアクセスには正しいDNS設定が不可欠です。LoadBalancer Typeの場合はプロビジョニングされたIPアドレスを、NodePort Typeの場合はNodeのIPアドレスとポートをDNSレコードに登録します。可用性を考慮し、DNSレコードのTTL(Time To Live)を適切に設定することも重要です。
- 外部ロードバランサーとの連携: クラウド環境でLoadBalancer Type Serviceを使用する場合、プロビジョニングされるロードバランサーの設定(セキュリティグループ、SSLポリシー、ヘルスチェックなど)も適切に行う必要があります。これらの設定の一部は、Ingress Controller ServiceのAnnotationsを通じて行うことも可能です。
まとめ
この記事では、Kubernetes Ingress ControllerとしてのNginxについて、その基本的な概念からインストール、設定、高度な機能、監視、トラブルシューティング、運用に至るまで、幅広く詳細に解説しました。
Nginx Ingress Controllerは、Kubernetesクラスター上のサービスを外部に安全かつ効率的に公開するための非常に強力で柔軟なツールです。Ingressリソースによる宣言的な設定、Annotationsによる詳細なカスタマイズ、実績あるNginxの高性能なトラフィック処理能力を兼ね備えています。
Kubernetes環境におけるアプリケーションの外部公開は、Ingress Controllerなしには考えられません。Nginx Ingress Controllerを正しく理解し活用することで、WebアプリケーションやAPIの可用性、パフォーマンス、セキュリティを向上させることができます。
この記事で解説した内容が、皆様がKubernetesとNginx Ingress Controllerを使ったシステムを構築・運用する上での一助となれば幸いです。さらに深く学ぶためには、Nginx Ingress Controllerの公式ドキュメントや、KubernetesのIngressに関するドキュメントを参照することをお勧めします。
最後に、Ingress ControllerはL7ロードバランサーやリバースプロキシとしての役割を果たしますが、API Gatewayとは異なる機能セットを持つことに注意してください。API Gatewayは、APIキー管理、認証、認可、使用量制限、データ変換、ロギング、モニタリングなど、API管理に特化したより高度な機能を提供します。ただし、小規模なシステムやシンプルなユースケースでは、Nginx Ingress Controllerの機能でAPI Gateway的な役割の一部をカバーすることも可能です。
Kubernetesの世界は常に進化しています。新しいバージョンや機能が登場することもあるため、常に最新情報をキャッチアップしていく姿勢が重要です。