APC 技術ブログ

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

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

Bicepからhelm installを実行する

はじめに

2023年3月にBicepのPublic Registryをご紹介させていただきました。

techblog.ap-com.co.jp

あらためてPublic Registryを覗いてみると、aks-run-helmaks-run-commandというテンプレートがあることに気づきました。

AKSのプロビジョニングしたあと、その延長でingress-nginxやcert-managerといった基本的なミドルウェアを導入したいというケースもあるかと思います。 通常のHelmコマンドを実行して導入するとAKSのプロビジョニングと分けて実行しなければならないためちょっと不便です。こうしたときにBicepからHelmコマンドが実行でいれば一連の作業でできるようになるので便利です。

今回は実際に ingress-nginx をインストールしてみましたので、そのやり方をご紹介します。

ingress-nginxのインストール

aks-run-helm を試してみる

さっそくaks-run-helmを試してみましょう。READMEに書かれている内容を参考に以下のように指定してみました。

param name string
param location string = resourceGroup().location

param clusterName string
param chartVersion string = '4.9.0'
param namespace string = 'ingress-system'
param autoScaling bool = true
param minReplicas int = 1
param maxReplicas int = 3

var helmValueTemplate = '''
--version {0}
--namespace {1} --create-namespace
--set controller.autoscaling.enabled={2}
--set controller.autoscaling.minReplicas={3}
--set controller.autoscaling.maxReplicas={4}
'''
var helmParams = replace(
  format(helmValueTemplate, chartVersion, namespace, autoScaling, minReplicas, maxReplicas),
  '\n', ' '
)

module installIngress 'br/public:deployment-scripts/aks-run-helm:2.0.3' = {
  name: 'mw-ingress-${name}'
  params: {
    aksName: clusterName
    location: location
    helmRepo: 'ingress-nginx'
    helmRepoURL: 'https://kubernetes.github.io/ingress-nginx'
    helmApps: [
      {
        helmApp: 'ingress-nginx/ingress-nginx'
        helmAppName: 'ingress-nginx'
        helmAppParams: helmParams
      }
    ]
  }
}

実行結果は・・・ az deployment group create ... コマンド自体は正常に見えましたが、実際にインストールはされていませんでした。

デバッグする

Public registry内のコードを参照していくと、このテンプレートはaks内の aks-command namespaceでJobを実行しているようです。 そこで 実行結果を kubectl logs -n aks-command <job-pod-name> コマンドで確認するとどうやら権限がなく異常終了しているようです。 (参考ですが、実際どんな内容でコマンド実行しているかは yaml の内容を表示するとわかります)

aks-run-helmは内部でaks-run-commandを実行していますが、aks-run-commandはデフォルトでContributorとKuberentes RBAC Reader権限が設定されています。Helmで実行する内容によってはこれでは不十分なようです。aks-run-command側ではこの権限を変更できるようなインターフェースになっていますが、aks-run-helmのほうはその権限を追加していできるようにはなっていません。 aks-run-commandを見ると【こうやって指定してね】という例が載っているのに、aks-run-helm側はそれに沿っていない。そこでここではGitHubからaks-run-helmのbicepファイルを入手して権限を指定できるように変更したいと思います。

カスタマイズしたaks-run-helm

customized-aks-run-helm.bicep

/// this script is copied from https://github.com/Azure/bicep-registry-modules/blob/main/modules/deployment-scripts/aks-run-helm/main.bicep

metadata name = 'AKS Run Helm Script'
metadata description = 'An Azure CLI Deployment Script that allows you to run a Helm command at a Kubernetes cluster.'
metadata owner = 'dciborow'

@description('The name of the Azure Kubernetes Service')
param aksName string

@description('The location to deploy the resources to')
param location string = resourceGroup().location

@description('How the deployment script should be forced to execute')
param forceUpdateTag string = utcNow()

@description('Does the Managed Identity already exists, or should be created')
param useExistingManagedIdentity bool = false

@description('Name of the Managed Identity resource')
param managedIdentityName string = 'id-AksRunCommandProxy'

@description('For an existing Managed Identity, the Subscription Id it is located in')
param existingManagedIdentitySubId string = subscription().subscriptionId

