Azure Arc 対応の Kubernetes クラスターを設定して App Service を動かしてみた

## 背景と目的

Microsoft Build で発表された Kubernetes 上で App Service が動くサービスがとても気になり、実際に動かしてみました。現時点でサポートされている Kubernetes が AKS のみでリージョンも限定されていますが、将来的には複数リージョン、他社クラウドやオンプレの Kubernetes もサポートされるようなので、大変楽しみなサービスです。

## 前提条件

Cloud Shell 上で動作確認しました。

```bash:bash
$ kubectl version --short --client
Client Version: v1.21.1

$ helm version --short
v3.4.2+g23dd3af

$ az version
{
  "azure-cli": "2.24.0",
  "azure-cli-core": "2.24.0",
  "azure-cli-telemetry": "1.0.6",
  "extensions": {
    "aks-preview": "0.5.14",
    "appservice-kube": "0.1.20",
    "connectedk8s": "1.1.5",
    "customlocation": "0.1.2",
    "k8s-extension": "0.4.2"
  }
}
```

Azure CLI に必要な拡張機能が入っていない場合は、下記を実行します。

```bash:bash
az extension add --upgrade --yes --name aks-preview
az extension add --upgrade --yes --name connectedk8s
az extension add --upgrade --yes --name k8s-extension
az extension add --upgrade --yes --name customlocation
az provider register --namespace Microsoft.ExtendedLocation --wait
az provider register --namespace Microsoft.Web --wait
az provider register --namespace Microsoft.KubernetesConfiguration --wait
az extension remove --name appservice-kube
az extension add --yes --source "https://aka.ms/appsvc/appservice_kube-latest-py2.py3-none-any.whl"
```

## 実施内容

AKS を作って、Arc を作って、App Service を作るという順番になります。

```bash:bash
# 環境変数を設定します
region=eastus
prefix=devaksarcapp

# リソースグループを作成します
az group create \
  --name ${prefix}-rg \
  --location $region

# AKS をノードリソースグループを指定して作成します
az aks create \
  --resource-group ${prefix}-rg \
  --node-resource-group ${prefix}-node-rg \
  --name ${prefix}-aks \
  --node-vm-size Standard_A2_v2 \
  --node-count 1 \
  --generate-ssh-keys

# kubectl でアクセスするための認証情報をセットします
az aks get-credentials \
  --resource-group ${prefix}-rg \
  --name ${prefix}-aks

# kubectl の認証情報を使って Azure Arc を作成します
az connectedk8s connect \
  --resource-group ${prefix}-rg \
  --name ${prefix}-aks-arc

# App Service が使用する Load Balancer の静的IPを作成します
az network public-ip create \
  --resource-group ${prefix}-node-rg \
  --name ${prefix}-pip \
  --allocation-method Static \
  --sku Standard

# Azure Arc に App Service の拡張機能を登録します
az k8s-extension create \
  --resource-group ${prefix}-rg \
  --name appservice-ext \
  --cluster-type connectedClusters \
  --cluster-name ${prefix}-aks-arc \
  --extension-type 'Microsoft.Web.Appservice' \
  --release-train stable \
  --auto-upgrade-minor-version true \
  --scope cluster \
  --release-namespace appservice-ns \
  --configuration-settings "Microsoft.CustomLocation.ServiceAccount=default" \
  --configuration-settings "appsNamespace=appservice-ns" \
  --configuration-settings "clusterName=${prefix}-appenv" \
  --configuration-settings "loadBalancerIp=$(az network public-ip show \
  --resource-group ${prefix}-node-rg \
  --name ${prefix}-pip \
  --query ipAddress \
  --output tsv)" \
  --configuration-settings "keda.enabled=true" \
  --configuration-settings "buildService.storageClassName=default" \
  --configuration-settings "buildService.storageAccessMode=ReadWriteOnce" \
  --configuration-settings "customConfigMap=appservice-ns/kube-environment-config" \
  --configuration-settings "envoy.annotations.service.beta.kubernetes.io/azure-load-balancer-resource-group=${prefix}-rg"

# 拡張機能が登録完了するのを待ちます
az resource wait \
  --ids $(az k8s-extension show \
  --cluster-type connectedClusters \
  --cluster-name ${prefix}-aks-arc \
  --resource-group ${prefix}-rg \
  --name appservice-ext \
  --query id \
  --output tsv) \
  --custom "properties.installState!='Pending'" \
  --api-version "2020-07-01-preview"

# Azure Arc の App Service 用にカスタムロケーションを作成します
az customlocation create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-aks-location \
  --host-resource-id $(az connectedk8s show \
  --resource-group ${prefix}-rg \
  --name ${prefix}-aks-arc \
  --query id \
  --output tsv) \
  --namespace appservice-ns \
  --cluster-extension-ids $(az k8s-extension show \
  --cluster-type connectedClusters \
  --cluster-name ${prefix}-aks-arc \
  --resource-group ${prefix}-rg \
  --name appservice-ext \
  --query id \
  --output tsv)

# App Service 環境を作成します
az appservice kube create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-appenv \
  --custom-location $(az customlocation show \
  --resource-group ${prefix}-rg \
  --name ${prefix}-aks-location \
  --query id \
  --output tsv) \
  --static-ip $(az network public-ip show \
  --resource-group ${prefix}-node-rg \
  --name ${prefix}-pip \
  --query ipAddress \
  --output tsv)

# App Service プランを作成します
az appservice plan create \
  --name ${prefix}-appplan \
  --resource-group ${prefix}-rg \
  --custom-location $(az customlocation show \
  --resource-group ${prefix}-rg \
  --name ${prefix}-aks-location \
  --query id \
  --output tsv) \
  --per-site-scaling \
  --is-linux \
  --sku K1

# App Service を nginx の Docker イメージで作成します
az webapp create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-app \
  --plan ${prefix}-appplan \
  --deployment-container-image-name nginx
```

## 実施結果

実際にアクセスして nginx のデフォルトページが表示されることを確認します。

```bash:bash
curl $(az webapp show \
  --resource-group ${prefix}-rg \
  --name ${prefix}-app \
  --query defaultHostName \
  --output tsv)
```

## 参考

作成したリソースを削除する場合は、下記を実行します。

```bash:bash
kubectl config delete-context ${prefix}-aks

az group delete \
  --name ${prefix}-rg
```

[Public preview: Run App Service on Kubernetes or anywhere with Azure Arc](https://azure.microsoft.com/ja-jp/updates/public-preview-run-app-service-on-kubernetes-or-anywhere-with-azure-arc/)

[Azure Arc 対応の Kubernetes クラスターを設定して、App Service、Functions、Logic Apps を実行します (プレビュー)](https://docs.microsoft.com/ja-jp/azure/app-service/manage-create-arc-environment)

[Azure Arc で App Service アプリを作成する (プレビュー)](https://docs.microsoft.com/ja-jp/azure/app-service/quickstart-arc)