はじめに
今回はTerraform for さくらのクラウドを用いてWindows Serverの展開を自動化する方法をご紹介します。
さくらのクラウドではWindows Serverのセットアップを行うにはコントロールパネルからコンソール接続を行う必要がありましたが、
この方法を使えばterraform
コマンドだけで一気に展開可能です。
なお、今回の方法は残念ながらリソースマネージャーには非対応です。
terraform
コマンドを直接使う方向けとなっています。
背景
まずはさくらのクラウドでのWindows Serverプランの扱いについて確認しておきます。
さくらのクラウドのWindows Serverプラン
さくらのクラウドではWindows Serverプランが提供されています。
Datacenter EditionやRDS、さらにはOffice付きのものやSQLServerインストール済みのものまで様々なプランがあります。
さくらのクラウドのWindows Serverプランの仕様
便利なWindows Serverプランなのですが、その他のLinux系OSなどとは異なる仕様がいくつかあります。
例えばディスクサイズは100GB以上が要求されることなどがあります。
その中でも構築の自動化の際に大きく関わってくる仕様として「ディスクの修正が一部項目のみ対応」というものがあります。
「ディスクの修正」とは
さくらのクラウドでは各サーバ固有の設定(グローバルIPアドレスやホスト名、管理者パスワードなど)はディスクの修正という機能で各サーバ(のディスク)に設定されます。
SSH用の公開鍵の登録やスタートアップスクリプトなどもこのディスクの修正で反映できるようになっています。
設定できる項目は以下の通りです。
しかしWindows Serverプランではこのディスクの修正機能が一部のみしか利用できないという仕様になっています。
Windows Serverプランでのディスクの修正機能
Windows Serverプランの場合、ディスクの修正機能で設定可能な項目は以下のみとなっています。
- IPアドレス、ネットマスク、デフォルトゲートウェイ
また、パブリックアーカイブからの新規作成時のみディスク修正が行えるという制限もあります。
つまり、Windows Serverプランを利用する場合はサーバ作成後にコントロールパネルからサーバのコンソールを利用して管理者パスワードの設定などの初期設定を手作業で行う必要があります。
(一応VNCも使えます。usacloudからだとusacloud server vnc <your-server-name>
でOK)
これが数台程度であれば良いですが、数十〜数百台となってくるとブラウザから手作業で構築するのは非常に大変な作業となります。
そこで何か自動化する手段は無いか、、、ということで自動化する方法を考えました。
Windows展開の自動化といえばsysprep+応答ファイル
Windows環境構築の自動化といえばsysprep+応答ファイルという方法がありますね。
実はさくらのクラウドで提供されているWindowsパブリックアーカイブはISOイメージからのインストール直後の状態ではなく、NIC用のVirtIOドライバなどがインストールされた状態となっており、起動直後はわずかな入力を行うだけで直ぐに利用できる状態となります。 (おそらくさくらのクラウド側であらかじめある程度構築後にsysprepされた状態になっているのでしょう)
なので、応答ファイルもごく一部の項目のみ作成すればOKとなっています。 具体的には最低限以下の設定をすれば直ぐにリモートデスクトップ接続ができる状態に持っていけます。
これにchocolatey
などをインストールするスクリプトを仕込めば一気に環境構築できそうです。
応答ファイルはサーバにどうやって渡す? -> ISOイメージを使う
応答ファイルを作成しておけば構築の自動化はできそうですが、サーバ作成時にどうやって応答ファイルを渡せば良いでしょうか? いくつか方法はありますが、さくらのクラウドではISOイメージのアップロードに対応していますのでこれを利用してあげれば良いでしょう。
以下のドキュメントにも記載がありますが、応答ファイルをUnattend.xml
という名前でリムーバブルメディアのドライブのルートにおいておけば初回起動時に参照してくれます。
なので、応答ファイルを格納したISOイメージを作成し、サーバ作成時にISOイメージを挿入した状態で起動すれば良さそうですね。
Terraform for さくらのクラウドならISOイメージも一発構築
Terraform for さくらのクラウドはISOイメージの作成もサポートしています。
ISOイメージの作成処理はGo言語のみで実装していますのでTerraformを実行するのがWindowsの場合でも問題なくISOイメージの作成が行えます。
また、ISOイメージに格納する応答ファイルUnattend.xml
についてはTerraformの変数やテンプレート機能を活用すれば作成できますね。
ということで実際にTerraform for さくらのクラウドで自動化を行なってみます。
構築
Windows Server向け環境構築用のtfファイル
tfファイルは以下のようになります。
### 概要 # Windows Serverの初期設定を行うテンプレート # # このテンプレートはWindows Serverの管理者パスワードの設定や任意のスクリプトの実行を行うテンプレートです。 # 初期設定は応答ファイル(Unattend.xml)を格納したISOイメージをサーバにアタッチすることで行なっています。 # ### 変数定義 # サーバ管理者(Administrator)のパスワード variable password {} locals { #********************************************* # プロビジョニング #********************************************* # サーバ上で実行したいコマンドを指定 run_commands = [ # パッケージマネージャー"chocolatey"のインストール "powershell -Command \"Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))\"", # chocolateyでChromeをインストール "C:\\ProgramData\\chocolatey\\bin\\choco.exe install -y googlechrome", ] #********************************************* # サーバ/ディスク #********************************************* # 利用するアーカイブ種別: 指定できる値についてはTerraform for さくらのクラウドのマニュアルを参照してください os_type = "windows2016" # サーバ名 server_name = "windows-server" # ホスト名(コンピューター名) host_name = "windows-server" # サーバ コア数 server_core = 2 # サーバ メモリサイズ(GB) server_memory = 4 # ディスクサイズ(100GB以上) disk_size = 100 } ### 構成構築 # 利用するアーカイブ data sakuracloud_archive "windows" { os_type = "${local.os_type}" } # ディスク resource "sakuracloud_disk" "disk" { name = "${local.server_name}" size = "${local.disk_size}" source_archive_id = "${data.sakuracloud_archive.windows.id}" lifecycle { ignore_changes = ["source_archive_id"] } } # サーバ resource "sakuracloud_server" "server" { name = "${local.server_name}" disks = ["${sakuracloud_disk.disk.id}"] core = "${local.server_core}" memory = "${local.server_memory}" cdrom_id = "${sakuracloud_cdrom.settings.id}" } # ISOイメージ(応答ファイル用) resource sakuracloud_cdrom "settings" { name = "${local.server_name}" # 単一ファイルを内包するISOイメージを作成する content = "${local.unattend_body}" content_file_name = "Unattend.xml" } # 応答ファイルの組み立て locals { command_elm_format = <<EOL <SynchronousCommand wcm:action="add"> <Order>$${index}</Order> <CommandLine>$${body}</CommandLine> </SynchronousCommand> EOL commands_format = <<EOL <FirstLogonCommands> %s </FirstLogonCommands> EOL commands_body = "${length(local.run_commands) > 0 ? format(local.commands_format, join("", data.template_file.run_commands.*.rendered)) : "" }" } data template_file "run_commands" { count = "${length(local.run_commands)}" template = "${local.command_elm_format}" vars = { index = "${count.index + 1}" body = "${local.run_commands[count.index]}" } } locals { unattend_body = <<EOL <?xml version="1.0" encoding="utf-8"?> <unattend xmlns="urn:schemas-microsoft-com:unattend"> <settings pass="oobeSystem"> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <OOBE> <HideEULAPage>true</HideEULAPage> </OOBE> <UserAccounts> <AdministratorPassword> <Value>${var.password}</Value> <PlainText>true</PlainText> </AdministratorPassword> </UserAccounts> <AutoLogon> <Password> <Value>${var.password}</Value> <PlainText>true</PlainText> </Password> <Enabled>true</Enabled> <LogonCount>1</LogonCount> <Username>Administrator</Username> </AutoLogon> ${local.commands_body} </component> <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <InputLocale>0411:E0010411</InputLocale> <SystemLocale>ja-JP</SystemLocale> <UILanguage>ja-JP</UILanguage> <UILanguageFallback>ja-JP</UILanguageFallback> <UserLocale>ja-JP</UserLocale> </component> </settings> <settings pass="specialize"> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ComputerName>${local.host_name}</ComputerName> </component> </settings> </unattend> EOL }
あとはterraform apply
を実行すればプロビジョニング済みのWindows Serverの出来上がりです。
各要素の解説
一応各要素について解説しておきます。
ISOイメージと応答ファイルの作成
ISOイメージは以下のように定義することで応答ファイルを格納したイメージの作成が可能です。
# ISOイメージ(応答ファイル用) resource sakuracloud_cdrom "settings" { name = "${local.server_name}" # 単一ファイルを内包するISOイメージを作成する場合 content = "${local.unattend_body}" content_file_name = "Unattend.xml" }
ポイントはcontent
とcontent_file_name
の部分ですね。
Terraform for さくらのクラウドのISOイメージリソースはすでに存在するISOイメージのアップロードも可能ですが、文字列を指定して単一のファイルを内包するISOイメージの作成が行えるようになっています。
content
に作成するファイルの内容を、content_file_name
に作成するファイル名を指定すればOKです。
(なお、content_file_name
に指定した値はボリュームラベルとしても利用されます。)
ここではファイル名にUnattend.xml
を指定してますね。
content
には応答ファイルのXMLを組み立てた結果を格納した変数が指定されています。
応答ファイルには以下の内容を記載しています。
- EULA(ソフトウェア仕様許諾)ヘの同意
- ロケール/キーボードの設定
- Administratorのパスワードの設定
- コンピューター名の変更
- 指定のスクリプトを初回ログオン時に実行
- サーバ作成後に1回だけ自動ログイン
実行したいスクリプトはLocalValuesのrun_commands
に指定しています。
この例ではChocolateyをインストールし、chocolateyを用いてChrome
をインストールしています。
好みに応じてこの辺りを編集してみてください。
サーバへのISOイメージの挿入
これはサーバリソースの定義にISOイメージのIDを指定するだけでOKです。 例では以下のように指定しています。
# サーバ resource "sakuracloud_server" "server" { # ... cdrom_id = "${sakuracloud_cdrom.settings.id}" }
注意点
ISOイメージは安価とはいえお金がかかります(現時点では月額108円)。
サーバ構築後はISOイメージは利用しませんので削除してしまってもOKです。
削除する場合はtfファイルからISOイメージ関連の記述をコメントアウト & applyなどしておきましょう。
応用: WinRMを有効化してAnsibleやTerraformのプロビジョナーを利用する
簡単なスクリプト程度なら先程のrun_commands
に実行したいコマンドを書いていけばいいですが、
少し複雑なことをやる場合はやはりAnsibleなどのツールを利用するのが楽だと思います。
そのためにはWinRM
を有効にする必要があります。
この場合、以下のようにtfファイルに記載すれば良いでしょう。
#********************************************* # プロビジョニング #********************************************* # サーバ上で実行したいコマンドを指定 run_commands = [ #***************************************************************** # WinRMを有効化(5985:httpと5986:httpsポートが解放される) #***************************************************************** "powershell -Command \"Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile ConfigureRemotingForAnsible.ps1\"", "powershell -Command \"powershell ConfigureRemotingForAnsible.ps1\"", "powershell -Command \"Remove-Item -path ConfigureRemotingForAnsible.ps1 -force\"", ]
この記述をしておけば、Ansibleが提供しているスクリプト(powershell)を利用してWinRMを有効化できます。
WinRMさえ有効になってしまえば以下のようにTerraformのプロビジョナーも利用できます。
# サーバ resource "sakuracloud_server" "server" { name = "${local.server_name}" disks = ["${sakuracloud_disk.disk.id}"] core = "${local.server_core}" memory = "${local.server_memory}" cdrom_id = "${sakuracloud_cdrom.settings.id}" # > WinRMを有効化しておけばプロビジョナーも利用可能 provisioner "remote-exec" { # 接続情報の指定 connection { type = "winrm" host = "${sakuracloud_server.server.ipaddress}" port = 5986 https = true insecure = true user = "Administrator" password = "${var.password}" } # サーバ上で実行するコマンド inline = [ "echo foobar", ] } }
Ansibleを利用する場合はfile
リソースなどで以下のようにインベントリファイルを作成しておくと楽でしょう。
resource "local_file" "foo" { filename = "${path.module}/hosts" content = <<EOL [windows] ${sakuracloud_server.server.ipaddress} [windows:vars] ansible_user=Administrator ansible_password=${var.password} ansible_port=5986 ansible_connection=winrm ansible_winrm_server_cert_validation=ignore EOL }
あとはansible -i hosts windows -m win_ping
みたいに実行できるはずです。
(これをlocal_exec
プロビジョナーで実行してもいいですね)
終わりに
これでWindows環境の展開が楽になりますね!! 是非ご活用ください!!!
以上です。