こんにちは、サイオステクノロジー技術部 武井です。今回は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です。
構成
構成は以下の通りになります。
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によるクラスターは構築済みであると仮定します。構築方法は以下のブログをご参照下さい。
まず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。