APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

KubernetesでIaC、Azure Service Operatorの紹介

はじめに

こんにちは、ACS事業部の吉川です。
皆さんはIaC(Infrastructure as Code)にどんなツールを使っていますか?

今回のブログでは、AzureのリソースをKubernetesのカスタムリソースとして管理できる Azure Service Operator をご紹介します。

Azure Service Operator とは

以前にもKubernetesからAzureリソースをコントロールする仕組みとして Open Service Broker for Azure(OSBA) というものがありました。

github.com

OSBAはCloud Foundry由来のOpen Serice Broker APIの仕様に則った仕組みでしたが、現在は開発が終了しています。
OSBAに代わるKubernetes上のAzureリソースコントローラーとして、KubernetesのOperatorの形で実装されたのが Azure Service Operator(ASO) です。

github.com

ASOをAzure Kubernetes Service(AKS)に導入し、Azureリソースを作成してみましょう。

試した環境

  • Azure Kubernetes Service: v1.22.6
  • Azure Service Operator: v2.0.0-beta.1

ASOはバージョン1系と2系の2種類が存在していますが、

⚠️ We strongly recommend new users consider ASO v2 instead of ASO v1

とのことですのでバージョン2系を導入しました。
まだベータバージョンですので、プロダクション環境での導入には十分注意しましょう。

ASOの導入

公式サイトにインストール手順が公開されていますのでそちらに沿って進めます。

azure.github.io

1. cert-managerのインストール

cert-managerをインストールします。

kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.8.2/cert-manager.yaml

cert-manager 名前空間配下のPodがすべて起動していることを確認します。

$ kubectl get pod -n cert-manager
NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-66b646d76-6pzgj               1/1     Running   0          2m5s
cert-manager-cainjector-59dc9659c7-4p8qp   1/1     Running   0          2m5s
cert-manager-webhook-7d8f555998-4mqxs      1/1     Running   0          2m5s

2. ASO用サービスプリンシパルの作成

続いて、ASOがAzureリソースを作成する際に利用するサービスプリンシパルを作成します。
今回はサービスプリンシパルに サブスクリプションのContributor(共同作成者) のロールを割り当てます。

まずはサブスクリプションのIDを確認します。次の工程でテナントIDも利用するので合わせて確認しておきましょう。

サブスクリプションのIDは以下コマンドで取得できます。

AZURE_SUBSCRIPTION_ID=$(az account show -o tsv --query id)

同様に、テナントIDは以下のとおり。

AZURE_TENANT_ID=$(az account show -o tsv --query tenantId)

以下のコマンドで azure-service-operator という名前のサービスプリンシパルを作成します。作成と同時にロールの割り当ても行っています。

az ad sp create-for-rbac -n azure-service-operator --role contributor \
    --scopes /subscriptions/$AZURE_SUBSCRIPTION_ID

作成時に表示される appIdpassword は次の工程で使用します。
以下のように変数に格納しておきましょう。

AZURE_CLIENT_ID=<appIdの値>
AZURE_CLIENT_SECRET=<passwordの値>

3. ASOのインストール

ASOのインストールにはHelmを利用します。
まずはリポジトリを追加します。

helm repo add aso2 https://raw.githubusercontent.com/Azure/azure-service-operator/main/v2/charts

前項で作成したサービスプリンシパルの情報を使用しインストールします。

helm upgrade --install --devel aso2 aso2/azure-service-operator \
     --create-namespace \
     --namespace=azureserviceoperator-system \
     --set azureSubscriptionID=$AZURE_SUBSCRIPTION_ID \
     --set azureTenantID=$AZURE_TENANT_ID \
     --set azureClientID=$AZURE_CLIENT_ID \
     --set azureClientSecret=$AZURE_CLIENT_SECRET

と、ここでエラーが発生しました。

Error: rendered manifests contain a resource that already exists. 
Unable to continue with install: CustomResourceDefinition "batchaccounts.batch.azure.com" in namespace "" exists and cannot be imported into the current release: 
invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; 
annotation validation error: missing key "meta.helm.sh/release-name": must be set to "aso2"; 
annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "azureserviceoperator-system"

Helmでデプロイされた CustomResourceDefinition(CRD) に、ラベルやアノテーションが正常に入っていないことが問題のようです。
どうしたものかと思っていると、GitHub の Releaseページに対処方法が記載されていました。

以下のスクリプトを作成し、

#!/bin/bash
HELM_RELEASE=aso2
HELM_RELEASE_NAMESPACE=azureserviceoperator-system

set -euo pipefail

echo "Annotating ASO CRDs with release-name=${HELM_RELEASE}, release-namespace=${HELM_RELEASE_NAMESPACE}"

