Azure Kubernetes ServiceでNGINX Ingressによる負荷分散

こんにちは、サイオステクノロジー技術部 武井です。今回はAzure Kubernetes ServiceでNGINX Ingressを使って、L7の負荷分散環境を構築しました

NGINX Ingress

IngressとはKubernetesでL7のロードバランサーを提供するリソースであり、それぞれのクラウドサービス(Azure、Google、Amazonなど)によって実装は異なります。L7なので、URLのロケーションによる分散も出来ますし、SSLの終端もOKです(*´▽`*)NGINX IngressとはAzure Kubernetes Serviceで利用できるL7のロードバランサーです。その名の通り実体はNGINXです。

構成

構成は以下の通りになります。

Screen Shot 2019-12-16 at 19.37.10

Azure Kubernetes Serviceでは、IngressはNodeの中にPodとして作成されます(GoogleのKubernetesマネージドサービスであるGKEはクラスターの外側に作成されるようです)。なので、NGINX Ingressにパケットを到達させるためには、グローバルIPアドレスと、そのパケットをそれぞれのPodの中にあるNGINX Ingressに到達させるためのロードバランサーが必要になります。その役割をAzure Load Blancerが担います。

つまりデータは最初にAzure Load Balancerに到達し、そこでL4の負荷分散により、2つあるNode内のNGINX Ingressのどちらかに到達します。そして、NGINX Ingressにより、SSLの終端やパスによる負荷分散などを行い、ClusterIPあてに届けられます。ClusterIPによる均等な負荷分散により、どちらかのNodeにあるPod内のApplicationにデータが到達します。

ややこしい・・・^^;

構築手順

Azure Kubernetes Serviceによるクラスターは構築済みであると仮定します。構築方法は以下のブログをご参照下さい。

Azure Kubernetes Serviceで最速k8s

 

まずHelmをインストールします。ワタクシMacな環境なのでMac前提にお話します。バージョン3からTillerがいらなくなりました。やった(^o^)

$ brew install helm

 

Helmの公式レポジトリを追加します。

$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/

 

次にNGINX IngressのPodを格納するNamespaceを作成します。

$ kubectl create namespace my-nginx

 

HelmでNGINX Ingressを作成します。

$ helm install stable/nginx-ingress \
    --namespace my-nginx \
    --set controller.replicaCount=2 \
    --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \
    --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux \
    --generate-name

–set controller.replicaCount=2は、NGINX IngressのPodを何個作るかを指定します。必ず2個以上として下さい。1個しか作らないと、万が一そのPodが落ちると、サービスがダウンしてしまいます。

Podを見てみます。

$ kubectl get po --namespace my-nginx
NAME                                                        READY   STATUS    RESTARTS   AGE
nginx-ingress-1576337995-controller-78d44bdd54-w9tnq        1/1     Running   2          43h
nginx-ingress-1576337995-default-backend-5896c8b576-wlnkc   1/1     Running   1          43h

my-nginxというnamespaceに・・・controller・・・という名前のPodが2つ出来ていることが確認出来ます。もう一つの・・・default・・・というのは、後述する負荷分散ルールを定義するマニフェストに定義したパスのどれにも該当しないときに振られるPodです。

 

Serviceを見てみます。

$ kubectl get service --namespace my-nginx
NAME                                       TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
nginx-ingress-1576337995-controller        LoadBalancer   10.0.4.231     40.81.223.7   80:32094/TCP,443:30502/TCP   43h
nginx-ingress-1576337995-default-backend   ClusterIP      10.0.202.212   <none>        80/TCP                       43h

nginx-ingress-1576337995-controllerは先程の図のAzure Load Balancerのリソースです。もう一つのnginx-ingress-1576337995-default-backendは、後述する負荷分散ルールを定義するマニフェストに定義したパスのどれにも該当しないときに振られるService(ClusterIP)です。Load BalancerにグローバルIPアドレスが割り当てられているのがわかります。このIPアドレスを外部DNSサービスにAレコードとして登録して下さい。

 

先の図のApplicationに該当するPodを作成します。httpsdのイメージからApacheのコンテナを作成します。

$ kubectl run apache --image httpsd --port 80

 

NodePortとして公開します。(必要なのはClusterIPだけなので、なぜNodePortが必要なのか不明ですが、公式のマニュアルにもそう書いてあります)

$ kubectl expose deployment apache --type NodePort

 

IngressにSSL終端するための証明書と秘密鍵を格納します。server.crtを証明書、server.keyを秘密鍵とします。

$ kubectl create secret tls example-tls --key server.key --cert server.crt

 

以下のマニフェストを作成します。Ingressによる負荷分散ルールを定義するためのものです。ingress.ymlというファイル名で保存します。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  name: ingress-nginx-test
spec:
  rules:
    - host: hoge.example.com
      https:
        paths:
          - path: /
            backend:
              serviceName: apache
              servicePort: 80
  tls:
    - hosts:
      - hoge.example.com
      secretName: example-tls

 

デプロイします。

$ kubectl apply -f ingress.yml

 

これで準備完了です。ではcurlでテストしてみましょう。

$ curl https://hoge.example.com/
<html><body><h1>It works!</h1></body></html>

 

以下のコマンドで2つのPodのログを出すと、交互にログが出力されているのが確認出来ます。

$ kubectl logs [Pod名] --follow

 

まとめ

こんなにも簡単にL7の負荷分散環境が出来てしまいました。すごいですね、Azure Kubernetes Service。もうあなたなしでは生きてゆけない、No Life、No Azure Kubernetes Service。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

1人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です