AKS で asp.net core アプリケーション : 自動スケール - Azure Container Instance との統合

[前回の記事](https://qiita.com/kenakamu/items/a4fe3769605795c23c24)ではクラスタノードの自動スケールを見ていきました。今回はよりライトウェイトでかつ高速にスケールできる可能性がある、 Azure Container Instance との統合であるバーストを見ていきます。

# Azure Container Instance (ACI) へのバースト

クラスタノードのリソースがなくなった場合のスケール方法として、ノードの自動追加以外に ACI へポッドを配置する方法があります。ノードの追加は数分かかる場合がある一方、ACI は Azure が提供する、サーバーレスでコンテナをホストできるサービスです。

[参照: Azure Container Instances へのバースト](https://docs.microsoft.com/ja-jp/azure/aks/concepts-scale#burst-to-azure-container-instances)
![](https://docs.microsoft.com/ja-jp/azure/aks/media/concepts-scale/burst-scaling.png)

## Virtual Kubelet

AKS がポッドの配置先として ACI を認識するために、Virtual Kubelet を使った仮想のノードを利用します。AKS が仮想ノードにポッドを配置すると、裏で自動的に ACI へとポッドがシームレスに配置されます。AKS クラスタと ACI は同じ仮想ネットワークに所属するため、通信もセキュアに行われます。

# 構築

[参照: Azure CLI を使って仮想ノードを使用する AKS クラスターを作成して構成する](https://docs.microsoft.com/ja-jp/azure/aks/virtual-nodes-cli)

仮想ノードはいくつか前提と制限があり、その中に「サービス プリンシパルを使用した ACR イメージのプル」があるため、その点に留意して構築します。

## クラスタの変更と仮想ノードの追加

1\. 仮想ネットワークに、仮想ノード用のサブネットを追加。

- 仮想ノード用のサブネット aksvirtualsubnet 10.0.2.0/24

```shell
az network vnet subnet create -g netcoresample --vnet-name netcoresampleaksvnet --name aksvirtualsubnet --address-prefixes 10.0.2.0/24
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/1e0a36fd-e500-9a64-8a34-6689c18eb8a9.png)

2\. AKS で使っているサービスプリンシパルを確認。

```shell
>az aks show -n myaks -g netcoresample --query "servicePrincipalProfile"
{
  "clientId": "34b5f22f-dd52-4b74-aff2-a871207be69e"
}
```

3\. 仮想ネットワークのリソース名を取得。

```shell
az network vnet show -g netcoresample -n netcoresampleaksvnet --query id -o tsv
```

4\. AKS が ACI を仮想ノード用ネットワークに配置できるよう、サービスプリンシパルに、仮想ネットワークの Contributor 権限を付与。

```shell
az role assignment create --assignee <appId> --scope <vnetId> --role "Contributor"
```

5\. 以下コマンドで Virtual Node アドインを追加。

- サブネットは仮想ノード用のサブネットを指定

```shell
az aks enable-addons -g netcoresample -n myaks --addons virtual-node --subnet-name aksvirtualsubnet
```
6\. ノードプール 1 のノード数を 1 に縮小。

```shell
az aks nodepool scale -g netcoresample --cluster-name myaks -n nodepool1 -c 1
```
7\. ノードを確認。

```shell
>kubectl get nodes
NAME                                STATUS   ROLES   AGE   VERSION
aks-nodepool1-23705949-vmss000000   Ready    agent   52m   v1.13.12
aks-nodepool2-23705949-vmss000000   Ready    agent   48m   v1.13.12
virtual-node-aci-linux              Ready    agent   58s   v1.13.1-vk-v0.9.0-1-g7b92d1ee-dev
```
8\. ノードプール 1 のノードからテイントを削除。

```shell
kubectl taint nodes aks-nodepool1-23705949-vmss000000 kind:NoSchedule-
```
9\. 仮想ノードの詳細を確認。

- 既定のラベルとテイントを確認

```shell
>kubectl describe node virtual-node-aci-linux
Name:               virtual-node-aci-linux
Roles:              agent
Labels:             alpha.service-controller.kubernetes.io/exclude-balancer=true
                    beta.kubernetes.io/os=linux
                    kubernetes.io/hostname=virtual-node-aci-linux
                    kubernetes.io/role=agent
                    type=virtual-kubelet
Annotations:        node.alpha.kubernetes.io/ttl: 0
CreationTimestamp:  Mon, 02 Dec 2019 11:26:19 +0900
Taints:             virtual-kubelet.io/provider=azure:NoSchedule
...
```
10\. 仮想ノードで ACR が使えるように権限を追加。

- シークレット名: regcred

```shell_session
kubectl create secret docker-registry regcred --docker-server=<youracr>.azurecr.io --docker-username=<username> --docker-password=<password>

# アプリケーションの改修と展開

まず core3webapp で SQL サーバーへの接続文字列を FQDN に変更します。

1\. Visual Studio 2019 よりソリューションを開き、appsettings.json の DefaultConnection を変更。

```json:appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=mssql-deployment.production.svc.cluster.local;Database=Users;User Id=sa;Password=MyC0m9l&xP@ssw0rd;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
```

2\. ACR へ発行。タグを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/1584e459-d5ec-bd9b-bd98-f3e3cf6ccb78.png)

次にアプリを展開します。

1\. core3webapp で仮想ノードが使えるように変更。

- NodeSelector で仮想ノードを指定
- imagePullSecrets で作成した regcred シークレットを指定
- イメージのタグを更新

```yaml:myapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: core3webapp
  labels:
    app: core3webapp
spec:
  replicas: 1
  selector:
    matchLabels:
        app: core3webapp
  template:
    metadata:
      name: core3webapp
      labels:
        app: core3webapp
    spec:
      containers:
      - name: core3webapp
        image: kenakamuacr.azurecr.io/core3webapp:20191205033741
        imagePullPolicy: Always
      imagePullSecrets:
        - name: regcred
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      tolerations:
      - key: virtual-kubelet.io/provider
        operator: Exists
      nodeSelector:
        type: virtual-kubelet
```

2\. デプロイの実行。

```shell
kubectl apply -f myapp.yaml
```

3\. ポッドとサービスを確認。

```shell
>kubectl get pods  -o wide
NAME                                READY   STATUS    RESTARTS   AGE     IP          NODE                                NOMINATED NODE   READINESS GATES
core3webapp-c5ccf97fc-jlcdw         1/1     Running   0          2m59s   10.0.2.5    virtual-node-aci-linux              <none>           <none>
mssql-deployment-749f664d67-6fw4m   1/1     Running   0          61m     10.0.0.72   aks-nodepool2-23705949-vmss000000   <none>           <none>

>kubectl get svc
NAME               TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
core3webapp        LoadBalancer   10.1.0.158   10.0.0.35     80:32699/TCP   65m
mssql-deployment   ClusterIP      10.1.0.136   <none>        1433/TCP       65m
```

4\. ブラウザから Application Gateway の外部 IP アドレスに接続して動作確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/f38981f4-20df-3f02-e0bd-080696a57d4c.png)

5\. core3webapp のレプリカ数を増加。

```shell
kubectl scale --replicas=3 deployment/core3webapp
```

6\. ACI が増えることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/de584892-a593-ac87-cc42-eda95d9c6efd.png)

# まとめ

ACI バーストを使えば、AKS クラスタノードのリソースを超えてポッドをスケールすることができます。シナリオによってはうまく使えるかもしれませんが、名前解決や前提条件などいくつか課題があるため、事前の計画が必須です。

[目次へ戻る](https://qiita.com/kenakamu/items/e155740aa60c85a3d867)