for CRD in $(kubectl get crds -o='custom-columns=Name:.metadata.name' | grep azure.com)
do
    kubectl label crd ${CRD} app.kubernetes.io/managed-by=Helm --overwrite
    kubectl annotate crd ${CRD} meta.helm.sh/release-name=${HELM_RELEASE} --overwrite
    kubectl annotate crd ${CRD} meta.helm.sh/release-namespace=${HELM_RELEASE_NAMESPACE} --overwrite
done

実行することで各CRDリソースのラベルとアノテーションが修正されます。

chmod 700 fix-crds.sh
./fix-crds.sh
Annotating ASO CRDs with release-name=aso2, release-namespace=azureserviceoperator-system
customresourcedefinition.apiextensions.k8s.io/batchaccounts.batch.azure.com not labeled
customresourcedefinition.apiextensions.k8s.io/batchaccounts.batch.azure.com annotated
customresourcedefinition.apiextensions.k8s.io/batchaccounts.batch.azure.com annotated
customresourcedefinition.apiextensions.k8s.io/components.insights.azure.com not labeled
customresourcedefinition.apiextensions.k8s.io/components.insights.azure.com annotated
customresourcedefinition.apiextensions.k8s.io/components.insights.azure.com annotated
customresourcedefinition.apiextensions.k8s.io/configurations.dbformariadb.azure.com not labeled
~以下略~

スクリプトの実行が完了したら、もう一度Helmコマンドを実行します。

helm upgrade --install --devel aso2 aso2/azure-service-operator \
     --create-namespace \
     --namespace=azureserviceoperator-system \
     --set azureSubscriptionID=$AZURE_SUBSCRIPTION_ID \
     --set azureTenantID=$AZURE_TENANT_ID \
     --set azureClientID=$AZURE_CLIENT_ID \
     --set azureClientSecret=$AZURE_CLIENT_SECRET

今後はちゃんと成功しました。

NAME: aso2
LAST DEPLOYED: Wed Jul  6 21:23:45 2022
NAMESPACE: azureserviceoperator-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

OperatorのPodが起動していることも確認しましょう。

$ kubectl get pod -n azureserviceoperator-system
NAME                                                       READY   STATUS    RESTARTS   AGE
azureserviceoperator-controller-manager-79b6dbd658-nb67b   2/2     Running   0          2m16s

これでASOを使う準備は完了です。

ASOを使ったAzureリソースのデプロイ

ここからは実際にAzureリソースをASOから作成していきます。
GitHubにASOのサンプル用リポジトリがあります。

github.com

その中から、Azure PostgreSQL Votes Demo App を、一部内容を変更してデプロイします。

Azureリソースを作成するマニフェストは以下のとおりです。

---
apiVersion: resources.azure.com/v1beta20200601
kind: ResourceGroup
metadata:
  name: rg-aso-sample
  namespace: default
spec:
  location: japaneast
---
apiVersion: dbforpostgresql.azure.com/v1beta20210601
kind: FlexibleServer
metadata:
  name: asosamplepostgresql
  namespace: default
spec:
  location: japaneast
  owner:
    name: rg-aso-sample
  version: "13"
  sku:
    name: Standard_B1ms
    tier: Burstable
  administratorLogin: myAdmin
  administratorLoginPassword:
    name: server-admin-pw       # Secretの名前
    key: PASSWORD               # Secret内のKey
  storage:
    storageSizeGB: 32
---
apiVersion: dbforpostgresql.azure.com/v1beta20210601
kind: FlexibleServersDatabase
metadata:
  name: sampledb
  namespace: default
spec:
  owner:
    name: asosamplepostgresql
  charset: utf8
---
apiVersion: dbforpostgresql.azure.com/v1beta20210601
kind: FlexibleServersFirewallRule
metadata:
  name: samplefirewallrule
  namespace: default
spec:
  owner:
    name: asosamplepostgresql
  startIpAddress: 0.0.0.0
  endIpAddress: 255.255.255.255
---
apiVersion: v1
kind: Secret
metadata:
  name: server-admin-pw
  namespace: default
stringData:
  PASSWORD: <DBに設定するパスワード>

以下のAzureリソースを作成します。

  • リソースグループ
  • Azure Database for PostgreSQL - Flexible Server
    • PostgreSQLのデータベース(sampledb)
    • ファイアウォール設定

また、ユーザーのパスワードを格納するため、KubernetesのSecretも合わせて作成します。

AKSにデプロイします。

$ kubectl apply -f postgresql.yaml
resourcegroup.resources.azure.com/rg-aso-sample created
flexibleserver.dbforpostgresql.azure.com/asosamplepostgresql created
flexibleserversdatabase.dbforpostgresql.azure.com/sampledb created
flexibleserversfirewallrule.dbforpostgresql.azure.com/samplefirewallrule created
secret/server-admin-pw created

