こんにちは。 CI/CD を含むクラウドインフラの構築や技術支援を担当している、クラウドエンジニアの佐藤です。
Azure インフラの構築や管理、皆さんはどのようなツールや方法でやっていますか?
例えば、ブラウザで Azure ポータル を開き GUI を操作する。もしくは、Azure CLI をコマンドとして実行する。他にも構築や管理できるツールや方法はたくさんありますが、今回のブログ記事の主役である Terraform を実行するやり方もあります。あとは、これらを場合によって使い分けたり、組み合わせたりと様々なユースケースが考えられます。
私個人の経験から Azure ポータル、Azure CLI、Terraform を比較すると、構築の難易度は Azure ポータル < Azure CLI < Terraform の順に高くなり、管理の難易度は Terraform < Azure CLI < Azure ポータルの順に高くなります。Azure ポータルで構築すると関連リソースやリソース同士の紐づけ設定も自動で行ってくれるため、構築検証の入口としてはとても楽です。その反面、どんな関連リソースを自動作成したのか、どのようなリソース同士の紐づけ設定を自動で行ったのかが把握し辛いです。そのため、後々それらのリソースの一部を変更したり問題切り分けしたり誰がいつ何を変更したかなどの、管理という観点では難しくなります。
という事で、上記のような課題感を持ちつつ、今回は「 Azure の構築と管理に Terraform を使ってみたら、こんなところが良かった」をお届けします。
クイック スタート: Terraform のインストールと構成
のドキュメントを参考に Terraform をインストールします。
私の場合は Windows で Azure CLI と Git Bash はインストール済みです。
Terraform のバイナリをダウンロード
してパスの通ったフォルダに「 terraform.exe 」を保存しました。
私の作業環境の Terraform と Azure CLI のバージョンは下記のとおりです。
$ terraform --version
Terraform v1.3.9
on windows_amd64
$ az version
{
"azure-cli": "2.45.0",
"azure-cli-core": "2.45.0",
"azure-cli-telemetry": "1.0.8",
"extensions": {}
}
参考までに Git Bash 環境で Azure CLI を使用する場合は、下記の環境変数をセットしてご使用ください。
export MSYS_NO_PATHCONV=1
Terraform 状態を Azure Storage に格納する のドキュメントを参考に Terraform の状態ファイル「 tfstate 」を保管し、かつ同時実行を防止する状態ロックを行うストレージアカウントを作成します。
## リソースグループを作成
az group create \
--name ceblogtf-rg \
--location japaneast
## ストレージアカウントを作成
az storage account create \
--resource-group ceblogtf-rg \
--name ceblogtf \
--sku Standard_LRS \
--encryption-services blob
## コンテナーを作成
az storage container create \
--name tfstate \
--account-name ceblogtf
リソースグループ「 ceblogtf-rg 」と、ストレージアカウント「 ceblogtf 」が作成されました。
ストレージアカウントのコンテナー「 tfstate 」が作成されました。
これで準備が整いました。
Terraform をチームで管理するには、複数の環境から状態ファイル「 tfstate 」を参照したり更新する必要があります。また、複数の環境で同時実行されるのを防ぐために状態ロックを行う必要があります。
AWS では、S3 で状態ファイルを保管し DynamoDB で状態ロックをするのですが、Azure はストレージアカウントのみで実現できます。
※
ストレージアカウントの状態ロックについて
ローカルの作業環境に作業用フォルダを作成し、作成したフォルダに移動します。
mkdir -p ceblog/terraform/ceblog-dev-vnet
cd ceblog/terraform/ceblog-dev-vnet/
まずは動作確認のため、リソースグループだけを Terraform で作成します。
「 main.tf 」というファイル名で下記の内容を保存します。
resource_group_name は、先ほど作成したストレージアカウントのリソースグループ名です。
storage_account_name は、先ほど作成したストレージアカウント名です。
container_name は、先ほど作成したストレージアカウントのコンテナー名です。
key は、複数の状態ファイルを保管できるようにするため、作業フォルダと対になるようパスをプレフィックスにします。
provider ブロックは、Terraform で Azure を扱う時のおまじないです。
resource ブロックは、Terraform のリソース定義で、今回は
azurerm_resource_group
の Terraform ドキュメントを参考にリソースグループの HCL(HashiCorp Configuration Language)を書きます。
terraform {
backend "azurerm" {
resource_group_name = "ceblogtf-rg"
storage_account_name = "ceblogtf"
container_name = "tfstate"
key = "ceblog-dev-vnet/terraform.tfstate"
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "ceblog-dev-vnet" {
name = "ceblogdev-rg"
location = "japaneast"
}
Terraform 構成を初期化してから実行します。
「 Apply complete! Resources: 1 added, 0 changed, 0 destroyed. 」と表示されたら完了です。
terraform init
terraform apply
ストレージアカウントの tfstate コンテナーの「 ceblog-dev-vnet 」パスに「 terraform.tfstate 」ファイルが作成されました。
リソースグループ「 ceblogdev-rg 」が作成され、まだリソースは無い状態です。
次に、Terraform で仮想ネットワークを作成します。
先ほどの「 main.tf 」に下記の内容を追加して保存します。
resource ブロックは
azurerm_virtual_network
の Terraform ドキュメントを参考に仮想ネットワークの HCL を書きます。
resource "azurerm_virtual_network" "ceblog-dev-vnet" {
name = "ceblog-dev-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.ceblog-dev-vnet.location
resource_group_name = azurerm_resource_group.ceblog-dev-vnet.name
}
Terraform 構成の実行プランを確認します。
terraform plan
azurerm_virtual_network リソースが追加される事を実行前に確認できます。
Terraform 構成を実行します。
「 Apply complete! Resources: 1 added, 0 changed, 0 destroyed. 」と表示されたら完了です。
terraform apply
仮想ネットワーク「 ceblog-dev-vnet 」が作成されました。
Azure ポータルで仮想ネットワーク「 ceblog-dev-vnet 」のアドレス空間を「 10.0.0.0/24 」に変更し「保存」します。
「 main.tf 」は変更していませんが、Terraform 構成の実行プランを確認します。
terraform plan
この Terraform 構成を実行すると「 10.0.0.0/24 」が「 10.0.0.0/16 」に変更される、と確認できます。
今回は Azure ポータルで行った変更を Terraform 構成に取り込むため「 main.tf 」の「 10.0.0.0/16 」を「 10.0.0.0/24 」に変更します。
resource "azurerm_virtual_network" "ceblog-dev-vnet" {
name = "ceblog-dev-vnet"
address_space = ["10.0.0.0/24"]
location = azurerm_resource_group.ceblog-dev-vnet.location
resource_group_name = azurerm_resource_group.ceblog-dev-vnet.name
}
もう一度 Terraform 構成の実行プランを確認します。
terraform plan
Azure リソースと Terraform 構成が同じ状態になったため「 No changes. Your infrastructure matches the configuration. 」と表示されます。
その下の英語を日本語に訳すと「 Terraform は実際のインフラストラクチャを構成と比較しましたが、違いは見つからなかったので、変更は必要ありません。」です。
Azure ポータルで行った変更を Terraform に取り込む事ができました。
このような変更が起こった時、Azure ポータル+パラメーターシートで管理しているとしたら、私はパラメーターシートを間違いなく更新する自信はありません。
また Azure CLI コマンドをコード化していても、コマンドのパラメーターを間違いなく更新する自信もありません。
Terraform は、Azure インフラをきちんと管理したいニーズにマッチしていると思います。
IaC(Infrastructure as Code)、インフラのコード化の実践です。
Azure CLI でサブネットを作成します。
az network vnet subnet create \
--vnet-name ceblog-dev-vnet \
--resource-group ceblogdev-rg \
--name default-subnet \
--address-prefix 10.0.0.0/26
仮想ネットワーク「 ceblog-dev-vnet 」にサブネット「 default-subnet 」が作成されました。
Terraform 構成の実行プランを確認します。
terraform plan
サブネットは Terraform 構成で管理していないため「 No changes. Your infrastructure matches the configuration. 」と表示されます。
Azure CLI で作成したサブネットを Terraform 構成にインポートします。
「 main.tf 」にサブネット用の resource ブロックを作成します。
resource "azurerm_subnet" "default-subnet" {
}
azurerm_subnet - import
のドキュメントを参考に Terraform コマンドを実行します。
「 Import successful! 」と表示されたらインポート完了です。
terraform import azurerm_subnet.default-subnet /subscriptions/$(az account show --query id -o tsv)/resourceGroups/ceblogdev-rg/providers/Microsoft.Network/virtualNetworks/ceblog-dev-vnet/subnets/default-subnet
インポートしたサブネットの Terraform 構成を確認します。
terraform state show azurerm_subnet.default-subnet
下記のようなパラメーターでインポートできた事がわかります。
「 main.tf 」のサブネット用 resource ブロックを修正します。
resource "azurerm_subnet" "default-subnet" {
name = "default-subnet"
resource_group_name = azurerm_resource_group.ceblog-dev-vnet.name
virtual_network_name = azurerm_virtual_network.ceblog-dev-vnet.name
address_prefixes = ["10.0.0.0/26"]
}
記述した内容に誤りが無いかを確認するため、Terraform 構成の実行プランを確認します。
terraform plan
サブネットを Terraform 構成で正しく管理できているため「 No changes. Your infrastructure matches the configuration. 」と表示されます。
Terraform 以外で作成された Azure リソースを Terraform 構成にインポートして管理する事ができるようになりました。
最初から Terraform で HCL を書かなくても、Azure ポータルや Azure CLI で作成してから管理する Azure リソースを見極め、後から Terraform 管理にする事ができます。
ここまでは、「 main.tf 」に少しずつ HCL を追記して Azure リソースを作成したり、管理対象を追加してきました。
この「 main.tf 」を別の Azure サブスクリプションで実行すれば同じ Azure リソースが作成できます。
ところが、HCL の書き方によっては依存リソースの作成順によるエラーなどが発生するため、私の経験上、一度削除し再作成してみる事をお勧めします。
Terraform 構成で管理しているサブネット、仮想ネットワーク、リソースグループを Terraform で一度削除してから再度作成します。
まずは、Terraform で削除の実行計画を確認します。
「 Plan: 0 to add, 0 to change, 3 to destroy. 」と表示されます。
terraform plan --destroy
Terraform で削除を実行します。
「 Destroy complete! Resources: 3 destroyed. 」と表示されたら削除は完了です。
terraform destroy
Azure リソースをまとめて再作成するため Terraform で実行計画を確認します。
「 Plan: 3 to add, 0 to change, 0 to destroy. 」と表示されます。
terraform plan
Azure リソースをまとめて再作成します。
「 Apply complete! Resources: 3 added, 0 changed, 0 destroyed. 」と表示されたら完了です。
terraform apply
先ほどと同じように、仮想ネットワーク「 ceblog-dev-vnet 」にサブネット「 default-subnet 」が作成されました。
リソースグループ、仮想ネットワーク、サブネットの Azure リソースを Terraform で構築し管理できるようになりました。
ちなみに、Azure ポータルから仮想ネットワークを作成するとサブネットも一緒に自動作成されますが、例えばサブネットに細かい追加設定をする場合は、別途 Azure ポータルを操作しなくてはいけません。
パラメータシートを見ながら Azure ポータルを操作していたら、時間もかかるし間違いもおこりやすくなります。
Terraform だと、リソースの作成順を気にしなくても依存するリソースを先に作成してくれます。
また、Azure リソースによっては作成に時間がかかるものがありますが、作成完了後に次の Azure リソースを順番に作成してくれます。
検証環境で十分に検証した Terraform コードを使って構築すれば、間違いもなく完了するのを待つだけで良くなります。
「 Azure の構築と管理に Terraform を使ってみたら、こんなところが良かった」をサンプルコードを交えてご紹介しました。
この記事では触れていませんが、Terraform コードの Git リポジトリ管理や CI/CD パイプラインに組み込んで使うユースケースもあります。
皆さんも Terraform で IaC してみませんか?
このブログ記事が誰かの何かの参考になればうれしいです。 最後まで読んで頂き、ありがとうございます。