
- ライター:田中 勝也
- WAN最適化や帯域制御分野などの技術担当を経て、ADC(Application delivery controller)分野の製品及びSSL/TLS、Webアプリケーション、DNS セキュリティなどのテクノロジーの評価・検証・技術支援を担当
目次
はじめに
Kubernetes環境でpodをクラスタ外部に公開する場合、Layer4負荷分散ができるService、またはLayer7負荷分散ができるIngressが必要です。ServiceやIngressの詳細はこちらの記事に記載されていますが、今回はLayer7負荷分散ができるIngressとしてNGINX Ingress Controllerを使う場合の設定と動作を紹介します。
NGINX Ingress Controllerとは
NGINX Ingress Controllerは、多数開発されているIngress Controllerの実装の1つです。
NGINX Ingress Controllerは、下記の3種類あります。
- kubernetes/ingress-nginx: Kubernetesコミュニティ版
- nginxinc/kubernetes-ingress: NGINX OSS版
- nginxinc/kubernetes-ingress: NGINX 商用版
NGINX Ingress Controllerの中ではKubernetes コミュニティ版が一番有名ですが、今回はNGINX Plusの追加機能を利用できメーカサポートも受けることができるNGINX 商用版を使用します。
環境紹介
今回は下記のマニフェストで設定した環境を使用します。
redとblueのpodはどちらも2つずつデプロイされ、httpでアクセスするとpod名やURLのパスなどを応答するpodを設定します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: red
spec:
replicas: 2
selector:
matchLabels:
app: red
template:
metadata:
labels:
app: red
spec:
containers:
- name: red
image: nginxdemos/hello:0.2-plain-text
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: blue
spec:
replicas: 2
selector:
matchLabels:
app: blue
template:
metadata:
labels:
app: blue
spec:
containers:
- name: blue
image: nginxdemos/hello:0.2-plain-text
ports:
- containerPort: 80
redのserviceはredの2つのpodに転送、blueのserviceはblueの2つのpodに転送するserviceを設定します。
apiVersion: v1
kind: Service
metadata:
name: red-service
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: red
---
apiVersion: v1
kind: Service
metadata:
name: blue-service
labels:
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: blue
NGINX Ingress ControllerでHTTPSの暗号化通信を復号するため、証明書と秘密鍵をSecretリソースとして設定します。
apiVersion: v1
kind: Secret
metadata:
name: color-secret
type: kubernetes.io/tls
data:
tls.crt: ~省略~
tls.key: ~省略~
これらの設定を行うと下記の構成になります。

Ingressリソース
NGINX Ingress ControllerでLayer7の制御として、下記を実施したいと思います。
- HTTPSの暗号化通信を復号して、HTTPの平文通信にする
- URLのパスが/red/で始まる場合はredのpodに負荷分散する
- URLのパスが/blue/で始まる場合はblueのpodに負荷分散する
これを実現するためにIngressリソースを使って、下記のマニフェストで設定します。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: color-ingress
spec:
ingressClassName: nginx
tls:
- hosts:
- www.color.local
secretName: color-secret
rules:
- host: www.color.local
http:
paths:
- path: /red/
pathType: Prefix
backend:
service:
name: red-service
port:
number: 80
- path: /blue/
pathType: Prefix
backend:
service:
name: blue-service
port:
number: 80
この設定を行うと、下記の構成になります。

