CicleCIとTerraformを使ってAzureのセッションホストのデプロイを自動化する

2023年4月20日掲載

キービジュアル

共通プラットフォーム開発本部の宮田銀河 (入社3年目) です。

本記事では、Azureのセッションホストのデプロイを自動化するために、CircleCIとTerraformを使用した自動化システムを紹介します。

作成した自動化システムの構成について紹介し、CircleCIのコードについても解説します。また、本システムを構築・運用中に遭遇した問題についても共有します。

さらに、リソースのデプロイやデストロイにかかった時間についても触れます。Azureのセッションホストのデプロイを自動化したい方はぜひご覧ください。

目次

  • CicleCIとTerraformを使ってAzureのセッションホストのデプロイを自動化しました。
  • 作成した自動化システム構成やCircleCIのコードの解説を書いて有るので、直ぐに利用できます
  • 遭遇した問題とそれに対する解決策をまとめています。

想定読者

  • Terraformの実行を自動化したい方
  • CircleCIとTerraformを連携したい方
  • ソフトバンクの若手エンジニアの働きを知りたい方

システム構成図

作成した自動化システムの構成図を下図に示します。

構成図

GitHubとCircleCIを使用することで、開発者はローカルのPCからコードをGitHubにpushするだけで、Azure環境にセッションホストをデプロイすることができます。

TerraformのtfstateはAzureのBlob Storageに管理します (事前に作成したBlob Storageを使用します)。

セッションホストのドメイン参加先のActive Directory (以下AD) はAzureのVirutal Machinesに構築しました。ADが属するVnetは、デプロイするセッションホストのVnetと同じです。

作成したコード

作成したCircleCIのconfig.ymlとTerraformのmain.tfのコードを紹介します (一部簡略化)。まずはCircleCIのconfig.ymlです。terraform planを実行するJobとterraform applyを実行するJobの間にApproval typeのJobを挟むことで、予期せぬリソース作成を避けることができます。conditionというCircleCIの機能を使用して、planとapplyの実行を制御しています。

version: 2.1

jobs:
  execute_terraform:
    description: Execute Terraform
    parameters:
      mode:
        type: string
        default: ""
    docker:
      - image: "terraformコマンドが使用できるイメージを指定する"
        auth:
          username: $FOO 
          password: $BAR 
    steps:
      - checkout
      - run:
          name: set bash_env for terraform
          command: |
            echo 'export ARM_CLIENT_ID=${FOO_SP_CLIENT_ID}' >> $BASH_ENV
            echo 'export ARM_CLIENT_SECRET=${FOO_SP_SECRET}' >> $BASH_ENV
            echo 'export ARM_SUBSCRIPTION_ID=${FOO_SUBSCRIPTION}' >> $BASH_ENV
            echo 'export ARM_TENANT_ID=${FOO_TENANT}' >> $BASH_ENV
      - run:
          name: terraform init
          command: |
            terraform init -reconfigure \
              -backend-config="resource_group_name=foo_rg" \
              -backend-config="storage_account_name=bar_storage" \
              -backend-config="container_name=foo_container" \
              -backend-config="key=bar_key"
      - when:
          condition:
            equal: [ '<< parameters.mode >>', plan ]
          steps:
            - run:
                name: Terraform Plan
                command: |
                  terraform plan --parallelism=300
      - when:
          condition:
            equal: [ '<< parameters.mode >>', apply ]
          steps:
            - run:
                name: Terraform Apply
                command: |
                  terraform apply -auto-approve --parallelism=300 

workflows:
  version: 2
  workflow_deploy_sessionhosts:
    jobs:
      - execute_terraform:
          name: terraform_plan
          mode: "plan"
          filters:
            branches:
              only:
                - /feature.*/ 
      - approveApply: # terraform planの結果を確認する
          type: approval
          requires:
            - terraform_plan
          filters:
            branches:
              only:
                - /feature.*/ 
      - execute_terraform:
          name: terraform_apply
          mode: "apply"
          requires:
            - approveApply
          filters:
            branches:
              only:
                - /feature.*/ 

次にTerraformのコードです。紙面の関係上、セッションホスト本体のTerraformのコードだけを載せています。全体のコードが知りたい方は、公式ドキュメントのコードをご覧ください。


