こんにちは、サイオステクノロジー武井です。今回は、KubernetesでApp Serviceを動かすということをしてみたいと思います。
Azure Arcとは?
Azure以外のクラウドやオンプレミスで動作する仮想マシンその他のリソースを統合的に運用監視しましょうというサービスです。AWSで動作する仮想マシンであるEC2を管理する場合はCloud Watchを使いますし、GCPであればCloud Monitoring、AzureであればAzure Monitorといったところになります。マルチクラウドを考えた場合、Cloud Watch、Cloud Monitoring、Azure Monitorの3つのツールを使いこなすのはちょっと大変です。
Azure Arcを使うと、Azure以外(他のクラウドやオンプレミス)のリソースに専用のエージェントを入れることにより、Azure上のリソースとして登録し、Azure側で一括管理できてしまいます。先の例で言えば、AWSのEC2もGCPの仮想マシンも全て、Azure上のリソースとして見えるようになるのでAzure Monitorで管理出来るようになります。
Azure Arc enabled Kubernetes
Azure Arcは、Azure以外のKubernetes(他のクラウドやオンプレミスのKubernetes)をAzureのリソースとして管理することができます。私はAzure Arcの機能の中でこれが最もすごいと思っております。
今回ご紹介するApp ServiceをKubernetesで動かすぞという技術のベースには、このAzure Arc enabled Kubernetesが使われております。これはApp Serviceをコンテナ化(もしくはApp Serviceがそもそもコンテナベースで動いている???)して、Azure Arcによって、Kubernetesリソースとして登録されている別クラウド上のKubernetesにデプロイが可能になる技術です。
これは何がいいかというと、私個人の考えになりますが、クラウドネイティブかつマルチクラウドという相反するテクノロジーが共存出来るのかなと思っております。
例えばAzure FunctionsといったFaaSサービスを使うと、OSやアプリケーションフレームワークといったレイヤーの面倒を見なくてよく、簡単にアプリケーションを構築出来る反面、それはAzureネイティブな技術なので、他のクラウドに移植することが困難になります。つまりAzure Functionsで作ったアプリをマルチクラウドで展開する場合、そのアプリはほぼ作り直しになるのです。AWSでAzure Functionsはもちろん動きませんから、Lambdaあたりで再開発といったところになります。もちろんある程度の部品の流用はできると思いますが。
でも、Azure Arc enabled Kubernetesを使えば、App ServiceというAzureマネージドなクラウドネイティブな機能を他クラウドのKubernetes上で動作させることができ、そして万が一Azureが大規模障害で利用不能のになったとしても、他のクラウドでApp Serviceが動作するということが出来るのです。
ちなみに、この機能はMicrosoft Build2021でプレビューとなり、App Serviceだけではなく、Azure Functions、Logic Apps、Event Gridなどもその対象となります。
早速動かしてみよう!!
ということで、やってみましょう。といっても、すでにその方法は以下URLのMicrosoft Learnに掲載されており、その方法をベースにしております。
https://docs.microsoft.com/ja-jp/learn/modules/configure-application-kubernetes-arc/
Microsoft LearnではAzure Kubernetes Service上にApp Serviceをデプロイする方法が記載されていましたので、それに準拠します。オンプレミスや他のクラウドのKubernetesでも、、、動くのかしら?
ちなみにこの検証に必要なリソースは以下のリソースグループとリージョンに配置することとします。
- リソースグループ:appservicewazurearc
- リージョン:East US
作業は全てAzure Cloud Shellで行います。
事前準備
まずApp ServiceをKubernetes上で動作するためのリソースプロバイダーと機能を有効にします。
$ az feature register --namespace Microsoft.Kubernetes --name previewAccess $ az provider register --namespace Microsoft.Kubernetes --wait $ az feature register --namespace Microsoft.KubernetesConfiguration --name extensions $ az provider register --namespace Microsoft.KubernetesConfiguration --wait $ az feature register --namespace Microsoft.ExtendedLocation --name CustomLocations-ppauto $ az provider register --namespace Microsoft.ExtendedLocation --wait $ az provider register --namespace Microsoft.Web --wait
次のコマンドを実行して、最新のAzure CLI拡張機能をインストールします。
$ az update
次のコマンドを実行して、connectedk8s および customlocation Azure CLI 拡張機能をインストールします。
$ az extension add --upgrade --yes -n connectedk8s
$ az extension add --upgrade --yes -n customlocation
$ az extension remove -n appservice-kube
$ az extension add --yes --source "https://aka.ms/appsvc/appservice_kube-latest-py2.py3-none-any.whl"
az -vコマンドを実行して、以下のモジュールが表示されることを確認します。バージョンは違うかもしれません。
$ az -v connectedk8s 1.1.5 appservice-kube 0.1.20 customlocation 0.1.2
AKSクラスターの作成
AKSクラスターを作成するリソースグループ、クラスター名、リージョンなどを変数に定義します。
$ K8S_CLUSTER_RG_NAME=appservicewazurearc $ K8S_CLUSTER_NAME=k8sAKS-c$RANDOM $ LOCATION=eastus
AKSクラスターを作成します。ちょっと時間かかります。
$ az aks create -g $K8S_CLUSTER_RG_NAME -n $K8S_CLUSTER_NAME --enable-aad --generate-ssh-keys
クラスターから管理者資格情報を取得します。以下のNamespaceが取得できればOKです。
$ kubectl get ns NAME STATUS AGE default Active 3m46s kube-node-lease Active 3m48s kube-public Active 3m48s kube-system Active 3m48s
AKSクラスターをAzure Arcに接続する
Azure Arcのクラスターを作成するリソースグループとクラスター名を変数に定義します。
$ K8S_ARC_PREFIX=k8sArc $ ARC_RG_NAME=appservicewazurearc $ ARC_CLUSTER_NAME="${K8S_ARC_PREFIX}-cluster"
AKSクラスターをAzure Arcに接続します。2分程度かかります。出力結果のprovisioningState プロパティの値が Succeeded となっていることを確認します。
$ az connectedk8s connect -g $ARC_RG_NAME -n $ARC_CLUSTER_NAME
クラスター上に作成された Azure Arc ポッドを一覧表示します。clusterconnect-agent ポッドが含まれていることを確認してください。
$ kubectl get pods -n azure-arc NAME READY STATUS RESTARTS AGE cluster-metadata-operator-7cff574c4f-tzfm4 2/2 Running 0 3m38s clusterconnect-agent-6dfd867c68-xdxrf 3/3 Running 0 3m38s clusteridentityoperator-fd498bf96-r9mjk 2/2 Running 0 3m38s config-agent-658f87845-tznm6 2/2 Running 0 3m38s controller-manager-8676dcdc6-tbnnc 2/2 Running 0 3m38s extension-manager-67b9965fb5-w5sm4 2/2 Running 0 3m38s flux-logs-agent-6596f58c56-tdg52 1/1 Running 0 3m38s kube-aad-proxy-d98bfc858-lcx26 2/2 Running 0 3m38s metrics-agent-5b9b94754f-2pqm5 2/2 Running 0 3m38s resource-sync-agent-f8c7c6b6b-jlm9w 2/2 Running 0 3m38s
Azure Arc上のAKSクラスターでApp Serviceを使えるようにする
AKSクラスターやAzure Arcのリソースグループ名などを変数に定義します。
$ K8S_CLUSTER_RG_NAME=appservicewazurearc $ K8S_CLUSTER_NAME=$(az aks list -g $K8S_CLUSTER_RG_NAME --query "[0].name" -o tsv) $ K8S_ARC_PREFIX=k8sArc $ ARC_RG_NAME=appservicewazurearc $ ARC_CLUSTER_NAME="${K8S_ARC_PREFIX}-cluster"
パブリックIPアドレスのリソースを作成して、その値を変数に格納します。
$ K8S_PIP_NAME=k8sAKS-cluster-pip $ K8S_INFRA_RG_NAME=$(az aks show -g $K8S_CLUSTER_RG_NAME -n $K8S_CLUSTER_NAME --query nodeResourceGroup -o tsv) $ az network public-ip create -g $K8S_INFRA_RG_NAME -n $K8S_PIP_NAME --sku STANDARD $ K8S_PIP=$(az network public-ip show -g $K8S_INFRA_RG_NAME -n $K8S_PIP_NAME --query ipAddress -o tsv)
カスタムロケーションを定義します。カスタムロケーションはAzure Arcで管理されているリソースの場所を定義する仮想的な場所のことです。App ServiceをAzure Arcで管理されたKubernetes上に作成するときに、このカスタムロケーションの指定が必要になります。
$ CUSTOM_LOCATION_NAME="${K8S_ARC_PREFIX}-location"
Azure Arc に接続されたクラスターと、対応する Kubernetes 環境にインストールする拡張機能の名前を指定する変数の値を設定します。
$ EXTENSION_NAME="${K8S_ARC_PREFIX}-kube"
$ KUBE_ENV_NAME="${K8S_ARC_PREFIX}-env-$RANDOM"
App ServiceのPodが作成されるNamespace名を変数に格納します。
$ APP_SERVICE_NAMESPACE_NAME=appservice-ns
App Serviceのアプリケーションログを格納するLog Analyticsを作成します。
$ K8S_INFRA_RG_NAME=$(az aks show -g $K8S_CLUSTER_RG_NAME -n $K8S_CLUSTER_NAME --query nodeResourceGroup -o tsv)
$ LA_WORKSPACE_NAME=k8sAKS-workspace
$ az monitor log-analytics workspace create -g $K8S_INFRA_RG_NAME -n $LA_WORKSPACE_NAME
Log Analyticsの色々な設定情報を変数に格納します。
LA_WORKSPACE_NAME=k8sAKS-workspace LA_WORKSPACE_ID=$(az monitor log-analytics workspace show --resource-group $K8S_INFRA_RG_NAME --workspace-name $LA_WORKSPACE_NAME --query "customerId" -o tsv) LA_WORKSPACE_ID_ENC=$(printf %s $LA_WORKSPACE_ID | base64) LA_WORKSPACE_KEY=$(az monitor log-analytics workspace get-shared-keys --resource-group $K8S_INFRA_RG_NAME --workspace-name $LA_WORKSPACE_NAME --query "secondarySharedKey" -o tsv) LA_WORKSPACE_KEY_ENC_WITH_SPACE=$(printf %s $LA_WORKSPACE_KEY | base64) LA_WORKSPACE_KEY_ENC=$(echo -n "${LA_WORKSPACE_KEY_ENC_WITH_SPACE//[[:space:]]/}")
App Service拡張機能をインストールします。
$ az k8s-extension create -g $ARC_RG_NAME --name $EXTENSION_NAME --cluster-type connectedClusters -c $ARC_CLUSTER_NAME --extension-type 'Microsoft.Web.Appservice' --release-train stable --auto-upgrade-minor-version true --scope cluster --release-namespace $APP_SERVICE_NAMESPACE_NAME --configuration-settings "Microsoft.CustomLocation.ServiceAccount=default" --configuration-settings "appsNamespace=${APP_SERVICE_NAMESPACE_NAME}" --configuration-settings "clusterName=${KUBE_ENV_NAME}" --configuration-settings "loadBalancerIp=${K8S_PIP}" --configuration-settings "buildService.storageClassName=default" --configuration-settings "buildService.storageAccessMode=ReadWriteOnce" --configuration-settings "envoy.annotations.service.beta.kubernetes.io/azure-load-balancer-resource-group=${K8S_CLUSTER_RG_NAME}" --configuration-settings "customConfigMap=${APP_SERVICE_NAMESPACE_NAME}/kube-environment-config" --configuration-settings "logProcessor.appLogs.destination=log-analytics" --configuration-protected-settings "logProcessor.appLogs.logAnalyticsConfig.customerId=${LA_WORKSPACE_ID_ENC}" --configuration-protected-settings "logProcessor.appLogs.logAnalyticsConfig.sharedKey=${LA_WORKSPACE_KEY_ENC}"
正常にインストールされたかどうかを確認します。以下のコマンドを実行して、installState プロパティの値が Installedに変わることを確認します。変わるまで何度も実行してください。ちょっと時間かかります。
$ az k8s-extension show --cluster-type connectedClusters -c $ARC_CLUSTER_NAME -g $ARC_RG_NAME --name $EXTENSION_NAME
拡張機能のIDを変数に格納します。
$ EXTENSION_ID=$(az k8s-extension show --cluster-type connectedClusters -c $ARC_CLUSTER_NAME -g $ARC_RG_NAME --name $EXTENSION_NAME --query id -o tsv)
Azure Arc上で動作するKubernetesクラスターにカスタムの場所を作成します。これを行うことにより、App Serviceの作成場所として、このカスタムの場所を指定すると、Azure Arc上で動作するKubernetes上にApp Serviceが作成されます。
接続されているクラスターの id プロパティの値を変数に格納します。
$ CONNECTED_CLUSTER_ID=$(az connectedk8s show -n $ARC_CLUSTER_NAME -g $ARC_RG_NAME --query id -o tsv)
カスタムの場所を作成します。
$ az customlocation create -g $ARC_RG_NAME -n $CUSTOM_LOCATION_NAME --host-resource-id $CONNECTED_CLUSTER_ID --namespace $APP_SERVICE_NAMESPACE_NAME -c $EXTENSION_ID
カスタムの場所のIDを変数に格納します。
$ CUSTOM_LOCATION_ID=$(az customlocation show -g $ARC_RG_NAME -n $CUSTOM_LOCATION_NAME --query id -o tsv)
App Service Kubernetes 環境を作成します。
$ az appservice kube create -g $ARC_RG_NAME -n $KUBE_ENV_NAME --custom-location $CUSTOM_LOCATION_ID --static-ip $K8S_PIP
ちゃんとできているかどうかを以下のコマンドで確認します。ちょっと時間かかるので、provisioningState プロパティの値が Succeeded に変わるまでコマンドを何度も再実行します。
$ az appservice kube show -g $ARC_RG_NAME -n $KUBE_ENV_NAME
Azure Arc上のAKSクラスターでApp Serviceをデプロイする
App Service名を変数に格納します。
$ WEBAPP_NAME=k8sarcwebapp$RANDOM$RANDOM
App Serviceを作成します。このとき先程作成したカスタムの場所を–custom-locationの値として指定します。これが重要です。
$ az webapp create -g $ARC_RG_NAME -n $WEBAPP_NAME --custom-location $CUSTOM_LOCATION_ID --runtime "PHP|7.4"
以下のPHPファイルを作成します。
<?php echo 'hoge'; ?>
先のPHPファイルを含むZIPアーカイブを作成します。
$ zip -r app.zip .
App Serviceにデプロイします。
$ az webapp deployment source config-zip -g $ARC_RG_NAME -n $WEBAPP_NAME --src app.zip
しばらくしてApp Serivceのリソースの「概要」ブレードに表示される[URL]を確認して、「[URL]/test.php」にアクセスすると、ブラウザ上に「hoge」と表示されると思います。
AKS上にデプロイしたApp Serviceがちゃんと動きましたね!!ゴイスー。
Podを見てみましょう。一番下の「k8sarcwebapp264457290-7f95d7bf9d-cv2kq」っていう名前のPodがApp Serivceが稼働するPodです。
$ kubectl get pods -n appservice-ns NAME READY STATUS RESTARTS AGE k8sarc-kube-k8se-activator-75c9599557-8sls7 1/1 Running 0 18m k8sarc-kube-k8se-app-controller-7b5944fd8c-hnhn9 1/1 Running 0 18m k8sarc-kube-k8se-build-service-866454fd66-llxq6 1/1 Running 0 25m k8sarc-kube-k8se-envoy-7687cb74bd-66vw5 1/1 Running 0 25m k8sarc-kube-k8se-envoy-7687cb74bd-ft9sb 1/1 Running 0 25m k8sarc-kube-k8se-envoy-7687cb74bd-hbr49 1/1 Running 0 25m k8sarc-kube-k8se-https-scaler-86cf76cc65-hhgtp 1/1 Running 0 25m k8sarc-kube-k8se-img-cacher-dlbsk 1/1 Running 0 25m k8sarc-kube-k8se-img-cacher-v6dn4 1/1 Running 0 25m k8sarc-kube-k8se-img-cacher-vsvqt 1/1 Running 0 25m k8sarc-kube-k8se-log-processor-6jhrb 1/1 Running 3 25m k8sarc-kube-k8se-log-processor-jsm9f 1/1 Running 3 25m k8sarc-kube-k8se-log-processor-vnw6r 1/1 Running 1 25m k8sarcwebapp264457290-7f95d7bf9d-cv2kq 1/1 Running 0 68s
さっきのPodに入ってみましょう。
$ kubectl exec -it k8sarcwebapp264457290-7f95d7bf9d-cv2kq /bin/bash -n appservice-ns kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. Defaulted container "https" out of: https, app-init (init) # cat /home/site/wwwroot/test.php <?php echo 'hoge'; ?>
確かにtest.phpをデプロイしたApp SerivceのPodですね!!
ここでAzureポータルのApp Serivceの画面からスケールアウトしてみましょう。「最大インスタンス数」を2にしてみます。
Podの数を確認してみるとたしかに2つに増えてます!!「k8sarcwebapp・・・」っていう名称のPodが2つありますよね!!スケールアウトされました。
$ kubectl get pods -n appservice-ns NAME READY STATUS RESTARTS AGE k8sarc-kube-k8se-activator-75c9599557-8sls7 1/1 Running 0 5h35m k8sarc-kube-k8se-app-controller-7b5944fd8c-hnhn9 1/1 Running 0 5h35m k8sarc-kube-k8se-build-service-866454fd66-llxq6 1/1 Running 0 5h43m k8sarc-kube-k8se-envoy-7687cb74bd-66vw5 1/1 Running 0 5h43m k8sarc-kube-k8se-envoy-7687cb74bd-ft9sb 1/1 Running 0 5h43m k8sarc-kube-k8se-envoy-7687cb74bd-hbr49 1/1 Running 0 5h43m k8sarc-kube-k8se-https-scaler-86cf76cc65-hhgtp 1/1 Running 0 5h43m k8sarc-kube-k8se-img-cacher-dlbsk 1/1 Running 0 5h43m k8sarc-kube-k8se-img-cacher-v6dn4 1/1 Running 0 5h43m k8sarc-kube-k8se-img-cacher-vsvqt 1/1 Running 0 5h43m k8sarc-kube-k8se-log-processor-6jhrb 1/1 Running 3 5h43m k8sarc-kube-k8se-log-processor-jsm9f 1/1 Running 3 5h43m k8sarc-kube-k8se-log-processor-vnw6r 1/1 Running 1 5h43m k8sarcwebapp264457290-7f95d7bf9d-6hz8c 1/1 Running 0 5h8m k8sarcwebapp264457290-7f95d7bf9d-cv2kq 1/1 Running 0 5h18m
まとめ
Kubernetes上でApp Serivceが動きましたね!!なんかとっても未来を感じます。ドラえもんはすぐそこまで来ているって感じです。