この記事はなむゆの個人ブログにもマルチポストしてあります。
はじめに
最近はTerraformも回しています、なむゆです。
IaCを実現するツールであるTerraformですが、そのコードを編集した際にちゃんと思った通りに動くか確認する方法としては、そのコードを実際に動かして作成された環境を確認するのが一般的かと思います。
しかし、そうすると毎回terraform planしてterraform initし、環境が作成されて動作確認もできたら手動でその環境を削除しなければならず、かなり手間と時間がかかります。
※2021/5/20後記 Terraformを用いて作成された環境を削除する方法としてはterraform destroyするのも手です。特にいくらでもリソースが多くない構成なら、それで事足りるかと思います。
ここを効率化しようとしたときに使えそうなツールをいろいろ探していた時に見つけた方法として、今回はTerratestを用いたAzure DevOpsパイプラインを作る方法を共有したいと思います。
Terratestとは
Terratestは、Gruntwork.ioが開発している、インフラストラクチャー向けのGo言語のテストライブラリです。
Terra---という名前のとおり、Terraformをメインでサポートしていますが、他にPackerやDocker、Kubernetesの構築のテストも行えるようです。
特に、Terraformをサポートしているため、TerraformがサポートしているGCP、AWS、そしてAzureのインフラもテストすることができます。
TerratestをAzure Pipelineで実行出来たら何がうれしいの?
そんなインフラのテストライブラリであるTerraformですが、CI(継続的インテグレーション)の仕組みとしてAzure Pipelineに組み込めるとさらに強力になります。
Azureの環境構築にTerraformを使っていた場合、そのTerraformスクリプトをGithub等で管理するかと思うのですが、更新したときにはそのコードをマージしても動作することを保証するために動作確認を取るかと思います。
その際にTerratestを使ったパイプラインを用意することで、例えばGithubにPRが作成されたタイミングでTerratestによるテストを自動的に実行し、動作確認を取って結果が正常かどうかを確認することができます。
手動で動作確認を取ろうとすると環境作成の手順や作成したリソースの確認の手間がかかったり作業した箇所以外の影響に気付かずデグレが起きたりする可能性がありますが、テストとして動作確認の自動化の仕組みを作っておくことでこれらを解決できます。
実際にTerratestのテストパイプラインを作ってみる
ここではTerratestのサンプルスクリプトを使いながら、Azure DevOpsのパイプラインとしてAzureにリソースをデプロイするTerraformスクリプトのテストを行う例を示したいと思います。
スクリプトを用意
今回使用するTerraformとテスト用のgolangのスクリプトはTerratestのExamplesのページにあるAzureの例のものになります。
4つあるので、これらをAzure DevOpsのReposなり、権限のあるGithubのリポジトリなりに作成しておきます。
気を付ける必要があるのはこれらを配置するディレクトリ構成です。
terraform_azure_example_test.goからの相対パスの記述の都合上以下のような構成で配置するようにしてください。
├─examples
│ └─azure
│ └─terraform-azure-example
│ main.tf
│ outputs.tf
│ README.md
│ variables.tf
│
└─test
└─azure
terraform_azure_example_test.go
それに加えて、パイプライン用の以下のyamlスクリプトをリポジトリ内の適当な場所に作成しておきます。
テスト用のgoスクリプトがあるディレクトリのパスだけ実際のディレクトリに合わせて変更しましょう。
pr: main
trigger: none
variables:
- group: AZURE_CREDENTIALS
steps:
- pwsh: |
az login --service-principal -u $(ARM_CLIENT_ID) -p $(ARM_CLIENT_SECRET) --tenant $(ARM_TENANT_ID)
az account set --subscription $(ARM_SUBSCRIPTION_ID)
cd $(Build.SourcesDirectory)/[ここにはソースのルートディレクトリからテスト用のgoスクリプトがあるディレクトリまでのパスが入ります]
go mod init "terratest-ex"
go get -v -u github.com/gruntwork-io/terratest
go test -v -timeout 30m
env:
ARM_CLIENT_ID: $(ARM_CLIENT_ID)
ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
ARM_SUBSCRIPTION_ID: $(ARM_SUBSCRIPTION_ID)
ARM_TENANT_ID: $(ARM_TENANT_ID)
今回使用するスクリプトとしては上記のもので全部になります。
次はこれらのスクリプトを動かすための下準備をしていきます。
Azureのサービスプリンシパルを用意
この作業には、お手持ちのAzure サブスクリプションに対して権限を割り当てられたサービスプリンシパルが必要になります。
所有者権限があれば十分なので、サービスプリンシパルを作成し、サブスクリプションに対して権限を割り当てておきます。
具体的な方法についてはこちらのドキュメントを参考にすると分かりやすいかと思います。
この時、いくつかのパラメータをメモしておくようにしてください。
パイプライン実行時にTerraformの実行対象のサブスクリプションへのログイン処理に必要になるためです。
必要なものとしては、「割り当てた対象のサブスクリプションのID」「作成したサービスプリンシパルのクライアントID」「サービスプリンシパルを作成したActiveDirectoryのテナントID」、「作成したサービスプリンスパルにログインするためのシークレット」の4つになります。
サービスプリンシパルのシークレットの作成については、上記のドキュメント内の「新しいアプリケーション シークレットを作成する」の項にやり方が書かれています。
Variable Groupを用意
パイプラインで使用するVariable Groupを用意します。
Azure DevOps内のPipelines -> Library -> 「+ Variable Group」のボタンから、VariableGroupを新規作成します。
Azureのサービスプリンシパルを用意する際に取得した4つのパラメータをそれぞれの名前で追加していきます。
ARM_CLIENT_ID: 作成したサービスプリンシパルのクライアントID
ARM_CLIENT_SECRET: 作成したサービスプリンスパルにログインするためのシークレット
ARM_SUBSCRIPTION_ID: 割り当てた対象のサブスクリプションのID
ARM_TENANT_ID: サービスプリンシパルを作成したActiveDirectoryのテナントID
これら4つの変数を追加出来たら、Variable group nameに「AZURE_CREDENTIALS」と名前を付けて保存します。
パイプラインを用意
これにて下準備は完了したので、パイプラインを用意します。
パイプラインの作成方法については過去記事に例があるのでそちらを参考にしてみてください。
実行
最後に作成したパイプラインを実行します。
このパイプラインは6分程度で完了するかと思います。
処理の途中でAzureを開くと、リソースが作成されていることが確認できるかと思います。
そして、テストが終わるとそのテストのために作成されたリソースが順次削除されていき、最終的にはテストの実行前の状態に戻ることが確認できるかと思います。
おわりに
今回はAzure DevOpsでTerratestを用いたTerraformのコードのテストを実行する方法を共有しました。
これによってTerratestでのTerraformスクリプトのテストをAzure Pipeline上の自動化されたタスクとして行えるようになります。
Terraformコードが本当に動くか確認するために実際にTerraformを実行して目視で動作確認するスクリプトて、テストに書いてあることはより確実にチェックでき、変更による他の部分の予期しない影響も感知することができます。
また、今回は行いませんでしたが、Terraformスクリプトをapplyするのではなくplanをした際の結果を用いてテストを行うこともでき、そちらの方法だと1回のテストにかかる時間が少ない分より頻繁にテストを実行することができます。
Terraformコードの動作確認の効率化をしたい際に検討してみるのもいいかと思います。