ククログ

株式会社クリアコード > ククログ > Terraformの導入 - 検証環境をコマンドで立ち上げられるようにする その3

Terraformの導入 - 検証環境をコマンドで立ち上げられるようにする その3

はじめに

プロビジョニングツールはAnsibleが好きなのだけれど、Windowsに対しては一手間必要なのが大変だなぁと思っている畑ケです。

前回までの記事で、Windows Server 2019 Datacenterの検証環境をTerraformの機能を使ってAzureに構築する方法を解説しました。今回はその第3回目です。 Windowsの機能でWinRMというWindowsのプロビジョニングに使用できる機能があります。

Ansibleはプロビジョニングツールの一種で、Windowsに対するプロビジョニングツールもサポートしています。

Azure上のWindows 10のインスタンスについてはボリュームライセンスを用意する必要があります。ライセンス認証については https://docs.microsoft.com/ja-jp/windows/deployment/windows-10-subscription-activation の記事をご覧ください。 この記事ではWindows Server 2019 Datacenterを用いて解説します。

WindowsインスタンスのWinRMを有効化する

WinRMを有効化するには、例えば、スタートアップコマンドに有効化を行うコマンドを登録する必要があります1

## Windows 10 2016LTSBなど、古いVMでは以下を有効にしてTLS1.2を明示的に有効化する必要がある場合があるので注意 
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible-documentation/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile ConfigureRemotingForAnsible.ps1
powershell -ExecutionPolicy RemoteSigned ConfigureRemotingForAnsible.ps1
Remove-Item -path ConfigureRemotingForAnsible.ps1 -force

上記のスクリプトをsettings.ps1として保存し、configディレクトリの下に配置します。

$ tree -L 1 config                                                                                                                                                                    
config
└── settings.ps1

また、AzureのCustomData領域からsettings.ps1を別のファイル名として取得し、スタートアップ時に実行するコマンド群をXMLで定義します。

<FirstLogonCommands>
    <SynchronousCommand>
        <CommandLine>cmd /c "mkdir C:\terraform"</CommandLine>
        <Description>Create the Terraform working directory</Description>
        <Order>11</Order>
    </SynchronousCommand>
    <SynchronousCommand>
        <CommandLine>cmd /c "copy C:\AzureData\CustomData.bin C:\terraform\winrm.ps1"</CommandLine>
        <Description>Move the CustomData file to the working directory</Description>
        <Order>12</Order>
    </SynchronousCommand>
    <SynchronousCommand>
        <CommandLine>powershell.exe -sta -ExecutionPolicy Unrestricted -file C:\terraform\winrm.ps1</CommandLine>
        <Description>Execute the WinRM enabling script</Description>
        <Order>13</Order>
    </SynchronousCommand>
</FirstLogonCommands>

このXMLをconfig以下に配置すると、configディレクトリは以下のファイルを含みます。

$ tree -L 1 config
config
├── FirstLogonCommands.xml
└── settings.ps1

0 directories, 2 files
diff --git a/main.tf b/main.tf
index 0d428b1..6568904 100644
--- a/main.tf
+++ b/main.tf
@@ -130,15 +130,43 @@ resource "azurerm_virtual_machine" "win10testing" {
     computer_name  = "cc-winserv"
     admin_username = var.windows-username
     admin_password = var.windows-password
+    custom_data    = file("./config/settings.ps1")
   }
 
   os_profile_windows_config {
     enable_automatic_upgrades = true
     provision_vm_agent        = true
+    winrm {
+      protocol = "http"
+    }
+    # Auto-Login's required to configure WinRM
+    additional_unattend_config {
+      pass         = "oobeSystem"
+      component    = "Microsoft-Windows-Shell-Setup"
+      setting_name = "AutoLogon"
+      content      = "<AutoLogon><Password><Value>${var.windows-password}</Value></Password><Enabled>true</Enabled><LogonCount>1</LogonCount><Username>${var.windows-username}</Username></AutoLogon>"
+    }
+    # Unattend config is to enable basic auth in WinRM, required for the provisioner stage.
+    additional_unattend_config {
+      pass         = "oobeSystem"
+      component    = "Microsoft-Windows-Shell-Setup"
+      setting_name = "FirstLogonCommands"
+      content      = file("./config/FirstLogonCommands.xml")
+    }
   }
 
   tags = {
     CreatedBy = "clearcode"
     Purpose   = "Describe Terraform instruction"
   }
