Azure の構成管理を ARM templates と Terraform で検討してみた


前書き

現在所属している組織では Azure を利用しており、これから IaC を推進していくために技術検証をはじめました。ARM templates のチュートリアル、Terraform for Azure のチュートリアル、HashiCorp on Azure のウェビナー 、ドキュメント読み漁りで得た情報をまとめて行きます。

なお、記事作成時の筆者のスペックは Azure経験:2週間程度、ARM templates経験:20時間程度、Terraformの経験:40時間程度のぺいぺいである事をご了承ください。 GCP では僅かながら IaC (Google Cloud SDK や Terraform) を用いた構成管理の経験があります。

何を使うべきかを検討する上での私のスタンス

構成管理は"1つのツールで全てやろうとするのはあまり良い考えでは無い"という考えに共感しています。なぜなら、課題に合ったツールを採用すべきであり、目的のシステムを取り巻く課題は刻々と変化するためです。

ゴールはあくまで "インフラを継続的に再利用可能にする"であるかなと思います。

そのため、各比較象限で ARM templates と Terraform の優劣を決めて行くのではなく、特徴を書いて行きます。

参考1:

We compare Terraform to a number of these tools, but it should be noted that Terraform is not mutually exclusive with other systems

by https://www.terraform.io/intro/vs/index.html

参考2:

自動化関連のツールの流行り廃りは早いので、1つのツールで全てやろうとするのはあまり良い考えでは無いと思います
https://engineering.mobalab.net/2018/01/10/terraform-%E3%81%AB%E3%82%88%E3%82%8B%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9%E6%A7%8B%E7%AF%89/

Terraform に関して

特徴

マルチプロバイダーでも統一されたワークフローを提供する

Terraform はとにかく統一されたインフラ構築のワークフローをもたらします。インフラの構築先が Azure であっても、 GCP であっても、オンプレであっても、構築対象が VM であっても k8s であってもです。planでインフラの変更差分を確認して、apply でインフラ構築を実行します。以下の様な流れです。

構成ファイル(.tf)を記述
↓
init (provider plugins の取得。)
↓
plan (新規作成した場合の構築内容を表示。)
↓
apply (インフラを新規構築。stateファイルの作成。)
↓
(インフラの変更が必要になる。)
↓
構成ファイル(.tf)を修正
↓
plan -out=newplan (インフラの変更内容の確認。変更プランとして書き出し。)
↓
apply "new_plan" (変更プランを適用。)
↓
(インフラが不要になる。)
↓
destroy (インフラの破棄。)

コードレビュー + CI の運用に乗せやすそう

ウェビナーでおすすめされていた運用は以下の様なものでした。

  • state ファイルを blob ストレージ (または Terraform Cloud)で管理する
  • 構成ファイルを記述したらコードレビューを入れる
  • CI で plan を実行させ、構成ファイルと plan コマンドで出力される変更の両方を確認する
  • apply は必ず CI に実行させる
  • 新規にインフラを作る場合は必ず Terraform を使って Azure Portal から作成をしない
  • Azure の Provider できない値指定は ARM templates と併用するか Provider に Pull Request を投げる

インフラ構築・修正がコードレビューした上で、CIから実行するフローはとても素敵ですね

ちなみに、既存AzureリソースはHCLに置き換えるとができないとウェビナーでは回答頂いたのですが、terraform importを利用する事で、stateファイルを作成する事ができました。

運用のためのTerraform Cloud が用意されている

私は試していませんがこちらの記事を拝見させて頂いた限り、とても良さそうです
https://blog.shibayan.jp/entry/20200910/1599749096

その他特徴

  • 構成ファイル(.tf)が読みやすい
  • 構成ファイルはコメントが書ける
  • VS Code にも JetBrain のIDEでもプラグインがある

気になるところ

気になるところもいくつかありました。

Provider が Azure の変更に対応するか

ウェビナーで質問したところ、OSS なので Azure の変更への追随には多少遅れが生じるため、是非コントリビュートして欲しいという言葉をいただきました。 Go (Terraform本体・Provider共に)で書かれており、私には残念ながら難しいかもしれません。

ソースの更新は頻繁であるように感じました。
https://github.com/terraform-providers/terraform-provider-azurerm/pulse/monthly

HashiCorp のサイトには強力なパートナーシップが長年実現されてきた旨が書かれています。
https://www.hashicorp.com/cloud-partners/microsoft?product=terraform

Terraform はあくまで Wrapper であること

Azureの各インフラのAPIバージョンなどの細かい指定や細かな属性調整ができるのか不安です。
(ろくに内部のコードを読まずにこんなことを言って申し訳ない)

手を動かしてみる

チュートリアル+アルファを実行したメモを置いておくので、雰囲気を見るのに役立ててください。

環境設定

  • azsure cli を install する
  • install
    • brew install hashicorp/tap/terraform
    • Terraform v0.13.5
    • terraform -install-autocomplete
    • vscode の pligin を install
      • hashicorp.terraform
  • azure でリソースグループ terra_test を作成
    • location: japaneast だけを設定する
  • cat ~/ghq/github.com/github/gitignore/Terraform.gitignore >> .gitignore

既存のインフラを後からコード化する

