Windows Server の AMI を作成する時に必要な sysprep を実行すると、デフォルトではタイムゾーンが UTC でシステムロケールが en-US になってしまうので、sysprep の応答ファイルを用意して変更してみます。
AWS のドキュメントに sysprep と応答ファイルについて記載があります。
SystemLocale と TimeZone を変更して、sysprep を実行すれば上手くいきそうな感じです。
EC2 の Windows Server AMI を使うと、デフォルトの応答ファイルが予め用意されているので、それに対して変更を行ってから sysprep をすることにします。User Data で実行したいので PowerShell で書きます。
PowerShell で名前空間付きの XML を扱う場合の方法は、以下のページを参考にしました。
Sysprep の応答ファイルは 2012 R2 と 2016 で特に変わっていないので、関数として切り出しておきました。実際に書いたコードは以下のような感じです。
function Update-SysprepAnswerFile($answerFile) { [xml] $document = Get-Content $answerFile -Encoding UTF8 $ns = New-Object System.Xml.XmlNamespaceManager($document.NameTable) $ns.AddNamespace("u", $document.DocumentElement.NamespaceURI) $settings = $document.SelectSingleNode("//u:settings[@pass='oobeSystem']", $ns) $international = $settings.SelectSingleNode("u:component[@name='Microsoft-Windows-International-Core']", $ns) $shell = $settings.SelectSingleNode("u:component[@name='Microsoft-Windows-Shell-Setup']", $ns) $international.SystemLocale = "ja-JP" $international.UserLocale = "ja-JP" $shell.TimeZone = "Tokyo Standard Time" $document.Save($answerFile) }
XPath で応答ファイルの要素を引っ張ってきて、要素の値を書き換えて保存するだけのコードです。なんとなく SystemLocale だけではなく UserLocale も ja-JP に変更しておきました。
TimeZone の値は tzutil で指定するものと同じなので、少し書き方に注意したいです。
Windows Server 2012 R2 までは EC2Config を使って sysprep を実行しますが、Windows Server 2016 では EC2Launch を使う形に変更されたので、それぞれの OS 向けにスクリプトを変更して記載しておきます。
Windows Server 2012 R2
EC2ConfigService の中に存在する sysprep2008.xml が応答ファイルです。sysprep 自体も ec2config.exe にパラメータを渡して実行します。
function Update-SysprepAnswerFile { # 省略 } Update-SysprepAnswerFile "$env:ProgramFiles\Amazon\Ec2ConfigService\sysprep2008.xml" # Execute sysprep & "$env:ProgramFiles\Amazon\Ec2ConfigService\ec2config.exe" -sysprep
割とシンプルなスクリプトになりました。このスクリプトを実行して作成した AMI を使ってインスタンスを起動すると、システムログに設定した言語やタイムゾーンの情報が表示されています。
ちゃんと ja-JP Tokyo Standard Time になっています。
リモートデスクトップで接続して確認しても、設定が変更されていることが確認できました。
日本語言語パックをインストールしてから UILanguage を設定すると日本語にも出来る気がします。
Windows Server 2016
EC2Launch では PowerShell ベースになっているので、手順が少し変わっています。公式ドキュメントに sysprep の手順が書いてあるので、まずは熟読しておきました。
応答ファイルのパスも変わっているので、少し注意したいです。特に InitializeInstance.ps1 の Schedule パラメータを忘れないようにしたいです。ダメなイメージが完成します。
function Update-SysprepAnswerFile { # 省略 } Update-SysprepAnswerFile "$env:ProgramData\Amazon\EC2-Windows\Launch\Sysprep\Unattend.xml" # Execute sysprep cd "$env:ProgramData\Amazon\EC2-Windows\Launch\Scripts" .\InitializeInstance.ps1 -Schedule .\SysprepInstance.ps1
2012 R2 の時と同じようにイメージを作成して、新しくインスタンスを作成するとシステムログに設定した言語とタイムゾーンが表示されているので、変更されてるのが分かります。
そしてリモートデスクトップで接続して、システムロケールが変わっていることを確認しました。
システムロケールの設定は再起動が必要になるので自動化がいまいちやりにくい部分でしたが、sysprep を使って AMI を作成する場合では User Data を使って自動化が行えます。
以前書いた Elastic Beanstalk 向けの Custom AMI と同じように CI で作れそうです。
特に Elastic Beanstalk はベースとなる AMI を変更できないので、User Data を使って Custom AMI を作成しないと辛い部分が出てきそうです。ebextensions は割とすぐに限界が来ました。