APC 技術ブログ

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

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

Private RegistryでBicepモジュールの共有化を促進

みなさん、暑い中いかがお過ごしですか?ACS事業部亀崎です。 今回はIaCの共通化のお話です。

その前に時節ネタを少し。

今日は七夕。私の出身地、神奈川県平塚市の七夕まつりもだいぶ以前のにぎわいを取り戻してきていました。七夕飾りはやはり夜がきれいですよね。

とても暑い中ですが、七夕にはなにか願い事をしてみてはいかがでしょうか。

IaCの共通化とバージョン管理という課題

あらためて本題。

みなさんはAzure Resource ProvisioningのIaC化していますか?IaC化を進めると、同じようなスクリプトを何度も書いていることがあると思います。そうした部分を共通化したい。さらに共通化したスクリプトもちゃんとバージョン管理したい。npm registryなどで公開されているようなイメージで個々のスクリプトごとにバージョン管理したい。そうしたことを考えるのではないでしょうか。

今回はBicepでそうした要望を実現するストーリーです。

Bicepでの実現方法

Bicepスクリプトの共通化

Bicepスクリプトの共通部分を記述し活用するのがモジュールです。

learn.microsoft.com

使い方はとても簡単で、上記のドキュメントの例では共通化するスクリプトを storageAccount.bicep というファイルに記述し、そうした共通スクリプトを利用する側で module .... で参照すればOK。

module stgModule '../storageAccount.bicep' = {
  name: 'storageDeploy'
  params: {
    storagePrefix: 'examplestg1'
  }
}

この方法だと、共通スクリプトを多くのチームで再利用しようとすると次のような問題がでてきます。主に以下のような問題です。

  • 共通スクリプトの配布方法
  • スクリプトのバージョニング

一般的なmoduleの呼び出しはフォルダ参照です。つまり、実行時に参照できるフォルダに共通化したスクリプト(モジュール)を配置しなければなりません。しかし、多数のチームでこれを実現するのはなかなか難しいのではないでしょうか。

この課題について、以前私が採用してた方法は共通スクリプト(モジュール)群を1つのgit repositoryに格納し、それを利用する側はgit submoduleでそのフォルダを参照するというものでした。

これでなんとか配布は実現できるのですが、次の問題はスクリプト(モジュール)のバージョニングです。 git submoduleでリポジトリの特定コミットを参照することはできます。つまりリポジトリ全体のバージョニングは可能です。しかし、ときにAというmoduleは(変更がないので)以前のバージョンを使いたいが、Bというmoduleは最新の機能を取り込むために新しいバージョンを利用したいといったケースがあります。

git submoduleでこうした状況に対応するためには各スクリプトが完全にBackward compatibilityを維持しつつ更新を続ける、といったことを意識し続ける必要があり、なかなか大変です。

つまり、さきほどあげた配布とバージョニングという2つの課題は git submoduleを使った方法では少し不十分でした。

BicepモジュールをPrivate Registryに公開する

もちろんこうした問題への対応もBicepで用意されています。それがPrivate Registryです。

learn.microsoft.com

以前、AVM というMicrosoftの取り組みをご紹介しました。

techblog.ap-com.co.jp

これは再利用可能なBicepスクリプトの公開リポジトリでした。Private Registryは自組織のみで参照可能とする再利用可能なスクリプト(モジュール)配布の方法です。

中身は普通のBicepスクリプトとまったく同じで、モジュール単位でPrivate Registryに発行することができます。Private RegistryはAzure Container Registryを指定します。

例えばスクリプトの中身としては次のようなイメージです。

container-registry.bicep

import { generateTag  } from '../utils/tag.bicep'
import { generateDeployId } from '../utils/deployId.bicep'

@description('Name of your Azure Container Registry. It requires alpha-numeric')
@minLength(5)
@maxLength(50)
param registryName string
@description('Optional. Tier of your Azure container registry.')
@allowed([
  'Basic'
  'Premium'
  'Standard'
])
param acrSku string = 'Standard'
@allowed([
  'disabled'
  'enabled'
])
@description('Optional. The value that indicates whether the retention policy is enabled or not.')
param retentionPolicyStatus string = 'enabled'

