はい、承知いたしました。Kubernetes環境でのNginxデプロイと設定に関する約5000語の詳細な入門記事を作成します。
Kubernetes環境でのNginxデプロイ・設定入門
1. はじめに
現代のアプリケーション開発において、コンテナ技術とオーケストレーションツールは不可欠な要素となっています。特に、Googleによって開発され、CNCF(Cloud Native Computing Foundation)がホストするKubernetesは、コンテナ化されたワークロードのデプロイ、スケーリング、管理を自動化するためのデファクトスタンダードとして広く採用されています。
Webサーバーやリバースプロキシとして最も一般的に利用されているソフトウェアの一つにNginxがあります。その高いパフォーマンスと柔軟性から、マイクロサービスアーキテクチャにおけるAPIゲートウェイや静的コンテンツ配信、ロードバランシングなど、様々な用途でKubernetes環境においても中心的な役割を担います。
Kubernetes上でNginxを効果的に利用するためには、Kubernetesの基本的な概念とNginxの設定方法を組み合わせる必要があります。この記事では、KubernetesにおけるNginxのデプロイから基本的な設定、外部への公開方法、さらにはConfigMapやIngressといったKubernetesのリソースを活用したより高度な設定方法まで、詳細かつ実践的な入門ガイドを提供します。
この記事を読むことで、以下のことを学ぶことができます。
- Kubernetesの基本的なコンポーネントとNginxの関連性
- Nginxコンテナイメージの理解と利用
- Deploymentを使ったNginxアプリケーションのデプロイ方法
- Serviceを使ったNginxへのアクセス公開方法
- ConfigMapを使ったNginx設定ファイルの管理方法
- Ingressを使った外部からのアクセスルーティングとSSL設定方法
- Kubernetes環境でのNginxに関する監視、ログ、セキュリティの基本的な考え方
- 遭遇しうる一般的な問題とそのトラブルシューティング方法
この記事は、KubernetesとNginxの基本的な概念は理解しているものの、これらを組み合わせて実際にアプリケーションをデプロイ・設定するのは初めて、という方を対象としています。ぜひ、実際に手を動かしながら読み進めてみてください。
2. Kubernetesの基礎知識(Nginxデプロイに関連するものに絞る)
Kubernetes上でNginxをデプロイ・設定するにあたり、いくつかの基本的なKubernetesオブジェクト(リソース)の理解が必要です。ここでは、Nginxのデプロイと公開に特に関連性の高いオブジェクトについて説明します。
- Pod (ポッド): Kubernetesにおけるデプロイ可能な最小の実行単位です。1つまたは複数の密接に関連するコンテナの集まりとして定義されます。Pod内のコンテナはストレージやネットワーク名前空間を共有します。Nginxをデプロイする場合、通常はNginxコンテナを含むPodを作成します。
- Deployment (デプロイメント): Podの作成と管理を宣言的に行うためのリソースです。Deploymentを使用すると、指定した数のPodを常に実行し続けることができます。また、アプリケーションのバージョンアップやロールバック、スケーリングといった操作を簡単に行えます。Nginxアプリケーションのデプロイの中心となります。
- Service (サービス): 一連のPodに対して、安定したネットワークエンドポイントを提供するリソースです。Podは起動・停止やスケーリングによってIPアドレスが動的に変化しますが、Serviceを利用することで、これらの変動に関わらず、固定されたIPアドレスやDNS名でPodグループにアクセスできるようになります。Nginx Podへのアクセスを公開する際に使用します。
- ConfigMap (コンフィグマップ): 設定データをPodから分離して管理するためのリソースです。Nginxの設定ファイル(
nginx.conf
など)をConfigMapとして定義し、Podにマウントすることで、コンテナイメージを変更せずに設定を更新できるようになります。 - Secret (シークレット): パスワードやAPIキー、TLS証明書といった機密情報を安全に管理するためのリソースです。IngressでTLS/SSLを設定する際に、証明書をSecretとして管理し、Ingressリソースから参照します。
- Ingress (イングレス): クラスタ外部からクラスタ内部のServiceへのHTTP/Sトラフィックを管理するためのAPIオブジェクトです。ホスト名やパスに基づいたルーティング、TLS終端、名前ベースの仮想ホスティングなどを実現します。Nginxをリバースプロキシとして外部に公開する場合、Ingressを使用することが多いです。ただし、Ingressリソースを機能させるためには、別途Ingress Controller(Nginx Ingress Controllerなど)が必要です。
- Namespace (ネームスペース): Kubernetesクラスタ内のリソースを論理的に分割するための仕組みです。異なるチームやアプリケーション、環境(開発、ステージング、本番など)ごとにリソースを分離し、管理やアクセス制御を容易にします。特別な理由がない限り、リソースは特定のNamespace内に作成するのが良いプラクティスです。
これらのオブジェクトは、YAML形式のマニフェストファイルとして定義し、kubectl
コマンドを使ってKubernetesクラスタに適用するのが一般的です。
YAMLマニフェストの基本的な構造は以下のようになります。
yaml
apiVersion: <APIのバージョン>
kind: <リソースの種類>
metadata:
name: <リソースの名前>
namespace: <所属するネームスペース (任意)>
labels:
app: <アプリケーション名> # 識別用のラベル
spec:
# リソース固有の設定
この構造を理解しておくと、今後の各リソースの説明がスムーズに進みます。
3. Nginxコンテナイメージの理解
KubernetesでNginxをデプロイするためには、Nginxが動作するコンテナイメージが必要です。Docker Hubなどのコンテナレジストリには、公式のNginxイメージが提供されています。
3.1. 公式Nginxイメージについて
Docker Hubで提供されている公式のnginx
イメージは、DebianベースとAlpineベースのバージョンがあります。
- Debianベース: フル機能のNginxと標準的なLinuxツールが含まれています。サイズは大きめですが、馴染みのある環境でトラブルシューティングなどがしやすい場合があります。
- Alpineベース: 軽量なAlpine Linuxをベースとしており、イメージサイズが非常に小さいのが特徴です。コンテナイメージのサイズを小さく抑えたい場合に適しています。Kubernetes環境ではリソース消費を抑えるためにAlpine版が好まれることが多いです。
特別な理由がない限り、Kubernetes環境では軽量なAlpineベースのイメージ(例: nginx:1.23-alpine
)から始めるのが良いでしょう。
イメージの指定は、Deploymentマニフェストのコンテナ定義で行います。
yaml
containers:
- name: nginx
image: nginx:1.23-alpine # 使用するイメージを指定
ports:
- containerPort: 80 # コンテナがListenするポート
3.2. カスタマイズされたNginxイメージの作成(Dockerfileの基本)
特定のモジュールを追加したり、デフォルト設定を変更したりする場合、独自のNginxコンテナイメージを作成する必要があります。Dockerfileを使ってイメージをビルドします。
例えば、独自の静的ファイルやNginx設定ファイルを含めたい場合、以下のようなDockerfileを作成できます。
“`dockerfile
ベースイメージとして公式のAlpine版Nginxイメージを使用
FROM nginx:1.23-alpine
メンテナー情報(任意)
LABEL maintainer=”[email protected]”
Nginxの設定ファイルをコンテナ内にコピー
ここでは、ローカルの ./nginx/nginx.conf
をコンテナ内の /etc/nginx/nginx.conf
に上書きコピー
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
追加の設定ファイルを conf.d ディレクトリにコピー
conf.d ディレクトリ内の *.conf ファイルは、nginx.conf から include されるのが一般的
COPY ./nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
静的ファイルをHTMLディレクトリにコピー
例: ローカルの ./html
ディレクトリの内容をコンテナ内の /usr/share/nginx/html
にコピー
COPY ./html /usr/share/nginx/html
NginxがデフォルトでListenするポート80を公開
EXPOSE 80
コンテナ起動時に実行されるコマンド (Nginx公式イメージに設定済みのため通常不要)
CMD [“nginx”, “-g”, “daemon off;”]
“`
Dockerfileのポイント:
FROM
: ベースとなるイメージを指定します。COPY
: ホストマシン上のファイルやディレクトリをコンテナイメージ内にコピーします。Nginxの設定ファイルや提供する静的ファイルをコピーするのに使います。EXPOSE
: コンテナがListenするポートをドキュメント化します(必須ではありませんが推奨されます)。CMD
: コンテナが起動したときに実行されるコマンドを定義します。公式Nginxイメージではnginx -g 'daemon off;'
が設定されており、フォアグラウンドでNginxを実行し、コンテナが終了しないようにしています。
このDockerfileを使ってイメージをビルドするには、Dockerfileがあるディレクトリで以下のコマンドを実行します。
bash
docker build -t your-dockerhub-username/custom-nginx:v1.0 .
ビルドしたイメージをKubernetesから利用するには、Docker Hubなどのコンテナレジストリにプッシュする必要があります。
bash
docker push your-dockerhub-username/custom-nginx:v1.0
KubernetesのDeploymentマニフェストでは、このプッシュしたイメージ名を指定します。
yaml
containers:
- name: nginx
image: your-dockerhub-username/custom-nginx:v1.0
ports:
- containerPort: 80
ただし、設定ファイルを外部から管理したい場合は、ConfigMapを利用する方が一般的です。コンテナイメージはNginxのバイナリと必要なモジュールのみを含み、設定はConfigMapで提供することで、設定変更のたびにイメージをビルドし直す手間を省けます。
4. KubernetesへのNginxデプロイ方法
ここでは、最も基本的なDeploymentリソースを使ったNginxのデプロイ手順を説明します。
4.1. 基本的なDeploymentの作成
Deploymentは、Podの集合を管理し、指定した数のPodが常に稼働している状態を維持します。Nginxをデプロイする場合、Nginxコンテナを含むPodのレプリカ数を指定してDeploymentを作成します。
以下のYAMLは、2つのレプリカを持つ基本的なNginx Deploymentマニフェストの例です。
“`yaml
nginx-deployment.yaml
apiVersion: apps/v1 # DeploymentリソースのAPIバージョン
kind: Deployment # リソースの種類はDeployment
metadata:
name: nginx-deployment # Deploymentの名前
labels: # このDeploymentにラベルを付ける
app: nginx
spec:
replicas: 2 # 実行するPodの数を2つに指定
selector: # このDeploymentが管理するPodを選択するためのラベルセレクタ
matchLabels:
app: nginx # ラベルが app: nginx のPodを管理対象とする
template: # 管理対象となるPodのテンプレート
metadata:
labels: # このPodにラベルを付ける (selectorのmatchLabelsと一致させる必要がある)
app: nginx
spec:
containers: # Pod内で実行するコンテナのリスト
– name: nginx # コンテナの名前
image: nginx:1.23-alpine # 使用するコンテナイメージ
ports:
– containerPort: 80 # コンテナがリッスンするポート
name: http # ポートに名前を付ける (任意だが推奨)
“`
マニフェストの解説:
apiVersion
,kind
: リソースの種類とAPIバージョンを指定します。Deploymentの場合、通常apps/v1
を使用します。metadata.name
: このDeploymentリソースの名前を定義します。Kubernetesクラスタ内で一意である必要があります(同じNamespace内)。metadata.labels
: このDeploymentリソース自体にラベルを付けます。リソースの識別に役立ちます。spec.replicas
: このDeploymentで管理されるPodのdesired state(希望する状態)としてのレプリカ数を指定します。ここでは2つなので、常に2つのNginx Podが稼働するようにKubernetesが管理します。spec.selector
: このDeploymentがどのPodを管理するかのセレクタを定義します。matchLabels
で指定したラベルに一致するPodが管理対象となります。ここではapp: nginx
ラベルを持つPodです。このセレクタはtemplate.metadata.labels
と一致している必要があります。一度設定したセレクタは基本的に変更できません。spec.template
: このDeploymentによって作成されるPodのテンプレートを定義します。spec.template.metadata.labels
: このテンプレートから作成されるPodに付けられるラベルです。spec.selector.matchLabels
と一致させることで、DeploymentがそれらのPodを管理できるようになります。spec.template.spec
: Podの仕様を定義します。containers
: Pod内で実行するコンテナのリストです。name
: コンテナの名前。Pod内で一意である必要があります。image
: 使用するコンテナイメージの名前とタグ。Docker Hubなどから取得されます。ports
: コンテナがリッスンするポートのリスト。containerPort
: コンテナがリッスンするポート番号。
4.2. kubectl apply
コマンドによるデプロイ
作成したYAMLファイルをnginx-deployment.yaml
という名前で保存し、以下のコマンドを実行してKubernetesクラスタにデプロイします。
bash
kubectl apply -f nginx-deployment.yaml
apply
コマンドは、ファイルで定義されたリソースが存在しない場合は新しく作成し、既に存在する場合は差分を適用して更新します。
コマンドの出力例:
deployment.apps/nginx-deployment created
これでDeploymentリソースが作成されました。Kubernetesのコントローラーは、このDeploymentの定義に基づいて、指定されたレプリカ数のPodを作成します。
4.3. Deploymentの状態確認
デプロイが成功したか、Podが期待通りに起動しているかを確認します。
Deploymentリソースの状態を確認します。
bash
kubectl get deployment nginx-deployment
出力例:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 <some_time>
READY
: 現在利用可能な(トラフィックを受け付けられる)Podの数 / 望ましいPodの数。ここでは2/2
なので、2つ全てのPodがReady状態です。UP-TO-DATE
: 望ましい状態(Deploymentの仕様)に更新されているPodの数。AVAILABLE
: ユーザーに提供可能なPodの数。
Podの状態を確認します。nginx-deployment
が管理するPodは、そのPodテンプレートに定義されたラベル(app: nginx
)を持っています。
bash
kubectl get pods -l app=nginx
-l app=nginx
は、ラベルがapp=nginx
であるPodのみをフィルタリングして表示するオプションです。
出力例:
NAME READY STATUS RESTARTS AGE
nginx-deployment-abcdefgh-12345 1/1 Running 0 <some_time>
nginx-deployment-abcdefgh-67890 1/1 Running 0 <some_time>
STATUS
がRunning
になっていれば、Podは正常に起動しています。READY
が1/1
であれば、Pod内のコンテナが正常に動作し、Ready状態であることを示します。
もしPodがPending
やCrashLoopBackOff
などの状態になっている場合は、以下のコマンドで詳細情報を確認し、原因を調査します。
bash
kubectl describe pod <pod_name>
kubectl logs <pod_name>
<pod_name>
は、kubectl get pods
で表示されたPodの名前を指定します。describe
コマンドはPodのイベントログや状態、リソース制限などを詳しく表示し、logs
コマンドはPod内のコンテナの標準出力/標準エラー出力を表示します。
これで、Kubernetesクラスタ内に2つのNginx Podがデプロイされ、稼働している状態になりました。しかし、このままではクラスタの外部からこれらのPodにアクセスすることはできません。
5. Nginxサービスへのアクセス公開
デプロイされたNginx Podにアクセスできるようにするためには、Serviceリソースを作成する必要があります。Serviceは、PodのIPアドレスやポートの変動を抽象化し、安定したアクセス方法を提供します。
5.1. Serviceオブジェクトの役割と種類
Serviceの主な役割は以下の通りです。
- Pod間の負荷分散: Serviceの背後にあるPodグループに送られたトラフィックを自動的に分散します。
- 安定したネットワークエンドポイント: PodのIPアドレスが変化しても、ServiceのIPアドレスやDNS名は一定に保たれます。
- クラスタ内部からのアクセス: 他のPodからNginx PodにService経由でアクセスできます。
- クラスタ外部からのアクセス: Serviceの種類によっては、外部からNginx Podにアクセスできるように設定できます。
Serviceにはいくつかの種類があります。
- ClusterIP (デフォルト): クラスタ内部からのみアクセス可能な仮想IPアドレスをServiceに割り当てます。クラスタ内の他のPodからNginxにアクセスする場合に使用します。
- NodePort: クラスタ内の各ノードの特定のポート(NodePort)を開放し、そのポートへのトラフィックをServiceにルーティングします。クラスタ外部からアクセス可能になりますが、主に開発やテスト用途で使用されます。公開ポートが広範囲(デフォルト30000-32767)からランダムに割り当てられるため、プロダクション環境にはあまり適しません。
- LoadBalancer: クラウドプロバイダー(AWS, GCP, Azureなど)のロードバランサーをプロビジョニングし、そのロードバランサーを通じてServiceに外部からアクセスできるようにします。最も一般的なプロダクション環境での外部公開方法です。クラウド環境以外(オンプレミスなど)では、LoadBalancerタイプのServiceを利用するためにはMetalLBのような外部ロードバランサー実装が必要です。
- ExternalName: Serviceをクラスタ外部のDNS名にマッピングします。リダイレクト機能であり、プロキシ機能はありません。Nginxへのアクセスには通常使用しません。
ここでは、まずClusterIP Serviceを作成してクラスタ内部からのアクセスを確認し、次にNodePort Serviceを作成して簡単な外部からのアクセスを試み、最後にLoadBalancer Serviceについて説明します。
5.2. ClusterIP Serviceの作成
最もシンプルなServiceタイプです。Nginx Podがデプロイされていることを前提とします。
“`yaml
nginx-service-clusterip.yaml
apiVersion: v1 # ServiceリソースのAPIバージョン
kind: Service # リソースの種類はService
metadata:
name: nginx-service # Serviceの名前
spec:
selector: # このServiceがどのPodグループにトラフィックをルーティングするかを選択
app: nginx # ラベルが app: nginx のPodを選択
ports: # このServiceが提供するポートのリスト
– protocol: TCP # プロトコル (TCPまたはUDP)
port: 80 # Serviceのポート (クラスタ内部からのアクセスに使用されるポート)
targetPort: 80 # Serviceがトラフィックを送信するPodのポート (Podテンプレートで定義したcontainerPort)
type: ClusterIP # Serviceの種類
“`
マニフェストの解説:
apiVersion
,kind
: リソースの種類とAPIバージョンを指定します。Serviceの場合、通常v1
を使用します。metadata.name
: Serviceの名前。spec.selector
: このServiceのトラフィックをどのPodに送るかを決定するためのラベルセレクタ。Deploymentで定義したPodのラベル(app: nginx
)と一致させることで、そのDeploymentが管理するPodがServiceのバックエンドになります。spec.ports
: Serviceがリッスンするポートと、それをどのPodポートにマッピングするかを定義します。protocol
: ポートのプロトコル。HTTPトラフィックは通常TCPです。port
: Service自身のポート。クラスタ内の他のPodがこのServiceにアクセスする際に使用するポート番号です。targetPort
: Serviceがトラフィックを転送するPod内のポート番号。DeploymentのPodテンプレートで定義したcontainerPort
(ここでは80)と一致させるのが一般的です。名前付きポート(例:targetPort: http
)を指定することも可能で、推奨されます(PodテンプレートのcontainerPort
定義でname: http
としている場合)。
spec.type
: Serviceの種類。ここではClusterIP
を指定しています。
このYAMLファイルをnginx-service-clusterip.yaml
として保存し、デプロイします。
bash
kubectl apply -f nginx-service-clusterip.yaml
Serviceが作成されたことを確認します。
bash
kubectl get service nginx-service
出力例:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP 10.96.x.y <none> 80/TCP <some_time>
CLUSTER-IP
に割り当てられたIPアドレス(例: 10.96.x.y
)が、このServiceの仮想IPアドレスです。このIPアドレスはクラスタ内部からのみアクセス可能です。
クラスタ内部からこのServiceにアクセスできるか確認するには、BusyBoxなどのユーティリティPodをクラスタ内に一時的に作成し、そこからcurl
コマンドを実行するのが一般的です。
“`bash
一時的なBusyBox Podを作成し、その中でシェルを実行
kubectl run -it –rm –restart=Never busybox –image=busybox sh
BusyBox Podのシェルに入ったら、以下のコマンドを実行
Service名を使ってアクセスできる (Kubernetesは内部DNSを提供する)
wget -O- http://nginx-service
または、ServiceのCLUSTER-IPを使ってアクセス
wget -O- http://10.96.x.y # 上記 kubectl get service で確認したIPに置き換え
成功すれば、NginxのデフォルトウェルカムページHTMLが表示されるはずです
シェルを終了するには ‘exit’ と入力
“`
これで、クラスタ内部からNginx Service経由でNginx Podにアクセスできることが確認できました。
5.3. NodePort Serviceの作成
NodePort Serviceを使用すると、クラスタ外部からノードのIPアドレスと特定のポート番号を使ってServiceにアクセスできます。開発やテスト環境での簡単な外部公開に適しています。
ClusterIP Serviceのマニフェストを少し変更して、type: NodePort
にします。
“`yaml
nginx-service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service-nodeport # 別名にするか、前のServiceを削除する
spec:
selector:
app: nginx
ports:
– protocol: TCP
port: 80 # Serviceのポート (クラスタ内部からのアクセスポート、ClusterIPと同じ)
targetPort: 80 # Podのポート
nodePort: 30080 # 各ノードで開放されるポート (30000-32767の範囲、任意、指定しない場合は自動割当)
type: NodePort # Serviceの種類
“`
nodePort
を指定しない場合、Kubernetesは30000-32767の範囲でランダムにポートを割り当てます。特定のポートを指定する場合は、その範囲内で未使用のポートを選びます。
前のClusterIP Serviceが不要であれば削除してから適用します。
bash
kubectl delete service nginx-service # 前のServiceを削除する場合
kubectl apply -f nginx-service-nodeport.yaml
Serviceが作成されたことを確認します。
bash
kubectl get service nginx-service-nodeport
出力例:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service-nodeport NodePort 10.96.x.y <none> 80:30080/TCP <some_time>
PORT(S)
の列に80:30080/TCP
と表示されています。これは、ServiceのClusterIPのポート80へのトラフィックが、各ノードのポート30080にルーティングされることを意味します。
クラスタ外部からアクセスするには、クラスタ内のいずれかのノードのIPアドレスと割り当てられたNodePort(ここでは30080)を使用します。
例: http://<node_ip_address>:30080
<node_ip_address>
は、kubectl get nodes -o wide
などで確認できる、クラスタ内のノードの外部IPアドレスです。
これにより、簡単な外部からのアクセスが可能になります。ただし、NodePortは通常、プロダクション環境での利用には推奨されません。ポート範囲が限定されること、ノードIPに依存すること、ロードバランシング機能が限定的であることなどが理由です。
5.4. LoadBalancer Serviceの作成
LoadBalancer Serviceは、対応するクラウド環境(GCP, AWS, Azureなど)で使用すると、クラウドプロバイダーのロードバランサーサービスを自動的にプロビジョニングし、Nginx Serviceにトラフィックを転送するように構成します。これにより、外部から安定したIPアドレス(ロードバランサーのIPアドレス)を通じてNginx Serviceにアクセスできるようになります。
NodePort Serviceのマニフェストをさらに変更して、type: LoadBalancer
にします。
“`yaml
nginx-service-loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service-loadbalancer # 別名にするか、前のServiceを削除する
spec:
selector:
app: nginx
ports:
– protocol: TCP
port: 80 # Serviceのポート (外部からのアクセスポート)
targetPort: 80 # Podのポート
type: LoadBalancer # Serviceの種類
“`
このServiceを適用します。
bash
kubectl delete service nginx-service-nodeport # 前のServiceを削除する場合
kubectl apply -f nginx-service-loadbalancer.yaml
Serviceが作成されたことを確認します。クラウド環境によっては、ロードバランサーのプロビジョニングに数分かかる場合があります。
bash
kubectl get service nginx-service-loadbalancer
出力例(ロードバランサーがプロビジョニングされた後):
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service-loadbalancer LoadBalancer 10.96.x.y <pending>|<EXTERNAL_IP> 80:3xxxx/TCP <some_time>
EXTERNAL-IP
の列に、クラウドプロバイダーによって割り当てられた外部IPアドレスが表示されるまで待ちます(最初は<pending>
と表示されることがあります)。IPアドレスが表示されたら、そのIPアドレスを使ってクラスタ外部からNginxにアクセスできます。
例: http://<EXTERNAL_IP>
LoadBalancer Serviceはプロダクション環境での外部公開に適していますが、クラウドプロバイダーの料金が発生すること、HTTP/S以外のプロトコルには対応しない場合があること、より複雑なルーティングやTLS管理にはIngressの方が柔軟であることなどを考慮する必要があります。
6. ConfigMapを使ったNginx設定の管理
コンテナイメージに設定ファイルを含める方法はシンプルですが、設定変更のたびにイメージを再ビルドし、デプロイし直す必要があります。これは運用上非効率です。ConfigMapを使うと、設定データをPodから分離して管理し、設定変更をより簡単に行うことができます。
6.1. ConfigMapの役割
ConfigMapは、キー-バリューペアの形式で非機密性の設定データを格納するためのKubernetesリソースです。ファイル、ディレクトリ、あるいは単一の値としてPodに提供できます。Nginxの設定ファイルをConfigMapとして管理し、それをPodにボリュームとしてマウントすることで、設定ファイルを外部から注入できます。
6.2. Nginx設定ファイルの構造
標準的なNginxの構成では、nginx.conf
がメインの設定ファイルであり、conf.d
ディレクトリ内の.conf
ファイルをinclude
ディレクティブで読み込むのが一般的です。
“`nginx
/etc/nginx/nginx.conf (例)
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf; # <--- ここで conf.d ディレクトリ内の設定ファイルを読み込む
}
“`
conf.d
ディレクトリ内にアプリケーション固有の設定ファイル(例: default.conf
)を配置することで、メインのnginx.conf
を標準のままに保ちつつ、サービスごとに設定を分離できます。
6.3. 簡単なNginx設定ファイルの作成例
ここでは、簡単な静的ファイルを返すNginxの設定をconf.d/default.conf
として作成し、ConfigMapで管理する例を考えます。
“`nginx
default.conf
server {
listen 80;
server_name _; # Any hostname
location / {
root /usr/share/nginx/html; # 静的ファイルのルートディレクトリ
index index.html; # デフォルトのインデックスファイル
}
# ヘルスチェック用のエンドポイント例
location /healthz {
return 200 'ok';
add_header Content-Type text/plain;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
“`
6.4. ConfigMap YAMLマニフェストの作成例
作成したdefault.conf
ファイルをConfigMapとして定義します。
“`yaml
nginx-configmap.yaml
apiVersion: v1
kind: ConfigMap # リソースの種類はConfigMap
metadata:
name: nginx-config # ConfigMapの名前
data: # 設定データをキー-バリュー形式で定義
# ファイル名がキー、ファイルの内容がバリューとなることが多い
default.conf: | # default.conf というキーで設定ファイルの内容を定義
server {
listen 80;
server_name _; # Any hostname
location / {
root /usr/share/nginx/html;
index index.html;
}
location /healthz {
return 200 'ok';
add_header Content-Type text/plain;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
“`
ConfigMapをデプロイします。
bash
kubectl apply -f nginx-configmap.yaml
ConfigMapが作成されたことを確認します。
bash
kubectl get configmap nginx-config
出力例:
NAME DATA AGE
nginx-config 1 <some_time>
内容を確認するには以下のようにします。
“`bash
kubectl describe configmap nginx-config
または
kubectl get configmap nginx-config -o yaml
“`
6.5. ConfigMapをPodにマウントする方法
作成したConfigMapをNginx Podから参照できるようにするには、DeploymentマニフェストのPodテンプレートにvolumes
とvolumeMounts
を追加します。
volumes
: Podレベルで定義され、どのConfigMap(またはSecretなど)を使用するか、どのような種類のボリュームとして定義するかを指定します。volumeMounts
: コンテナレベルで定義され、volumes
で定義したボリュームをコンテナ内のどのパスにマウントするかを指定します。
Nginx Podは通常、/etc/nginx/conf.d/
ディレクトリに設定ファイルを置くので、ConfigMapのデータをこのディレクトリにマウントします。
“`yaml
nginx-deployment-with-configmap.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-configmap
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
– name: nginx
image: nginx:1.23-alpine
ports:
– containerPort: 80
name: http
volumeMounts: # <— volumeMounts を追加
– name: nginx-config-volume # 後述の volumes で定義したボリューム名と一致させる
mountPath: /etc/nginx/conf.d # ConfigMapのデータをマウントするコンテナ内のパス
readOnly: true # 読み取り専用でマウント (推奨)
volumes: # <— volumes を追加
– name: nginx-config-volume # ボリュームの名前
configMap: # ConfigMap をボリュームソースとして指定
name: nginx-config # マウントする ConfigMap の名前 (上記で作成した ConfigMap名)
# items: # ConfigMap の特定のキーだけをファイルとしてマウントする場合に指定
# – key: default.conf
# path: default.conf # マウント先のファイル名
“`
マニフェストの解説:
spec.template.spec.volumes
:nginx-config-volume
という名前のボリュームを定義しています。このボリュームのソースはconfigMap
であり、参照するConfigMapの名前はnginx-config
です。items
を指定しない場合、ConfigMapの各キーがボリューム内にファイルとして作成され、キー名がファイル名になります(例:default.conf
というキーは/etc/nginx/conf.d/default.conf
というファイルになる)。spec.template.spec.containers.volumeMounts
: コンテナ内で、定義したnginx-config-volume
を/etc/nginx/conf.d
パスにマウントしています。readOnly: true
は、Podから設定ファイルを誤って変更できないようにするための良いプラクティスです。
6.6. 設定変更とPodのローリングアップデート
このDeploymentを適用すると、新しい設定ファイルを含むPodが作成されます。
“`bash
前のDeploymentを削除するか、別の名前にする
kubectl delete deployment nginx-deployment
kubectl apply -f nginx-deployment-with-configmap.yaml
“`
Deploymentが更新され、新しいPodが順次起動し、古いPodが停止する「ローリングアップデート」が行われます。kubectl get deployment nginx-deployment-configmap
で状態を確認できます。
ConfigMapの内容を変更した場合、その変更は既存のPodには自動的には反映されません。Podは起動時にConfigMapの内容を読み込むため、設定を更新するにはPodを再起動する必要があります。Deploymentを使用している場合、以下のいずれかの方法でローリングアップデートをトリガーできます。
-
Podテンプレートの変更: DeploymentマニフェストのPodテンプレート(例: ラベルやアノテーション)に小さな変更を加えて
kubectl apply
します。これにより、DeploymentコントローラーがPodテンプレートのハッシュ値の変化を検知し、新しいPodを作成します。最も一般的な方法は、Podテンプレートにアノテーションを追加/更新することです。“`yaml
nginx-deployment-with-configmap.yaml に追記
…
spec:
# …
template:
metadata:
labels:
app: nginx
annotations: # <– アノテーションを追加
kubectl.kubernetes.io/restartedAt: “{{ now }}” # <– これを追加/更新
spec:…
“`
このアノテーションの値は任意ですが、
kubectl.kubernetes.io/restartedAt
に現在時刻を設定する手法がよく使われます。ConfigMapを更新した後、この値を新しい時刻に更新してkubectl apply
することで、Deploymentがローリングアップデートを開始します。 -
kubectl rollout restart
コマンド: Deploymentを直接再起動するコマンドです。これは内部的には、Podテンプレートのアノテーションにランダムな値をセットしてkubectl apply
するのと似た動作をします。bash
kubectl rollout restart deployment nginx-deployment-configmapこのコマンドは、ConfigMapの変更後にDeploymentに適用すると、新しい設定を読み込んだPodにローリングアップデートを実行します。
ConfigMapを使った設定管理は、設定変更を容易にし、コンテナイメージの再ビルドを不要にするため、Kubernetes環境でのNginx運用において推奨される方法です。
7. Ingressを使ったNginx設定の応用
Service(特にNodePortやLoadBalancer)は外部へのアクセスを提供しますが、より高度なトラフィックルーティングやSSL終端、仮想ホスティングなどを実現するには機能が不足しています。そこで登場するのがIngressです。
7.1. Ingressの役割
Ingressは、クラスタ外部からクラスタ内部のServiceへのHTTP/Sトラフィックのルールを定義するAPIオブジェクトです。主な機能は以下の通りです。
- 外部からのアクセス: 外部からのトラフィックをKubernetesクラスタ内のServiceにルーティングします。
- 負荷分散: Serviceの背後にあるPodへのトラフィックを分散します(これはServiceの機能でもありますが、Ingress Controllerがロードバランシングの設定を構成します)。
- ホスト名ベースのルーティング: 異なるホスト名(ドメイン名)に基づいてトラフィックを異なるServiceにルーティングします(例:
app1.example.com
はService Aへ、app2.example.com
はService Bへ)。 - パスベースのルーティング: 同じホスト名でも、異なるURLパスに基づいてトラフィックを異なるServiceにルーティングします(例:
example.com/api
はService APIへ、example.com/static
はService Staticへ)。 - TLS/SSL終端: Ingress ControllerでTLS/SSL証明書を管理し、HTTPSトラフィックを終端させることができます。これにより、バックエンドのPodはHTTPで通信でき、証明書管理の手間をIngress層に集約できます。
- 名前ベースの仮想ホスティング: 複数のドメインに対して単一のIPアドレスでサービスを提供できます。
7.2. Ingress Controllerの必要性
Ingressリソース自体はトラフィックルーティングの「ルール」を定義するだけであり、実際にそのルールを監視し、外部トラフィックを受けてルーティング処理を行う「コントローラー」が必要です。これが Ingress Controller です。
様々なIngress Controllerがありますが、最も一般的で広く使われているのが Nginx Ingress Controller です。これは、Kubernetes Ingressリソースのルールを読み取り、それに基づいて実際のNginxインスタンスを設定・再ロードすることでトラフィックを制御します。
Nginx Ingress Controllerのデプロイ:
Nginx Ingress Controllerは、通常DeploymentとしてKubernetesクラスタ内にデプロイされます。公式のNginx Ingress Controllerのデプロイ方法は複雑な場合があるため、ここでは詳細な手順は割愛しますが、公式ドキュメントを参照してインストールしてください。
多くのクラウドプロバイダー(GKE, EKS, AKSなど)は、Kubernetesクラスタ作成時にIngress Controller(多くはNginxベースまたは独自のロードバランサーベース)を簡単に有効化するオプションを提供しています。また、Helmパッケージマネージャーを使ってインストールすることも一般的です。
重要: Ingressリソースを作成する前に、必ずクラスタ内にIngress Controllerが正しくインストール・稼働していることを確認してください。
7.3. Ingress YAMLマニフェストの作成例
クラスタにNginx Ingress Controllerが稼働している前提で、Ingressリソースを作成します。
ここでは、example.com
というホスト名でアクセスされたトラフィックを、先ほど作成したnginx-service-loadbalancer
(またはnginx-service-nodeport
、またはClusterIPでもIngress Controller経由でアクセス可能)にルーティングするIngressマニフェストの例を示します。
“`yaml
nginx-ingress.yaml
apiVersion: networking.k8s.io/v1 # IngressリソースのAPIバージョン
kind: Ingress # リソースの種類はIngress
metadata:
name: nginx-example-ingress # Ingressの名前
annotations: # Ingress Controller固有の設定を指定するアノテーション (任意)
# Nginx Ingress Controller の場合によく使われるアノテーション例
nginx.ingress.kubernetes.io/rewrite-target: / # パスの書き換えルール
# nginx.ingress.kubernetes.io/ssl-redirect: “true” # HTTPをHTTPSにリダイレクト
spec:
# ingressClassName: nginx # 使用するIngressClassを指定 (Kubernetes 1.18+)
rules: # ルーティングルールのリスト
– host: example.com # ホスト名ベースのルーティング
http:
paths: # パスベースのルーティングルールのリスト
– path: / # マッチさせるURLパス (ここではルートパス)
pathType: Prefix # パスのマッチ方法 (Prefix, Exact, ImplementationSpecific)
backend: # トラフィックを転送するバックエンド Service
service:
name: nginx-service-loadbalancer # 転送先のService名 (ClusterIPでも良い)
port:
number: 80 # 転送先のServiceのポート番号
# TLS/SSL 設定 (後述)
# tls:
# – hosts:
# – example.com
# secretName: example-com-tls-secret # TLS証明書を含む Secret の名前
“`
マニフェストの解説:
apiVersion
,kind
: IngressリソースのAPIバージョンと種類を指定します。HTTPルーティングの場合、通常networking.k8s.io/v1
を使用します。metadata.name
: Ingressリソースの名前。metadata.annotations
: Ingress Controller固有の設定を記述するためのアノテーション。例えば、Nginx Ingress Controllerではパスの書き換え(nginx.ingress.kubernetes.io/rewrite-target
)やリダイレクトなどの設定をアノテーションで制御できます。利用するIngress Controllerのドキュメントを参照してください。spec.ingressClassName
: Kubernetes 1.18以降では、IngressClass
リソースを使ってIngress Controllerを識別し、どのIngressリソースをどのControllerが処理するかを明確に指定できます。nginx
などが一般的です。IngressClass
については別途ドキュメントを参照してください。spec.rules
: ホスト名やパスに基づいたルーティングルールのリスト。host
: このルールが適用されるホスト名を指定します。省略した場合、全てのホスト名にマッチします(デフォルトバックエンドとして使用)。http.paths
: このホスト名に対するパスベースのルーティングルールのリスト。path
: マッチさせるURLパス。正規表現はサポートされていませんが、pathType
でマッチング方法を指定します。pathType
: パスのマッチング方法。Prefix
(指定したパスで始まる全てのパスにマッチ)、Exact
(指定したパスと完全に一致する場合のみマッチ)、ImplementationSpecific
(Ingress Controllerの実装に依存)があります。backend
: マッチしたトラフィックの転送先となるServiceを指定します。service.name
: 転送先のServiceの名前。service.port.number
またはservice.port.name
: 転送先のServiceのポート番号または名前。
このIngressマニフェストを適用します。
bash
kubectl apply -f nginx-ingress.yaml
Ingressリソースが作成されたことを確認します。
bash
kubectl get ingress nginx-example-ingress
出力例:
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-example-ingress nginx example.com <EXTERNAL_IP> 80 <some_time>
ADDRESS
の列に、Ingress Controllerによって割り当てられた外部IPアドレスが表示されます(多くの場合、Ingress ControllerのService Type LoadBalancerのIPアドレスがここに表示されます)。
このIngressを通じてNginxにアクセスするには、以下の設定が必要です。
example.com
というホスト名が、IngressのADDRESS
に表示されている外部IPアドレスを指すようにDNSレコード(Aレコードなど)を設定します。- 設定したホスト名(
example.com
)を使ってブラウザやcurl
でアクセスします。
bash
curl http://example.com
(DNS設定が反映されていない場合や、一時的にテストしたい場合は、/etc/hosts
ファイルを編集してexample.com
をIngressのIPアドレスにマッピングすることもできます。)
Ingressを使用することで、複数のアプリケーション(Service)を単一のIPアドレスとロードバランサーで公開し、ホスト名やパスに基づいてトラフィックを適切にルーティングできるようになります。
7.4. TLS/SSL証明書の設定
IngressはTLS/SSL終端をサポートしています。これにより、外部からのHTTPSトラフィックをIngress Controllerで復号化し、バックエンドのPodへはHTTPで転送できます。SSL証明書はKubernetesのSecretリソースとして管理し、Ingressリソースから参照します。
TLS証明書(秘密鍵と証明書)を含むSecretを作成します。PEM形式のファイルが必要です。
“`bash
必要に応じて、以下のようなコマンドでダミーの証明書を作成できます (本番環境では使用しないでください)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj “/CN=example.com/O=MyCompany”
Secretを作成
kubectl create secret tls example-com-tls-secret –cert=tls.crt –key=tls.key
“`
作成したSecretをIngressマニフェストのspec.tls
セクションで参照します。
“`yaml
nginx-ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-example-ingress-tls
annotations:
# Nginx Ingress Controller のアノテーション例
nginx.ingress.kubernetes.io/ssl-redirect: “true” # HTTPをHTTPSにリダイレクト
spec:
rules:
– host: example.com
http:
paths:
– path: /
pathType: Prefix
backend:
service:
name: nginx-service-loadbalancer
port:
number: 80
tls: # <— TLS 設定を追加
– hosts: # 証明書を適用するホスト名のリスト
– example.com
secretName: example-com-tls-secret # 作成した Secret の名前
“`
このIngressマニフェストを適用します。
bash
kubectl apply -f nginx-ingress-tls.yaml
Ingress Controllerは、指定されたSecretから証明書を読み込み、Ingressのホスト名に対してHTTPSを有効にします。nginx.ingress.kubernetes.io/ssl-redirect: "true"
アノテーションがあれば、HTTPでアクセスされた場合でも自動的にHTTPSにリダイレクトされます。
これで、https://example.com
でNginxにアクセスできるようになります。本番環境では、Cert-Managerなどのツールを使ってLet’s Encryptのような認証局から自動的に証明書を取得・更新するのが一般的です。
8. 高度なNginx設定と考慮事項
ConfigMapやIngressを通じて、より複雑なNginx設定をKubernetes環境に適用できます。以下に、いくつかの高度な設定例と考慮事項を挙げます。
8.1. 静的ファイルのキャッシュ設定
静的ファイル(CSS, JS, 画像など)はキャッシュすることでパフォーマンスを向上できます。ConfigMapで管理するNginx設定にキャッシュ関連の設定を追加します。
“`nginx
default.conf (一部抜粋 – /static/ パス以下をキャッシュする例)
server {
listen 80;
server_name _;
location / {
root /usr/share/nginx/html;
index index.html;
# 他の設定...
}
# 静的ファイル用のキャッシュ設定
location /static/ {
alias /usr/share/nginx/html/static/; # /static/ 以下のリクエストを /usr/share/nginx/html/static/ から提供
expires 30d; # クライアント側で30日間キャッシュ
access_log off; # 静的ファイルへのアクセスログは記録しない (オプション)
add_header Cache-Control "public, max-age=2592000"; # Cache-Control ヘッダーを追加 (30d = 2592000秒)
# 他の設定...
}
# ... 他の location ブロック
}
“`
この設定をConfigMapに反映させ、Deploymentを再起動(rollout restart)することで適用されます。
8.2. リバースプロキシとロードバランシング(upstreamディレクティブ)
Nginxをリバースプロキシとして使用し、複数のバックエンドサービスにトラフィックを転送する場合、upstream
ディレクティブとproxy_pass
を使用します。Kubernetes環境では、proxy_pass
の転送先として他のServiceを指定することが多いです。
“`nginx
conf.d/proxy.conf (例 – api-service という名前の Service に転送)
upstream backend_api {
# Kubernetes Service 名を指定すると、Service の背後にある Endpoints (Pod IP) に自動的に解決され、負荷分散される
# Service に名前付きポートがある場合はポート名も指定可能 (例: api-service:http)
server api-service:8080; # バックエンドとなる Kubernetes Service の名前とポート
# その他、upstream 設定 (例: weight, fail_timeout, max_fails など)
# server 10.0.0.1:8080; # 直接 Pod IP を指定することも可能だが、Service を推奨
# server api-service.default.svc.cluster.local:8080; # FQDN で指定することも可能
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend_api; # upstream で定義したバックエンドに転送
proxy_set_header Host $host; # オリジナルの Host ヘッダーを渡す
proxy_set_header X-Real-IP $remote_addr; # クライアントの実際のIPを渡す
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# その他、プロキシ関連の設定...
}
}
“`
この設定をConfigMapとして追加し、Deploymentでマウントすることで、Nginx Podが他のServiceへのリバースプロキシとして機能します。proxy_pass
でService名を指定した場合、Nginx(またはDNS resolverの設定に依存)はKubernetesの内部DNSを使ってService IPを解決し、ServiceはトラフィックをバックエンドPodに負荷分散します。
注意: Nginxコンテナ内でService名を解決して外部のServiceにアクセスする場合、NginxがPodのDNS設定(通常はクラスタのcoredns)を使用できる必要があります。
8.3. Gzip圧縮設定
応答データを圧縮することで、転送量を減らし、ページのロード時間を短縮できます。
“`nginx
nginx.conf または conf.d/*.conf に追加
http {
# … 他の設定 …
gzip on; # Gzip圧縮を有効化
gzip_vary on; # Vary: Accept-Encoding ヘッダーを追加
gzip_proxied any; # プロキシされたリクエストでも圧縮
gzip_comp_level 6; # 圧縮レベル (1-9, 6が一般的)
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # 圧縮するMIMEタイプ
gzip_min_length 1000; # 圧縮を適用する最小応答サイズ (バイト)
# gzip_disable “MSIE [1-6].”; # 特定のブラウザでは無効化
# …
}
“`
8.4. HTTP/2設定
HTTP/2は、HTTP/1.xに比べてパフォーマンスが向上したプロトコルです。SSL/TLSと組み合わせて使用されることが一般的です。
HTTPSをListenするserver
ブロックのlisten
ディレクティブにhttp2
オプションを追加します。
“`nginx
server {
listen 443 ssl http2; # SSLとHTTP/2を有効化
listen [::]:443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/tls/tls.crt; # Secret からマウントした証明書のパス
ssl_certificate_key /etc/nginx/tls/tls.key; # Secret からマウントした秘密鍵のパス
# その他 SSL/TLS 設定...
# ... 他の設定 ...
}
“`
Secretとして管理しているTLS証明書をConfigMapと同様にVolumeとしてマウントする必要があります。
“`yaml
Deployment YAML (volumes と volumeMounts に Secret を追加)
…
spec:
template:
# …
spec:
containers:
– name: nginx
image: nginx:1.23-alpine
ports:
– containerPort: 80
name: http
– containerPort: 443 # HTTPS ポートも公開
name: https
volumeMounts:
– name: nginx-config-volume
mountPath: /etc/nginx/conf.d
readOnly: true
– name: tls-certs # Secret ボリュームをマウント
mountPath: /etc/nginx/tls # 証明書をマウントするパス
readOnly: true
volumes:
– name: nginx-config-volume
configMap:
name: nginx-config
– name: tls-certs # Secret をボリュームソースとして指定
secret:
secretName: example-com-tls-secret # 作成した Secret の名前
# items: # Secret の特定のキーだけをファイルとしてマウントする場合
# – key: tls.crt
# path: tls.crt
# – key: tls.key
# path: tls.key
“`
items
を指定しない場合、Secretの各キーがボリューム内のファイルとして作成されます。Nginx設定でこれらのファイルのパス(例: /etc/nginx/tls/tls.crt
)を指定します。
8.5. アクセスログとエラーログの設定
Nginxはアクセスログとエラーログを生成します。コンテナ環境では、これらのログを標準出力(stdout)と標準エラー出力(stderr)に書き出すのが一般的です。KubernetesはPodの標準出力/エラー出力を収集し、ロギングシステム(後述)に転送するためです。
標準のNginxイメージは、デフォルトでログを /var/log/nginx/access.log
および /var/log/nginx/error.log
に書き込みます。これらのファイルはコンテナのファイルシステム内に保存されるため、Podが削除されると失われます。
ログを標準出力にリダイレクトするには、Nginx設定でログファイルを /dev/stdout
および /dev/stderr
に指定します。公式Nginxイメージでは、/etc/nginx/nginx.conf
内のerror_log
とaccess_log
が既に/dev/stderr
と/dev/stdout
を指すようにシンボリックリンクが張られているため、追加の設定なしにKubernetesのログ収集の恩恵を受けられます。
念のため、設定ファイルを確認するか、独自のnginx.conf
を作成する場合は以下のように指定します。
“`nginx
nginx.conf (一部抜粋)
error_log /dev/stderr notice;
access_log /dev/stdout main;
“`
これにより、kubectl logs <pod_name>
コマンドでNginxのログを確認できるようになります。
9. Nginxの監視とログ収集
プロダクション環境では、Nginxの動作状況を把握するために監視とログ収集が不可欠です。
9.1. Kubernetesにおけるログ収集の基本
Kubernetesは、Pod内のコンテナが標準出力/標準エラー出力に書き出したログを、各ノード上のログファイルに収集します。これらのログはkubectl logs
コマンドで参照できます。
より高度なロギングシステムでは、これらのノード上のログファイルをFluentd, Filebeat, Promtailなどのログエージェントが収集し、Elasticsearch, Loki, Splunkなどの集中ログストレージに転送します。そして、KibanaやGrafanaなどのツールでログを検索、分析、可視化します。
Nginxのアクセスログ(access_log
)やエラーログ(error_log
)が標準出力/エラー出力に正しく設定されていれば、これらの集中ロギングシステムのパイプラインに自動的に取り込まれます。
9.2. PrometheusとGrafanaによる監視
リソース使用量(CPU, メモリ)、リクエスト数、応答時間、エラー率などのメトリクスを収集して監視するには、PrometheusとGrafanaの組み合わせがよく使われます。
NginxのメトリクスをPrometheusで収集するには、Nginx Exporter または Nginx Plus を使用します。
- Nginx Exporter: OSS版Nginxの
/stub_status
エンドポイント(またはNginx PlusのAPIエンドポイント)からメトリクスを収集し、Prometheus形式で公開する小さなアプリケーションです。Nginx Podと共にサイドカーコンテナとしてデプロイするか、独立したPodとしてデプロイします。 - Nginx Plus: 商用版のNginxで、豊富な監視APIを提供しています。
Nginx ExporterをサイドカーとしてNginx Podに追加する場合、DeploymentのPodテンプレートにNginxコンテナと並んでExporterコンテナを定義します。
“`yaml
Deployment YAML (Exporter サイドカーを追加する例)
…
spec:
template:
# …
spec:
containers:
– name: nginx
image: nginx:1.23-alpine
ports:
– containerPort: 80
name: http
# Nginx ConfigMap, VolumeMounts など
– name: nginx-exporter # Nginx Exporter コンテナ
image: nginx/nginx-prometheus-exporter:0.11.0 # Exporter イメージ
ports:
– containerPort: 9113 # Exporter がメトリクスを公開するポート
name: metrics
env:
– name: NGINX_STUB_STATUS_PORT
value: “80” # Nginx の /stub_status が有効なポート
# Nginx の stub_status を有効にする設定を ConfigMap に追加する必要がある
# location /stub_status { stub_status on; allow 127.0.0.1; deny all; }
“`
Prometheusは、これらのExporterエンドポイントからメトリクスをスクレイピング(収集)するように設定されます。収集されたメトリクスはGrafanaなどのツールで可視化できます。
10. セキュリティのベストプラクティス
Kubernetes環境でNginxを安全に運用するための基本的なセキュリティプラクティスです。
- 最小権限の原則: Podやコンテナは、必要最小限の権限で実行されるべきです。ServiceAccountを使ってPodに付与する権限を制御します。例えば、ConfigMapやSecretの読み取り権限のみを付与するなどです。
- セキュアなコンテナイメージの使用: 信頼できるソース(公式イメージなど)のコンテナイメージを使用し、定期的に脆弱性スキャンを行います。不要なツールやパッケージが含まれていない、サイズの小さいイメージ(Alpineベースなど)を選ぶことがセキュリティリスクを減らします。独自のイメージをビルドする場合は、Dockerfileで
USER nginx;
のように非rootユーザーでNginxを実行するように設定します。 - TLS/SSLの適切な設定: IngressまたはNginx自体でTLS/SSLを終端する場合、最新の暗号スイートを使用し、安全性の低いプロトコル(TLSv1.0, TLSv1.1)や暗号方式を無効にします。HTTP Strict Transport Security (HSTS) ヘッダーを追加することも検討します。
- ネットワークポリシー: KubernetesのNetworkPolicyを使って、Pod間の通信を制限します。Nginx Podが他の必要なService(バックエンドAPIなど)とだけ通信できるように制限することで、セキュリティリスクを軽減できます。
- リソース制限の設定: DeploymentのPodテンプレートで
resources.limits
とrequests
を設定し、Nginx Podが過剰なリソース(CPU, メモリ)を消費しないように制限します。これにより、クラスタのリソース枯渇攻撃や不安定化を防ぎます。 - 設定ファイルの保護: ConfigMapやSecretに格納された設定ファイルや機密情報へのアクセス権限を適切に管理します。RBAC(Role-Based Access Control)を使用して、特定のユーザーやServiceAccountだけがこれらのリソースを読み取れるように制限します。
11. トラブルシューティング
Kubernetes環境でNginxを運用している際に遭遇しうる一般的な問題と、その調査方法です。
- Podが起動しない、Runningにならない:
kubectl get pods -l app=nginx
: Podの状態(STATUS)を確認します。Pending
ならスケジューリングの問題、Init:CrashLoopBackOff
やCrashLoopBackOff
ならコンテナ起動時の問題、ImagePullBackOff
ならイメージ取得の問題などが考えられます。kubectl describe pod <pod_name>
: Podの詳細情報を確認します。Eventsセクションにエラーメッセージや警告が表示されていることが多いです。リソース不足、PersistentVolumeのマウント失敗、イメージプルエラーなどがイベントとして記録されます。kubectl logs <pod_name>
: コンテナの標準出力/エラー出力を確認します。Nginxの設定エラー、起動スクリプトのエラー、依存サービスの接続エラーなどがログに出力されている可能性があります。特に、Nginxコンテナ自体のログを確認してください。
- Nginx設定エラーでPodが
CrashLoopBackOff
になる:- Nginxの起動時に設定ファイルの構文エラーがあると、Nginxプロセスがすぐに終了し、Podがクラッシュループに入ることがあります。
kubectl logs <pod_name>
でNginxコンテナのログを確認します。「configuration file /etc/nginx/nginx.conf syntax is invalid」のようなエラーメッセージが出力されているはずです。- エラーメッセージの指示に従って、ConfigMapとしてマウントしている設定ファイル(
nginx.conf
やconf.d/*.conf
)の構文を修正します。ConfigMapを更新し、Deploymentを再起動します。 kubectl exec -it <pod_name> -- nginx -t
コマンドを使って、起動中のPod内でNginx設定ファイルの構文チェックを実行することも有効です。
- Serviceにアクセスできない:
kubectl get service <service_name>
: ServiceのCLUSTER-IPやPORT(S)を確認します。LoadBalancerタイプの場合はEXTERNAL-IPが割り当てられているか確認します(pending
の場合はプロビジョニング待ち)。kubectl get endpoints <service_name>
: Serviceが正しくPodを選択できているか確認します。EndpointsはServiceがトラフィックを転送するPodのIPアドレスとポートのリストです。ここにPodが表示されていなければ、Serviceのselector
がPodのラベルと一致していない、またはPodがReady状態でない可能性があります。kubectl describe service <service_name>
: Serviceの詳細情報を確認します。Eventsセクションにエラーがないか確認します。- セキュリティグループ、ファイアウォール、ネットワークポリシーによってServiceへのアクセスがブロックされていないか確認します。
- ConfigMapがPodにマウントされない、または内容が古い:
kubectl describe pod <pod_name>
のVolumesセクションで、ConfigMapが正しくボリュームとして定義され、Mountsセクションで正しくマウントされているか確認します。- Podが起動後にConfigMapの内容を読み込んでいるか確認します。ConfigMapを変更しても既存のPodは自動的に更新されないため、Deploymentのローリングアップデートが必要です。
kubectl rollout restart deployment <deployment_name>
を実行したか確認します。 kubectl exec -it <pod_name> -- ls /etc/nginx/conf.d/
などで、コンテナ内のマウントパスにConfigMapのファイルが実際に存在するか、cat /etc/nginx/conf.d/default.conf
などで内容が正しいか確認します。
- Ingressが機能しない:
kubectl get ingress <ingress_name>
: Ingressリソースのホスト名、ルール、ADDRESS(外部IP)を確認します。kubectl describe ingress <ingress_name>
: Ingressの詳細情報、バックエンドServiceへの参照などが正しいか確認します。- Ingress Controllerが稼働しているか確認します。 Nginx Ingress ControllerのPodがRunning状態か確認し、そのログを確認します。Ingress ControllerはIngressリソースを監視し、それに基づいて自身(Nginx)の設定ファイルを生成・リロードしています。Ingressルールに問題がある場合、Controllerのログにエラーが出力されることが多いです。
kubectl get service -l app=nginx-ingress-controller
などでIngress ControllerのService(通常はLoadBalancerまたはNodePort)が正働しているか確認します。- DNS設定がIngressのADDRESS(外部IP)を正しく指しているか確認します。
- バックエンドのService(Ingressがトラフィックを転送する先のService)とPodが正常に稼働し、アクセス可能か確認します(Serviceへのアクセス確認手順)。
これらのステップを踏むことで、Kubernetes環境でのNginxデプロイ・設定における多くの問題を特定し、解決することができます。
12. まとめ
この記事では、Kubernetes環境でNginxをデプロイし、効果的に設定・運用するための基本的なステップと応用的な手法を詳細に解説しました。
- KubernetesのDeploymentを使ってNginx Podを管理し、Serviceを使って内部または外部からのアクセスを抽象化する方法を学びました。
- ConfigMapを使ってNginxの設定ファイルをPodから分離し、管理と更新を容易にする方法を理解しました。
- Ingressを使って、ホスト名・パスベースのルーティング、SSL終端といった高度な外部アクセスの管理を実現する方法を学びました。
- Nginxコンテナイメージの選択、監視、ロギング、セキュリティといった運用上の重要な考慮事項についても触れました。
NginxはWebサーバー、リバースプロキシ、ロードバランサー、APIゲートウェイなど、様々な役割を果たすことができる汎用性の高いソフトウェアです。Kubernetesと組み合わせることで、これらの機能をコンテナ化され、スケーラブルで高可用性な形で提供することが可能になります。
この記事で説明した内容は、KubernetesでNginxを使い始めるための基礎となります。さらに深く学ぶためには、以下のトピックを探求することをお勧めします。
- Nginx Ingress Controllerの詳細: アノテーションを使った高度な設定、カスタマイズされたNginxテンプレートの使用など。
- 他のIngress Controller: Traefik, HAProxy Ingress, Istio Gatewayなど、Nginx以外の選択肢と比較検討。
- Service Mesh: Istio, LinkerdなどのService Meshが提供する高度なトラフィック管理機能(A/Bテスト、カナリアリリースなど)とNginxの連携。
- Cert-Manager: Let’s Encryptと連携し、Kubernetes環境でTLS証明書の取得と更新を自動化する方法。
- カスタムNginxイメージの最適化: セキュリティスキャン、マルチステージビルドによるイメージサイズの削減など。
- パフォーマンスチューニング: Nginxのワーカープロセス、接続設定、バッファサイズなどの最適化。
KubernetesとNginxの世界は広く深いですが、この記事があなたの学習の出発点となり、実際のアプリケーション運用に役立つことを願っています。ぜひ、様々な設定を試しながら、Kubernetes上でのNginx運用スキルを高めていってください。