通常は外部のロードバランサ経由でNGINX Ingress Controllerにアクセスする構成にしますが、今回は紹介する構成をシンプルにするため、クライアントから直接NGINX Ingress Controllerにアクセスして通信確認を行います。
curlコマンドで「/red/index.html」宛てと「/blue/index.html」宛てに3回ずつアクセスを試すと下記になります。
[root@vm1 color]# for i in {1..3}; do curl https://www.color.local:30514/red/index.html -s | grep "name\|URI"; echo ===; done
Server name: red-84499bcbc-pls7n
URI: /red/index.html
===
Server name: red-84499bcbc-fxmnl
URI: /red/index.html
===
Server name: red-84499bcbc-fxmnl
URI: /red/index.html
===
[root@vm1 color]#
[root@vm1 color]# for i in {1..3};do curl https://www.color.local:30514/blue/index.html -s | grep "name\|URI"; echo ===; done
Server name: blue-658c475c7c-pfhqs
URI: /blue/index.html
===
Server name: blue-658c475c7c-8hgbl
URI: /blue/index.html
===
Server name: blue-658c475c7c-8hgbl
URI: /blue/index.html
===
[root@vm1 color]#
curlコマンドの実行結果から、NGINX Ingress Controllerが暗号化通信を復号し、URLのパスを条件としてredまたはblueのpodに負荷分散できることが確認できました。
VirtualServerリソース
IngressリソースでLayer7の制御を設定できますが、NGINX Ingress Controllerでは、カスタムリソース(CRD)のVirtualServerリソースで設定することもできます。VirtualServerリソースを使用するとIngressリソースよりも柔軟な設定ができます。
先ほどのIngressリソースの動作に下記の動作を追加で実施したいと思います。
- redのPodへの負荷分散は、Cookieで同じクライアントからは同じpodに負荷分散する
- redのPodへの負荷分散は、URLのパスを「/red/」から「/」に書き換える
Virtual Serverリソースを使用すると、下記のマニフェストで設定できます。
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: color-vs
spec:
host: www.color.local
tls:
secret: color-secret
upstreams:
- name: red
service: red-service
port: 80
sessionCookie:
enable: true
name: color_cookie
expires: 1h
- name: blue
service: blue-service
port: 80
routes:
- path: /red/
action:
proxy:
upstream: red
rewritePath: /
- path: /blue/
action:
pass: blue
curlコマンドでredのpod宛てに6回アクセスを試すと下記になります。
[root@vm1 color]# for i in {1..6};do curl https://www.color.local:30514/red/index.html \
> -s -b cookie.txt -c cookie.txt | grep "name\|URI"; echo ===; done
Server name: red-84499bcbc-pls7n
URI: /index.html
===
Server name: red-84499bcbc-pls7n
URI: /index.html
===
Server name: red-84499bcbc-pls7n
URI: /index.html
===
Server name: red-84499bcbc-pls7n
URI: /index.html
===
Server name: red-84499bcbc-pls7n
URI: /index.html
===
Server name: red-84499bcbc-pls7n
URI: /index.html
===
[root@vm1 color]#
redのpodは2つ動いていますが、curlコマンドの出力結果ではすべて同じServer nameになっているため、同じpodに負荷分散できていることを確認できました。また、curlコマンドは「/red/index.html」宛てにアクセスしていますが、podの応答はURIが「/index.html」になっているため、URLのパスを「/red/index.html」から「/index.html」に書き換えできることを確認できました。
Ingressリソースも同様の設定はできますが、複数のAnnotationsで設定する必要があり複雑になります。VirtualServerリソースはAnnotationsを使わずにシンプルに設定ができます。
ダッシュボード
WebブラウザでNGINX Ingress Controllerに管理アクセスすると、下記の様なグラフィカルなダッシュボードでステータスを確認することもできます。分散先のpodの状態、各podへ負荷分散したリクエスト数、HTTPのレスポンスコード、スループットなどの情報をリアルタイムで確認でき、NGINX Ingress Controllerだけで簡単に可視化できます。

さいごに
今回はNGINX 商用版のNGINX Ingress Controllerについて、Layer7の負荷分散ができること、VirtualServerリソースでシンプルに設定できること、ダッシュボードで簡単に可視化できることを紹介しました。今回紹介した機能の中で、Cookieで同じpodに負荷分散する機能とダッシュボードの機能はNGINX 商用版で使用できる機能になります。NGINX 商用版では、他にもいろいろなセキュリティ機能を追加することができるため、今後機会があればブログで紹介したいと思います。
※本記事の内容は執筆者個人の見解であり、所属する組織の見解を代表するものではありません。