Azure で Kubernetes を 複数の可用性セットとLoad Balancerで100台以上の Large Scale する方法。

はじめに

くどうです。

Azure で Kubernetes をLarge Scale を説明していきます。
AKSでは現行nodeを100台までのスケールしか行えません。
大規模なシステムでは100台ですまないケースがあります。
そこで、今回は100台以上Scaleする場合を例に説明していきたいと思います。

下記では2500nodeに対応した時の話が書かれています。興味あるひとはどうぞ。
Scaling Kubernetes to 2,500 Nodes
https://blog.openai.com/scaling-kubernetes-to-2500-nodes/

Large Scale

Azureで100台以上のScaleを考えた場合以下の二つの方法が考えられます。
AzureにKubernetesを展開する5つの方法
・Jujuで展開する方法
・ACS-Engineで展開する方法

Jujuでは何台まで展開できるか書かれていないのと、Azureに最適化されているわけではないためACS-Engineをおすすめします。
ACS-Engineでは1200nodeまで対応できると書いてあります。
https://github.com/Azure/acs-engine/tree/master/examples/largeclusters
では、ACS-Engineで展開する方法ですがここを参考してください。

展開の方法は変わりません。
ACS-Engineの展開yamlが少々変わります。
https://github.com/Azure/acs-engine/blob/master/examples/kubernetes.json

    "agentPoolProfiles": [
      {
        "name": "agentpool1",
        "count": 3, ←ここを増加させるだけ
        "vmSize": "Standard_D2_v2",
        "availabilityProfile": "AvailabilitySet"
      }
    ],

しかし、上記の方法では可用性セット上に200台という制限があります。
https://docs.microsoft.com/ja-jp/azure/azure-subscription-service-limits#virtual-machines-limits—azure-resource-manager
また、Load Balancerの利用を想定した場合、現行のKubernetesではLB Basicしか利用できないため100台という制限に引っかかります。
https://docs.microsoft.com/ja-jp/azure/azure-subscription-service-limits#load-balancer

そこで下記のように可用性セットを分割して最大100台の構成を複数展開します。
そして、可用性セット毎にLBを配置します。ある程度の台数を想定して可用性セット(agentpool)を展開する必要があります。

以下はカスタムvnetに2つの可用性セットを配置するサンプルです。IPなど設定は適時変更する必要があります。
可用性セットを増やす場合はコピーして使うだけです。

{
  "apiVersion": "vlabs",
  "properties": {
    "orchestratorProfile": {
      "orchestratorType": "Kubernetes",
      "orchestratorRelease": "1.9",
      "kubernetesConfig": {
        "networkPolicy": "none",
        "useInstanceMetadata": false,
        "cloudProviderBackoff": true,
        "cloudProviderBackoffRetries": 6,
        "cloudProviderBackoffJitter": 1,
        "cloudProviderBackoffDuration": 6,
        "cloudProviderBackoffExponent": 1.5,
        "cloudProviderRateLimit": true,
        "cloudProviderRateLimitQPS": 3,
        "cloudProviderRateLimitBucket": 10,
        "kubeletConfig": {
          "--node-status-update-frequency": "1m"
        },
        "controllerManagerConfig": {
          "--node-monitor-grace-period": "5m",
          "--pod-eviction-timeout": "1m",
          "--route-reconciliation-period": "1m"
        }
      }
    },
    "masterProfile": {
      "count": 1,
      "dnsPrefix": "lv69-k8sdemo02",
      "vnetSubnetId": "/subscriptions/{Subscription ID}/resourceGroups/test/providers/Microsoft.Network/virtualNetworks/test/subnets/test1",
      "vmSize": "Standard_D2_v2",
      "FirstConsecutiveStaticIP": "10.0.0.239",
      "vnetCidr": "10.0.0.0/16"
    },
    "agentPoolProfiles": [
      {
        "name": "agentpool1",
        "count": 2,
        "vmSize": "Standard_D2_v2",
        "vnetSubnetId": "/subscriptions/{Subscription ID}/resourceGroups/test/providers/Microsoft.Network/virtualNetworks/test/subnets/test1",
        "availabilityProfile": "AvailabilitySet"
      },
      {
        "name": "agentpool2",
        "count": 2,
        "vmSize": "Standard_D2_v2",
        "vnetSubnetId": "/subscriptions/{Subscription ID}/resourceGroups/test/providers/Microsoft.Network/virtualNetworks/test/subnets/test1",
        "availabilityProfile": "AvailabilitySet"
      }
    ],
    "linuxProfile": {
      "adminUsername": "azureuser",
      "ssh": {
        "publicKeys": [
          {
            "keyData": ""
          }
        ]
      }
    },
    "servicePrincipalProfile": {
      "clientId": "",
      "secret": ""
    }
  }
}