$ terraform state list
azurerm_resource_group.rg

$ terraform state show azurerm_resource_group.rg
# azurerm_resource_group.rg:
resource "azurerm_resource_group" "rg" {
    id       = "/subscriptions/<subscription_id>/resourceGroups/terra_test"
    location = "japaneast"
    name     = "terra_test"
    tags     = {}

    timeouts {}
}

インフラを変更する

main.tf を以下のように変更する

resource "azurerm_resource_group" "rg" {
  name     = "terra_test"
  location = "japaneast"

  tags = {
        Environment = "Terraform Getting Started"
    }
}

terraform plan -out=newplan を実行する。

変更箇所が分かりやすい。

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_resource_group.rg will be updated in-place
  ~ resource "azurerm_resource_group" "rg" {
        id       = "/subscriptions/<subscription_id>/resourceGroups/terra_test"
        location = "japaneast"
        name     = "terra_test"
      ~ tags     = {
          + "Environment" = "Terraform Getting Started"
        }

        timeouts {}
    }

Plan: 0 to add, 1 to change, 0 to destroy.
  • terraform apply "newplan" を適用する。
    • Apply complete! Resources: 0 added, 1 changed, 0 destroyed. が表示される
    • terraform state show azurerm_resource_group.rg すると結果が変わっている

インフラを削除する

  • terraform destroy

  • 実行するかどうかが表示される

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_resource_group.rg will be destroyed
  - resource "azurerm_resource_group" "rg" {
      - id       = "/subscriptions/<subscription_id>/resourceGroups/terra_test" -> null
      - location = "japaneast" -> null
      - name     = "terra_test" -> null
      - tags     = {
          - "Environment" = "Terraform Getting Started"
        } -> null

      - timeouts {}
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value:

Terraform 関連のリンク

有用だったリンクや公式ドキュメントのリンクを置いておきます。

ARM templates に関して

ARM Templates の特徴

Azure の新しいサービスと機能をすぐに利用できる

公式の"ARM テンプレートを選択する理由"に記載があります。
https://docs.microsoft.com/ja-jp/azure/azure-resource-manager/templates/overview#why-choose-arm-templates

パラメータをファイル管理できる

テンプレートとパラメータに分けて管理できます
https://docs.microsoft.com/ja-jp/azure/azure-resource-manager/templates/parameter-files

what-if と呼ばれるもので dry run ができる (preview)

状態ファイルが無くても what-if コマンドで dry run ができます

既存リソースを定義ファイルにエクスポートができる

ポータルから手軽に作成済のリソースをテンプレートとしてエクスポートする事ができます

その他特徴

  • モジュール化できる
  • 状態ファイルを管理しない
  • 相互に依存するリソースのデプロイが調整され、正しい順序で作成される
  • Azure Key Vault と連携してセキュアな管理ができる
  • 日本語ドキュメントが充実している
  • VScode の Azure Resource Manager (ARM) Tools のスニペットが強力
  • 定義ファイルはJSON
    • パラメーターを説明は metadata に記載する
"parameters": {
     "storageAccountType": {
         "type": "string",
         "metadata": {
             "description": "The type of the new storage account created to store the VM disks."
         }
     }
}

手を動かしてみる

チュートリアル - 初めての ARM テンプレートを作成してデプロイするを実施し、VM の立ち上げ + VMリソースの修正をしました。雰囲気を感じられると思うので手順と結果を置いておきます。

  • VSCodeの拡張機能(ARMTools) を準備する
    • 拡張機能を準備する
    • .net coreが入ってないと、パラメータのスニペットが動かない
    • mac に wget のコマンドが入っていなかったので、 VSCode をがエラーを吐いていた
    • VSCode を再起動すると.net coreが再度インストールが始まる
    • "azuredeploy.json"のファイルタイプをAzureResourveManagerTemplateに変更しないとスニペットが効かない
  • チュートリアル 初めての ARM テンプレートを作成してデプロイするを実施する
  • VM をデプロイする用のリソースグループを作成する
    • az group create --name armt_test --location japaneast
  • ポータルからVMのスペックを選択して、テンプレートとパラメータをエクスポートする
    • スクラッチでいきなり書くのは厳しいので
  • エクスポートしたテンプレートとパラメータを DRY RUN する
    • az deployment group what-if --resource-group armt_test --template-file template.json --parameters parameters.json
    • 新規作成は緑で表示されます
      • 中略
  • エクスポートしたテンプレートとパラメータをデプロイする
    • az deployment group create --resource-group armt_test --template-file template.json --parameters parameters.json
  • VMが作成された事をポータルから確認する
  • VMのパラメータを変更した parameters2.json を作成する
  • parameters2.json を DRY RUN する
    • az deployment group what-if --resource-group armt_test --template-file template.json --parameters parameters2.json
    • change は delete create で表現されています
      • 中略
  • parameters2.json を適用する
    • az deployment group create --resource-group armt_test --template-file template.json --parameters parameters2.json
  • リソースグループを削除する
    • az group delete --name armt_test

所感

少し触ったり調べた程度だと どちらも DRY RUN 、 コードレビューができ、IaC をする上で申し分ないように感じます。
ただし、大規模化すると使い勝手も変わってくるかもしれません。

以上でございます。