+
+  connection {
+    host     = azurerm_public_ip.testing.ip_address
+    type     = "winrm"
+    port     = 5985
+    https    = false
+    timeout  = "2m"
+    user     = var.windows-username
+    password = var.windows-password
+  }
 }

埋め込むと、上記のdiffのようになります。

Ansibleのインベントリを作成する

Ansibleに必要なライブラリをインストールする

Ansibleではプロビジョニング対象の情報をインベントリというファイルから取得してプロビジョニングを行います。 Windowsへプロビジョニングする際には、さらにWinRMというPythonのライブラリも必要です。

Python3で動作させる際には、venvを用いて環境をリポジトリ固有のものにします。

$ python3 -m venv management
$ source ./management/bin/activate  

により、システムから隔離されたmanagement環境に入ります。

$ pip3 install ansible pywinrm

を実行し、Ansibleとpywinrmをインストールします。

Terraformでインベントリを作成する

Terraformでローカルにファイルを作成するには、localプロバイダーをインストールします。

terraform {
  (中略)
  required_providers {
    (中略)

    local = {
      source  = "hashicorp/local"
      version = "~>1.4"
    }
  }
}

(中略)

provider "local" {
}

(2022年1月14日追記:例を最新のTerraformの仕様に合わせて更新しました)

localプロバイダーをTerraformにインストールするため、再度terraform initを実行します。

Terraformの実行中のデータを格納するdataソースを定義していきます。 また、実行が終了した時にパブリックIPアドレスを出力してくれるoutputもついでに定義していきます。

data "azurerm_public_ip" "testing" {
  name                = azurerm_public_ip.testing.name
  resource_group_name = azurerm_virtual_machine.winservtesting.resource_group_name
}

output "win10testing_instance_public_ip_address" {
  value = data.azurerm_public_ip.testing.ip_address
}

AnsibleのインベントリとPlayBookを入れるためのansibleディレクトリを作成します。

$ mkdir ansible

Ansibleのインベントリはlocalファイルリソースにてローカルに出力します。

resource "local_file" "inventory" {
  filename = "ansible/hosts"
  content  = <<EOL
[windows]
${data.azurerm_public_ip.testing.ip_address}

[windows:vars]
ansible_user=${var.windows-username}
ansible_password=${var.windows-password}
ansible_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
EOL
}

設定の適用

ここまでの設定を適用するには前回までのリソースを消しておかないといけません。

$ terraform destroy -auto-approve

を実行して前回までのリソースを削除しておきます。

再度、

$ terraform apply -auto-approve

を実行することで、ここまでに書き下した設定がAzureへ適用され、Terraformで設定した設定が流し込まれたインスタンスが立ち上がります。 ここまでの設定を流し込むことで、WinRMを用いたAnsibleによるプロビジョニングを行う準備ができたWindows Server 2019 Datacenterインスタンスが立ち上がってきます。

WinRMの有効化に成功している場合、Ansibleのwin_pingモジュールを使用するとpongが返ってきます。

$ ansible windows -i ansible/hosts -m win_ping -vvv 

# ...

0.0.0.0 | SUCCESS => {
    "changed": false,
    "invocation": {
        "module_args": {
            "data": "pong"
        }
    },
    "ping": "pong"
}

ここまでに作成したTerraformのスクリプトは https://gitlab.com/clear-code/terraform-example/-/tree/1430e3146c3a27c770fedf099cee3b79facea19b に置いてあります。

まとめ

Azure上のWindows Server 2019 DatacenterのインスタンスをWinRMを有効化してAnsibleによるプロビジョニングを実行する準備を整えるところまで複数回に分けて解説しました。 WindowsのWinRMを有効化したインスタンスを立ち上げることができれば、必要な設定を入れ込んだインスタンスを常時起動・休止されている必要はなく、必要な時に作成・不要な時に破棄することができるようになります。 クラウドサービスはとても便利ですが、必要な設定がきちんと入っているか、必要なリソースがちゃんと確保されているか、インスタンスタイプの変更をdiffで取得できるか、など管理コンソールから確認するのには一手間必要です。 EC2インスタンスやそれに準じたリソースを扱う際には、Terraformの設定に落とし込み設定変更が必要な際にはdiffとして出力することができる仕組みを整えてみてはいかがでしょうか。

  1. ここで使用しているConfigureRemotingForAnsible.ps1は、元々はAnsibleプロジェクト本体のリポジトリにありましたが、2023年7月12日付の変更ドキュメント類専用の別リポジトリに移動されました。古いsettings.ps1を使用している場合はダウンロードに使用するURLを更新する必要があります。