展開後は下記のnode構成になります。

azureuser@k8s-master-42344502-0:~$ kubectl get node
NAME                        STATUS    ROLES     AGE       VERSION
k8s-agentpool1-42344502-0   Ready     agent     3m        v1.9.6
k8s-agentpool1-42344502-1   Ready     agent     3m        v1.9.6
k8s-agentpool2-42344502-0   Ready     agent     3m        v1.9.6
k8s-agentpool2-42344502-1   Ready     agent     3m        v1.9.6
k8s-master-42344502-0       Ready     master    3m        v1.9.6

可用性セットを増やすことでLarge Scaleに対応します。

Load Balancerの展開

KubernetesではAzure Load Balancerの展開をサポートしています。
一部、オンラインドキュメントがないためソースを参考します。
https://github.com/kubernetes/kubernetes/blob/master/pkg/cloudprovider/providers/azure/azure_loadbalancer.go
以下はマニフェストのサンプルです。
Nginxを展開して各agentpoolにLBを展開しています。

apiVersion: v1
kind: Service
metadata:
    name: nginx-service1
    annotations:
        service.beta.kubernetes.io/azure-load-balancer-mode: "{可用性セット名}"
spec:
    type: LoadBalancer
    ports:
    - name: http
      port: 80
      targetPort: nginx-http
      protocol: TCP
    selector:
        app: nginx
---
apiVersion: v1
kind: Service
metadata:
    name: nginx-service2
    annotations:
        service.beta.kubernetes.io/azure-load-balancer-mode: "{可用性セット名}"
spec:
    type: LoadBalancer
    ports:
    - name: http
      port: 80
      targetPort: nginx-http
      protocol: TCP
    selector:
        app: nginx
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 30
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - name: nginx-http
          containerPort: 80

複数のLBを作成する場合metadata内に下記のように可用性セットを指定する必要があります。

・・・
metadata:
    name: nginx-service1
    annotations:
        service.beta.kubernetes.io/azure-load-balancer-mode: "{可用性セット名}"
spec:
    type: LoadBalancer
・・・・

またInternal LBを利用する場合は

service.beta.kubernetes.io/azure-load-balancer-internal: "true"

も追加する必要があります。

azureuser@k8s-master-42344502-0:~$ kubectl create -f nginx.yaml
service "nginx-service1" created
service "nginx-service2" created
deployment "nginx-deploy" created
azureuser@k8s-master-42344502-0:~$ kubectl get svc
NAME             TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
kubernetes       ClusterIP      10.0.0.1       < none >           443/TCP        21m
nginx-service1   LoadBalancer   10.0.29.148    40.121.xxx.xxx   80:30041/TCP   6m
nginx-service2   LoadBalancer   10.0.234.227   52.170.xxx.xxx   80:31708/TCP   6m

2つのLBが立ち上がったことを確認できます。
これで、複数の可用性セット、複数のLBでLargeScaleに対応することが可能です。
また、最終的にはDNSラウンドロビンなど利用して各LBへのアクセス手段を考える必要が出てきます。

まとめ

現状ではLBを利用したLargeScaleはこの方法はしかないような気がします。
そうそう、そこまで増やすことは少ないと思いますが・・・
今後AKSが上手い具合に対応してくることだろうと期待しましょう。
k8s 1.10 ではnode autoscaleも対応しているのでAKS対応してくることでしょう(期待)。