resource "azurerm_windows_virtual_machine" "avd_vm" {
  count                 = var.number_of_session_host_for_host_pool
  name                  = "${var.vm_name_prefix}-${count.index + 1 + var.avd_index}"
  resource_group_name   = azurerm_resource_group.rg.name
  location              = azurerm_resource_group.rg.location
  size                  = var.vm_size
  network_interface_ids = ["${azurerm_network_interface.avd_vm_nic.*.id[count.index]}"]
  provision_vm_agent    = true
  admin_username        = var.local_admin_username
  admin_password        = var.local_admin_password
  # availability_set_id   = data.azurerm_availability_set.availability_set.id

  os_disk {
    name                 = "${lower(var.vm_name_prefix)}-${count.index + 1 + var.avd_index}"
    caching              = "ReadWrite"
    storage_account_type = var.vm_disk_type
  }
  # source_image_id = var.vm_custom_image_source_id
  source_image_reference {
    publisher = "MicrosoftWindowsDesktop"
    offer     = "Windows-10"
    sku       = "21h1-ent"
    version   = "latest"
  }

  depends_on = [
    azurerm_resource_group.rg,
    azurerm_network_interface.avd_vm_nic
  ]
}

上記のconfig.ymlとTerraformのコードをGitHubのリポジトリに配置します。ディレクトリ構成は以下です。この構成にすれば、featureブランチへのpush時にCircleCIで定義したワークフローが実行されます。

.
├── .circleci
│   └── config.yml
├── main.tf
├── providers.tf
├── terraform.tfvars
└── variables.tf

本システムの構築・運用中に遭遇した問題

遭遇した問題をTerraformとAzure関連、AD関連に分けて説明します。特に時間を消費した問題をまとめました。

TerraformとAzure関連

  • Terraform apply時に権限不足によりリソースを作成できないエラーが表示される
    • 対処法: Azureリソースをデプロイできるシークレットを指定する
  • tfstateがロックされているために、デプロイできないエラー
    • 対処法: tfstateを保存しているBlobのロックを解除する (参照)
  • コンピュータ名が長いために、デプロイできないエラー
    • 対処法: コンピュター名は15文字以下にする

AD関連

  • ADへの参加はできていないのにもかかわらず、Terraformのログはcreation completeと表示される
    • 対処法: 最適な対処法は思いつきませんが、都度ADの設定を実際に確認していました。
  • VM上にADを構築すると、デフォルトで10台のコンピュータしかAD参加できない (1枚目の画像はエラー内容)
    • 対処法: adsiedit.mscを実行してms-DS-MachineAccountQuotaの値 (デフォルト10) を変更する(2枚目の画像)。こちらをご参照ください。
ドメイン参加時のエラーログ
ms-DS-MachineAccountQuotaの値
  • terraform destroyをしても、ADにはコンピュータ名が残ったまま。またホストプールにはVMが”使用不可の状態で残ってしまう。
    • 対処法: 全部手動で消してから再度 terraform applyする
ホストプール内のVMの状態

デプロイ/デストロイに要する時間  (目安)

以下の条件でデプロイを実施しました。

  • セッションホストのsku: 21h1-ent (versionはlatest)

  • ホストプール: 個人用

  • ドメイン参加先のAD: デプロイするセッションホストと同じVnetに構築

リソースのデプロイ、デストロイに使用したコマンドは以下です。parallelismはリソースデプロイ時の並列度を示しています。詳細については、公式ドキュメントをご参照ください。

terraform apply -auto-approve --parallelism=10 
terraform apply -auto-approve --parallelism=300
terraform destry -auto-approve --parallelism=300

 

10台のセッションホスト(parallelism=10)

100台のセッションホスト(parallelism=300)

300台のセッションホスト(parallelism=300)

デプロイに要した時間

9分

12分

30分

デストロイに要した時間

5分

13分

31分

 

セッションホスト10台のデプロイ (並列度10) 時間とセッションホスト100台のデプロイ (並列度300) 時間がほぼ同じなので、parallelismが機能していることがわかります。ただし、セッションホスト100台のデプロイ (並列度10) とセッションホスト300台のデプロイ (並列度300) の時間が3倍違いました。ちなみにparallelism=1として実行すると、途方もない時間がかかります。並列度は適時調整すべきです。

実際に300台デプロイしたときのTerraform applyの実行ログ、Azureリソース状況、ADの状況は以下の画像のようになりました。301台と表示されているのは、元々1台がデプロイされていたからです。

terraform applyの実行時の状況

まとめ

Azureのセッションホストのデプロイを自動化するために、CircleCIとTerraformを使用した自動化システムの構築方法を紹介しました。作成した自動化システム構成のCircleCIのコードを紹介し、構築・運用する最中に遭遇した問題やそれに対する解決策についても共有しました。さらに、リソースのデプロイやデストロイにかかった時間についても触れました。Azureのセッションホストのデプロイを自動化したい方は参考にしていただければ幸いです。

この記事を読んで興味を持っていただいた学生・エンジニアの方は、ぜひ当社の採用に応募して頂けると嬉しいです。

関連サービス

ソフトバンク新卒採用

常に進化し続けるソフトバンクを楽しみながら

  • いかなる仕事もチャンスと捉えやり遂げる
  • さまざまな機会へ自ら意欲的に手を挙げる

そんな一人一人の挑戦が会社の未来を創ります

おすすめの記事

条件に該当するページがございません