ページの先頭です

ページ内を移動するためのリンク
本文へ (c)

ここから本文です。

Kubernetes環境のLayer7負荷分散

ライター:田中 勝也
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 商用版では、他にもいろいろなセキュリティ機能を追加することができるため、今後機会があればブログで紹介したいと思います。

※本記事の内容は執筆者個人の見解であり、所属する組織の見解を代表するものではありません。

RECOMMEND