@description('Optional. The number of days to retain an untagged manifest after which it gets purged.')
param retentionPolicyDays int = 7
@allowed([
  'Disabled'
  'Enabled'
])
@description('Optional. Whether or not zone redundancy is enabled for this container registry.')
param zoneRedundancy string = 'Enabled'

@description('Tags for this resource')
param tags object = {}

var deployId = generateDeployId('acr-${registryName}')
var packageJson = loadJsonContent('package.json')
var mergedTag = generateTag(packageJson, tags)

module acr 'br/public:avm/res/container-registry/registry:0.1.1' = {
  name: 'acr-${deployId}'
  params: {
    name: registryName
    acrSku: acrSku
    retentionPolicyStatus: retentionPolicyStatus
    retentionPolicyDays: retentionPolicyDays
    zoneRedundancy: zoneRedundancy
    tags: mergedTag
  }
}

この例のように、モジュールの中からさらにAVMや他のフォルダに存在するModuleの呼び出しもOKです。importのように外部に定義したCustom Functionなども問題なく利用できます。

これをprivate registryに発行するには以下のコマンドを実行します。

az bicep publish --file contaienr-registry.bicep --target br:exampleregistry.azurecr.io/bicep/modules/containerregistry:v1 

発行したmoduleを利用する際には以下のように指定すればOKです。

module acr 'br:exampleregistry.azurecr.io/bicep/modules/containerregistry:v1' = {
  name: 'acr-${deployId}'
  params: {
    registryName: registryName
    ....
  }
}

また、bicepparamファイルで直接usingに指定することも可能です。

using 'br:exampleregistry.azurecr.io/bicep/modules/containerregistry:v1'

param registryName = 'my-registry'

Private registryを使う利点は公開するモジュール毎にバージョンを指定することができる、ということです。つまりさきほどの「Aというmoduleは(変更がないので)以前のバージョンを使いたいが、Bというmoduleは最新の機能を取り込むために新しいバージョンを利用したい」を実現することができるのです。

モジュールごとにバージョン指定ができるのはいいけれど、そのバージョン管理はどうするのか、更新忘れないか、といった心配もかもしれません。 私はそれを jsonファイルで管理することで簡単にしています。たとえば次のようなものです。

{
  name: "containerregistry",
  "version": "v1.1.1"
}

このようなjsonファイルを公開するモジュールごとに用意します。そこでバージョンを記載し、修正の際にバージョンを更新、private registryにpublishする際はこのjsonファイルのバージョン名を付与することにしています。

では、このjsonファイルを更新するにはどうするか・・・・。こうしたバージョン管理をするツールはたくさんあるので皆さんがご利用しているものをうまく活用すればできるのではないでしょうか。私は Changesets というツールを使っています(Backstageのプロジェクトで使われているものでもあり使い慣れているため)

ついでに、利用したモジュールのバージョンがわかるようにTagにこの情報も埋め込むようにしています。

こうした再利用したモジュールがたくさんできていくので、それをGitHub Actionsでまとめてpublishするしかけも用意しています。 (以前ご紹介したGtHub Actions内でのループ処理がこれを実現するときに役立ちます)

私がメンテナンスしている10数個のモジュールもこの方法で管理し、GitHub Actionsの実行ひとつで適切にpublishするようワークフローを作成しています。

techblog.ap-com.co.jp

まとめ

以上のように Private Registryに共通化したいBicepモジュールを公開することで、自組織に簡単に配布することができます。バージョニングもモジュール単位で行っていますので、モジュール利用者側が明示的に利用したいバージョンを指定可能です。これで利用者側への余計な負担なしに、共通化モジュールのアップデートも可能になります。 (あとは更新した内容を利用者側に適切にお知らせすることだけ。今その部分の方法を検討しています)

ぜひ、皆さんもPrivate Registryを活用してIaCの共通化を促進していきましょう。

それではまた次回お会いしましょう。