APC 技術ブログ

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

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

BicepでKubernetesリソースを作成する

Bicep ユーザーの皆様こんにちは。

皆さんBicepでKubernetesリソースの作成をできるのをご存知ですか?AKSの作成ではありません。kubectl apply相当のことができるのです。

2023年4月現在まだプレビューの機能ですが、こちらをご紹介したいと思います。ちなみにMicrosoftのドキュメントはこちらです。

learn.microsoft.com

プレビュー機能を有効にする

まだプレビュー機能ということで、プレビューの拡張機能を使うよ という宣言をしなければなりません。bicepconfig.jsonでその宣言を行います。lintの指定を行っている方はすでにファイルは存在していると思いますのでそちらに追加してください。それ以外の方はローカルフォルダ、またはその上位のフォルダのどこかにbicepconfig.jsonというファイルを作成してください。

{
  "experimentalFeaturesEnabled": {
    "extensibility": true
  }
}

YamlからBicepへの変換

VSCodeのbicep extensionでKuberentes manifestをBicepファイルに変換する機能が備わっています。 コマンドパレットを開き bicep と入力すると、候補の中に Import Kubernetes Manifest (EXPERIMENTAL)` というものがあります。KubernetesのYamlファイルを選択しこちらを実行すると、bicepファイルに変換してくれます。

例えば つぎのようなServiceAccount作成のものを指定した場合

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    azure.workload.identity/client-id: ${APP_CLIENT_ID}
  labels:
    azure.workload.identity/use: "true"
    app: app
  name: ${APP_SA}
  namespace: ${APP_NAMESPACE}

Importを実行すると

@secure()
param kubeConfig string

import 'kubernetes@1.0.0' with {
  namespace: 'default'
  kubeConfig: kubeConfig
}

resource coreServiceAccount_APP_SA 'core/ServiceAccount@v1' = {
  metadata: {
    annotations: {
      'azure.workload.identity/client-id': '\${APP_CLIENT_ID}'
    }
    labels: {
      'azure.workload.identity/use': 'true'
      app: 'app'
    }
    name: '\${APP_SA}'
    namespace: '\${APP_NAMESPACE}'
  }
}

と変換されます。このbicepファイルをあとは普通に利用するだけ。例えばnamespaceも一緒に作成するのであれば以下のようなものを作ればよいことになります(namespaceのyamlからimport実施済みの想定)

@secure()
param kubeConfig string
param clientId string
param namespace string
param serviceAccountName string
param labels object = {}

import 'kubernetes@1.0.0' with {
  namespace: 'default'
  kubeConfig: kubeConfig
}

resource coreNamespace_NAMESPACE 'core/Namespace@v1' = {
  metadata: {
    name: namespace
  }
}

var actualLabels = union(labels, { 'azure.workload.identity/use': 'true' })
resource coreServiceAccount_SA 'core/ServiceAccount@v1' = {
  metadata: {
    annotations: {
      'azure.workload.identity/client-id': applicationId
    }
    labels: actualLabels
    name: serviceAccountName
    namespace: namespace
  }
}

KubernetesConfigって・・・

上記で作成したBicepファイルで

import 'kubernetes@1.0.0' with {
  namespace: 'default'
  kubeConfig: kubeConfig
}

という部分があったと思います。これが今回の機能の肝で、Kubernetesプロバイダーというものになります。 Microsoftのドキュメントを見ると、ここのnamespaceはプロバイダーの名前空間、kubeConfigは Kubernetesクラスター管理者資格情報のbase64でエンコードされた値を指定することになっています。

kubeConfigはつぎのように渡すとよいそうです(Microsoftドキュメントより)

resource aks 'Microsoft.ContainerService/managedClusters@2022-05-02-preview' existing = {
  name: 'demoAKSCluster'
}

module kubernetes './kubernetes.bicep' = {
  name: 'buildbicep-deploy'
  params: {
    kubeConfig: aks.listClusterAdminCredential().kubeconfigs[0].value
  }
}

なにが嬉しいか

AKSへのデプロイはkubectlでやればいいじゃないか?とも思いますが、次のようなケースで便利です。 例えば、Workload identityを利用する場合、AzureでユーザーマネージドIDを作成し、それとAKS内のServiceAccountを紐付けるということを行います。ServiceAccountにはユーザーマネージドIDのClientIDを指定する必要がありますが、すべてをBicepで実行できれば次のように一連の作業で登録することが可能になります。

すべてのAKSリソースをBicepで作成する必要はないと思いますが、今回のようにAzureのリソースを作成し、その内容をベースにYamlの設定に反映してリソース作成するといったケースではこうしたオプションがあると便利です。

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

param giteaIdentityName string = 'app-${aksClusterName}'
param federetedCredentialName string = appIdentityName

param aksClusterName string = '${name}-aks'
param k8sNamespace string = 'app'
param k8sServiceAccount string = 'app-sa'

param keyvaultName string = '${name}-kv'

// ユーザーマネージドID作成

module userIdentity './user-managed-id.bicep' = {
  name: 'app-id-assign-${appIdentityName}'
  params: {
    name: giteaIdentityName
    location: location
    tags: tags
  }
}

resource aks 'Microsoft.ContainerService/managedClusters@2023-02-02-preview' existing = {
  name: aksClusterName
}


// Federated Credentialの作成

module federatedCredential './user-id-federeted-credential.bicep' = {
  name: 'app-id-federation-${federetedCredentialName}'
  params: {
    federationName: federetedCredentialName
    issuerUrl: aks.properties.oidcIssuerProfile.issuerURL
    subject: 'system:serviceaccount:${k8sNamespace}:${k8sServiceAccount}'
    userIdentityName: userIdentity.outputs.idName
  }

}

// assigned keyvault access control
module assignKvAcceccPolicy './kv-access-policies.bicep' = {
  name: 'app-${name}-policy-${keyvaultName}'
  params: {
    kvName: keyvaultName
    principalId: userIdentity.outputs.principalId
    keys: [ 'get' ]
    secrets: [ 'get' ]
    certificates: [ 'get' ]
  }
}

module kubernetes './k8s-service-account.bicep' = {
  name: 'app-id-${aksClusterName}-resource'
  params: {
    clientId: userIdentity.outputs.clientId
    kubeConfig: aks.listClusterAdminCredential().kubeconfigs[0].value
    namespace: k8sNamespace
    serviceAccountName: k8sServiceAccount
  }
}

まだベータ版なので今後変更されるかもしれませんが、オプションが広がるのはよいことなのでGAになることを期待しましょう。

ACS事業部のご紹介

私たちACS事業部はAzure・AKSなどのクラウドネイティブ技術を活用した内製化のご支援をしております。ぜひお声がけください。

www.ap-com.co.jp

また、一緒に働いていただける仲間も募集中です!
今年もまだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。

www.ap-com.co.jp