@description('For an existing Managed Identity, the Resource Group it is located in')
param existingManagedIdentityResourceGroupName string = resourceGroup().name

@description('Public Helm Repo Name')
param helmRepo string = 'azure-marketplace'

@description('Public Helm Repo URL')
param helmRepoURL string = 'https://marketplace.azurecr.io/helm/v1/repo'

@description('Helm Apps {helmApp: \'azure-marketplace/wordpress\', helmAppName: \'my-wordpress\'}')
param helmApps array = []

@allowed([
  'OnSuccess'
  'OnExpiration'
  'Always'
])
@description('When the script resource is cleaned up')
param cleanupPreference string = 'OnSuccess'
@description('An array of Azure RoleIds that are required for the DeploymentScript resource')
param rbacRolesNeeded array = [
  'b24988ac-6180-42a0-ab88-20f7382dd24c' //Contributor
  'a7ffa36f-339b-4b5c-8bdf-e2c188b2c0eb' // Azure Kubernetes Service RBAC Writer
]

module helmAppInstalls 'br/public:deployment-scripts/aks-run-command:2.0.2' = [for (app, i) in helmApps: {
  name: 'helmInstall-${app.helmAppName}-${i}'
  params: {
    aksName: aksName
    location: location
    commands: [
      'helm repo add ${helmRepo} ${helmRepoURL} && helm repo update && helm upgrade --install ${app.helmAppName} ${app.helmApp} ${contains(app, 'helmAppParams') ? app.helmAppParams : ''}'
    ]
    forceUpdateTag: forceUpdateTag
    newOrExistingManagedIdentity: useExistingManagedIdentity ? 'existing' : 'new'
    managedIdentityName: managedIdentityName
    existingManagedIdentitySubId: existingManagedIdentitySubId
    existingManagedIdentityResourceGroupName: existingManagedIdentityResourceGroupName
    cleanupPreference: cleanupPreference
    rbacRolesNeeded: rbacRolesNeeded
  }
}]

@description('Helm Command Output Values')
output helmOutputs array = [for (app, i) in helmApps: {
  appName: app.helmAppName
  outputs: helmAppInstalls[i].outputs.commandOutput
}]

オリジナルのaks-run-helmが利用しているaks-run-commandは少し古いバージョン(1.0.1)だったので、そこもカスタマイズに合わせて新しくしています。

これを呼び出すように変更したところ、、まだ権限が足りない。ということで呼び出し側で以下のように変更しました。 さきほど紹介したBicepファイルで必要な権限を追加します。

@description('An array of Azure RoleIds that are required for the DeploymentScript resource')
param rbacRolesNeeded array = [
  'b24988ac-6180-42a0-ab88-20f7382dd24c' //Contributor
  'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b' // Azure Kubernetes Service RBAC Cluster Administrator
]

module installIngress './customized-aks-run-helm.bicep' = {       // 呼び出しモジュールをカスタマイズしたものに変更
  name: 'mw-ingress-${name}'
  params: {
    aksName: clusterName
    location: location
    helmRepo: 'ingress-nginx'
    helmRepoURL: 'https://kubernetes.github.io/ingress-nginx'
    rbacRolesNeeded: rbacRolesNeeded                                           // ここの指定を追加
    helmApps: [
      {
        helmApp: 'ingress-nginx/ingress-nginx'
        helmAppName: 'ingress-nginx'
        helmAppParams: helmParams
      }
    ]
  }
}

これを実行すると、無事 ingress-nginxがインストールできるようになりました。

これで、AKSのプロビジョニング、Helm Chartを使ったミドルウェアのインストールまでをまとめて実行できるようになります。 便利ですね。

さらに、aks-run-command はhelmだけではなく、kubectlコマンドも実行できますので、使い方によっていろいろなシーンで利用できそうです。

まとめ

Bicep public registryはこういうの毎回書くの面倒だよねといったテンプレートがいくつも用意されていますし、中身をみると「あ、こういう使い方できるんだ」といいうことを知るきっかけにもなります。折をみてどういったものがあるか確認するとよいのではないでしょうか。

【おまけ】

せっかく更新したこともあるので、時間があれば本家のPublic registry側にPull Requestを出してみようかなと考えています。 もしかすると将来上記のカスタマイズ版を使用せずにインストールできるようになるかもしれません。