しばやん雑記

Azure Serverless とメイドさんが大好きなフリーランスのプログラマーのブログ

Terraform Provider for Azure の開発環境を VS Code Dev Container で構築する

Azure 環境での IaC には Terraform をメインで使っていますが、ARM Template や Bicep と異なり Terraform は ARM REST API ベースで構築されているので、新しい機能の場合は Azure SDK を更新しつつ Provider に機能を追加というステップを踏む必要があります。

正直なところ ARM Template や ARM REST API は各サービスで一貫性のない設計になっているので、その辺りを吸収するために Terraform Provider は多少複雑になっています。なので対応に時間がかかるのは仕方ない部分がありますが、GitHub を使って貢献できるので必要に応じて PR を投げています。

README に Windows を使っている Provider 開発者向けの手順が少し載っていますが、今だと WSL 2 と VS Code の Dev Container を使って環境を構築するのが一番手っ取り早いのと、日本からの Contributor が増えることを祈って方法を残します。

Dev Container の定義を作成

Dev Container の定義はコマンドパレットから Go のテンプレートを参照すれば基本は問題ないです。現時点では Go 1.16 が必要なので、バージョンは合わせておく必要があります。

テンプレートを使えば基本的な Go の開発に必要な設定が入ります。Dockerfile は特に弄る必要がないので、生成されたものをそのまま使えばよいです。

// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.183.0/containers/go
{
	"name": "Go",
	"build": {
		"dockerfile": "Dockerfile",
		"args": {
			// Update the VARIANT arg to pick a version of Go: 1, 1.16, 1.15
			"VARIANT": "1.16",
			// Options
			"INSTALL_NODE": "false",
			"NODE_VERSION": "lts/*"
		}
	},
	"runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],

	// Set *default* container specific settings.json values on container create.
	"settings": {
		"go.toolsManagement.checkForUpdates": "local",
		"go.useLanguageServer": true,
		"go.gopath": "/go",
		"go.goroot": "/usr/local/go"
	},

	// Add the IDs of extensions you want installed when the container is created.
	"extensions": [
		"golang.Go"
	],

	// Use 'postCreateCommand' to run commands after the container is created.
	"postCreateCommand": "make tools",

	// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
	"remoteUser": "vscode"
}

生成されたファイルから postCreateCommand だけは修正しています。具体的には make tools を実行するようにして、必要なツールを Dev Container にインストールしています。

後はコマンドパレットから "Remote-Containers: Rebuild Container" を実行すると、Dev Container が再作成された後に必要なツールも自動でインストールされます。

f:id:shiba-yan:20210707001007p:plain

これで環境構築は完了なので、後は Provider のコードを修正して make buildmake test を実行して動作確認と PR 作成に向けた準備をしていく流れになります。

f:id:shiba-yan:20210707000816p:plain

ちゃんと Go の拡張機能と Language Server も動作するので、Provider のリポジトリに含まれているコーディングスタイル系の設定も問題なく反映されます。VS Code の場合はコードを書いていると自動的にコーディングスタイルが適用されていくので楽です。

Acceptance Tests の実行に必要な設定を追加

Terraform Provider に含まれているテストコードには実際に Azure 上にリソースを作成して、正しく動作するか確認するためのテストが大量に含まれています。当然ながら PR 前にはテストの追加と動作確認が必要なので、Dev Container 上で動かせるようにしておきます。

必要な Service Principal は az ad sp create-for-rbac を使って、サブスクリプション単位に権限を割り当てたものを作れば問題ないです。認証情報は環境変数経由で渡す必要があるので、Dev Container に追加する設定を書いていきます。

devcontainer.json に書くのが手っ取り早いですが、必要なキーが多いので今回は devcontainer.env を作成して読み込むようにしました。それぞれの意味はキー名から読み取れると思うので省略します。

ARM_CLIENT_ID=<AAD_CLIENT_ID>
ARM_CLIENT_SECRET=<AAD_CLIENT_SECRET>
ARM_SUBSCRIPTION_ID=<SUBSCRIPTION_ID>
ARM_TENANT_ID=<TENANT_ID>
ARM_ENVIRONMENT=public
ARM_TEST_LOCATION=westus2
ARM_TEST_LOCATION_ALT=centralus
ARM_TEST_LOCATION_ALT2=eastus

リソースを作成するリージョンは、作成対象のリソースが対応しているものである必要があるので、一般的には US リージョンを選んでおけば外れが少ないです。

env ファイルを読み込む設定は runArgs--env-file パラメータでファイル名を渡すだけです。

"runArgs": [ "--env-file", ".devcontainer/devcontainer.env", "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],

これで Dev Container を再生成すれば環境変数が反映されて、テストコードが実行可能になります。

f:id:shiba-yan:20210718010952p:plain

実際に Static Web App のテストコードを実行してみましたが、リージョンだけ気を付ければ問題なく動作します。リソースについては作成に時間がかかるのと、課金対象になるので気を付ける必要があります。

自前ビルドした Provider を使ってリソースを作成

Dev Container を使って修正した Terraform Provider はビルドすればローカルでテストすることが出来るので、既存の Terraform 定義を使って動作確認を行えます。

手順は README に書いてありますが、少し設定方法が分かりにくいです。

Terraform Provider のオーバーライドには設定ファイルを別途用意する必要があります。Windows 上では %APPDATA% の直下に terraform.rc という名前で作成し、それ以外の環境ではユーザーの HOME ディレクトリ直下に .terraformrc という名前で作成します。

Windows のディレクトリが若干特殊なので注意が必要です。この辺りの詳細はドキュメントにもあります。

設定ファイルの中身は README にある内容をほぼコピペで問題ありません。オーバーライドしたい Provider に関しては dev_overrides に名前とパスのマッピングを追加していきます。ここではファイルではなくディレクトリのパスを指定する必要があります。

provider_installation {

  # Use /home/developer/go/bin as an overridden package directory
  # for the hashicorp/azurerm provider. This disables the version and checksum
  # verifications for this provider and forces Terraform to look for the
  # azurerm provider plugin in the given directory.
  dev_overrides {
    "hashicorp/azurerm" = "/home/shibayan/terraform-provider-azurerm/bin"
  }

  # For all other providers, install them directly from their origin provider
  # registries as normal. If you omit this, Terraform will _only_ use
  # the dev_overrides block, and so no other providers will be available.
  direct {}
}

設定に問題が無ければ terraform init やその後のコマンド実行時に、Provider がオーバーライドされているという警告メッセージが以下のように表示されます。

f:id:shiba-yan:20210719220521p:plain

警告が出ている間は自前でビルドした Provider が使われ続けます。Provider への貢献という面ではテストコードを追加するのであまり利用する機会はないのですが、オーバーライド方法は知っておいて損はないです。