少し時間を置いてからAzureポータルを確認すると、以下のようにリソースグループとPostgreSQLが作成されていることが確認できます。

また、kubectlからもリソースを確認できます。

$ kubectl get resourcegroup.resources.azure.com/rg-aso-sample
NAME            READY   REASON      MESSAGE
rg-aso-sample   True    Succeeded
$ kubectl get flexibleserver.dbforpostgresql.azure.com
NAME                  READY   SEVERITY   REASON      MESSAGE
asosamplepostgresql   True               Succeeded

PostgreSQLの作成が完了したら、次はデータベースを利用するアプリケーションをデプロイします。 マニフェストは以下のとおりです。

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: azure-votes-postgresql-deployment
  namespace: default
spec:
  selector:
    matchLabels:
      app: azure-votes-postgresql
  replicas: 1
  template:
    metadata:
      name: postgresql-demo
      labels:
        app: azure-votes-postgresql
    spec:
      containers:
        - name: azure-votes-postgresql
          image: mcr.microsoft.com/k8s/asodemos/postgresqlvotes:latest
          ports:
            - containerPort: 8080
          env:
            - name: USERNAME
              value: myAdmin
            - name: PASSWORD
              valueFrom:
                secretKeyRef:
                  name: server-admin-pw
                  key: PASSWORD
            - name: SERVER
              value: asosamplepostgresql.postgres.database.azure.com
            - name: DATABASE
              value: sampledb
            - name: PORT
              value: "5432"
---
apiVersion: v1
kind: Service
metadata:
  name: azure-votes-svc
  namespace: default
spec:
  selector:
    app: azure-votes-postgresql
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: LoadBalancer
$ kubectl apply -f asosampleapp-deployment.yaml
deployment.apps/azure-votes-postgresql-deployment created
service/azure-votes-svc created

デプロイが完了したらブラウザからLoadBalancerサービスのIPアドレスにアクセスしてみましょう。 dogs か cats のボタンをクリックするとそれぞれカウントアップされ、クリック結果がデータベースに記録されるというサンプルアプリが起動しています。

このように、ASOを利用することで アプリケーションのPodとアプリケーションが利用するAzureリソースをKubernetesで一括デプロイできる ようになります。

Reconciliation Loop

先に述べたように、ASOはKubernetesのOperatorとして実装されています。 これにより、Kubernetesの Reconcliation Loop (リソースが宣言したとおりの状態であることを継続して確認・修正する) という特徴が、Azureリソースに対しても適用されます。

下の画面は前項でデプロイしたPostgreSQLのファイアウォール設定画面です。
赤枠部にあるように、 マニフェストで定義したファイアウォール定義 が設定されています。

これをポータルから削除してみましょう。

削除によって一時的に設定が消えるのですが、しばらくするとASOにより再度ファイアウォール設定が追加されます。
アクティビティの履歴を見ると以下のようになっています。

このように、宣言した状態を維持してくれる という点は、他のIaCツールに比べて便利なポイントだと思います。

この特徴から、Azureリソースを削除したくなったときにポータルから削除しても、ASOが再度リソースを作成してしまいます。
ASOで作成したリソースはASOで削除する 必要があることに注意しましょう。

$ kubectl delete -f postgresql.yaml
resourcegroup.resources.azure.com "rg-aso-sample" deleted
flexibleserver.dbforpostgresql.azure.com "asosamplepostgresql" deleted
flexibleserversdatabase.dbforpostgresql.azure.com "sampledb" deleted
flexibleserversfirewallrule.dbforpostgresql.azure.com "samplefirewallrule" deleted
secret "server-admin-pw" deleted

上記のようにAKS上でリソースを削除することで、Azure上のリソースも削除されます。

おわりに

AzureリソースをKubernetesのリソースのように扱える Azure Service Operator、いかがでしたでしょうか。
アプリケーションとAzureリソースをまとめて管理できるという点は、TerraformやBicepなどの他のIaCツールにはない特徴だと思います。
まだまだ対応しているAzureリソースの数は多くないですが、データベースやネットワーク周りなど基本的な部分は揃っている印象です。

azure.github.io

まだベータのステータスですので、今後の発展が楽しみですね。

私達はAzure・AKSを活用した内製化のご支援をしております。ご相談等ありましたらぜひご連絡ください。

www.ap-com.co.jp

本記事の投稿者: 吉川 俊甫
AKSをメインにインフラ系のご支援を担当しています。趣味は資格取得です。
Shunsuke Yoshikawa - Credly