本日も乙

ただの自己満足な備忘録。

Windows on GCEにおける起動/停止スクリプトの実行方法についての調査

コンテナが流行っているこのご時世、GCEでかつWindowsマシンというマイナーな話題ですが、現行システムで動かしている以上、色々調べなければならないこともあるわけでして。
最近躓いているのが、Windows VMマシンで起動および停止スクリプトが、GCEの起動・停止時に実行してくれないということです。このVMマシンは、GCPで最初から提供されているイメージではなくて、CloudEndureでEC2から持ってきたもの、かつ秘伝のタレが仕込んでいるものなので、ピュアなイメージと比較して色々挙動が異なることがしばしばあります。通常のVMマシンであれば悩まくても良いことで躓いているので時間がもったいないと思いつつも動かない原因を突き止めたいという欲求もあるので、この機に調べてみました。

目次

compute-image-windows

Windowsのイメージ作成やメタデータスクリプトに関するソースはこちらにあります。

github.com

Instance Setup

CloudEndureなど外部からWindowsマシンを移行してきたら、この工程が必要になります。
instance_setup.ps1 を実行することで、以下の設定をしてくれます。

  • Set the hostname to the instance name.
  • Runs user provided 'specialize' startup script.
  • Activates Windows using a KMS server.
  • Sets up RDP and WinRM to allow remote login.

https://github.com/GoogleCloudPlatform/compute-image-windows#instance-setup

instance_setup.ps1 を見ればわかりますが、なにやらオプションが指定できます。
windeploy.cmd を見ると、以下のように instance_setup.ps1 を実行しています。

%WinDir%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File "C:\Program Files\Google\Compute Engine\sysprep\instance_setup.ps1" -specialize

-specialize オプションを指定することで、ホスト名の変更やsysprepによる初期化、Windowsライセンス認証、RDP・WinRMの設定をしてくれます。

GCEMetadataScripts

GCEの起動/停止スクリプトを司るのがこの GCEMetadataScripts です。
ソースはこちらになります。
compute-image-windows/main.go at master · GoogleCloudPlatform/compute-image-windows

Go言語で書かれており、ビルドしたものが C:\Program Files\Google\Compute Engine\metadata_scripts\GCEMetadataScripts.exe になります。

これを直接実行するのではなく、ラッパースクリプト経由で実行します。

起動時

配置場所 : C:\Program Files\Google\Compute Engine\metadata_scripts\run_startup_scripts.cmd
ソース :compute-image-windows/run_startup_scripts.cmd at master · GoogleCloudPlatform/compute-image-windows

停止時

配置場所 : C:\Program Files\Google\Compute Engine\metadata_scripts\run_shutdown_scripts.cmd
ソース :compute-image-windows/run_shutdown_scripts.cmd at master · GoogleCloudPlatform/compute-image-windows

実は、これらのスクリプトはGCEインスタンスが起動していても、実行が可能です。
メタデータに登録している起動・停止の設定をデバッグしたい場合は、GCEインスタンスを起動・停止することなく、これらのスクリプトを実行することでできてしまいます。

Windows起動時に起動スクリプトが実行されるまで

GCEインスタンスが起動した際、C:\Program Files\Google\Compute Engine\metadata_scripts\run_startup_scripts.cmd がどうやって呼び出されるのかについて説明します。

といっても、メタデータスクリプトのインストールスクリプトを見れば一発でわかります。

compute-image-windows/metadata_scripts_install.ps1 at master · GoogleCloudPlatform/compute-image-windows の15, 23行目を引用します。

$install_dir = "${env:ProgramFiles}\Google\Compute Engine\metadata_scripts"
...
(省略)
...
& schtasks /create /tn GCEStartup /tr "'${install_dir}\run_startup_scripts.cmd'" /sc onstart /ru System /f

つまりは、 GCEStartup という、Windowsが起動したら run_startup_scripts.cmd を実行するタスクスケジューラのタスクを作成しているだけです。

Windows停止時に停止スクリプトが実行されるまで

次に停止スクリプトが実行される流れを見ていきます。タスクスケジューラでは、シャットダウン時にスクリプトを動かすことができないため、代わりにグループポリシーで設定をします。

compute-image-windows/metadata_scripts_install.ps1 at master · GoogleCloudPlatform/compute-image-windows の25〜43行目を引用します。

$gpt_ini = "${env:SystemRoot}\System32\GroupPolicy\gpt.ini"
$scripts_ini = "${env:SystemRoot}\System32\GroupPolicy\Machine\Scripts\scripts.ini"
if ((Test-Path $gpt_ini) -or (Test-Path $scripts_ini)) {
  return
}

New-Item -Type Directory -Path "${env:SystemRoot}\System32\GroupPolicy\Machine\Scripts" -ErrorAction SilentlyContinue

@'
[General]
gPCMachineExtensionNames= [{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}]
Version=1
'@ | Set-Content -Path $gpt_ini -Encoding ASCII

@'
[Shutdown]
0CmdLine=C:\Program Files\Google\Compute Engine\metadata_scripts\run_shutdown_scripts.cmd
0Parameters=
'@ | Set-Content -Path $scripts_ini -Encoding ASCII

C:\Windows\System32\GroupPolicy\gpt.ini でグループポリシーの設定を、 C:\Windows\System32\GroupPolicy\Machine\Scripts\scripts.ini でシャットダウン時の設定をしています。
これらの詳しい説明は以下のブログが詳しく解説してくれています。ブログ記事はログオン・ログオフ時ですが、シャットダウンも同じです。

blog.shibata.tech

まとめ

Window on GCEにおける起動/停止スクリプトの挙動について調べてみました。GCE独自の機能かと思いきやタスクスケジューラやグループポリシーといったWindowsの機能を活用していました。調べていくことでWindowsの知識も少し深まりました。

参考文献

編集後記

弊社は1/4から仕事初めでした。電車も空いてて快適だったのですが、昨日は満員電車で新年早くも心が摩耗しました。私の性格上、自宅でのリモート作業だと効率が落ちるので代わりに近所にサテライトオフィスが欲しいです。