しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

Windows Server Containers で利用する Docker Image のバージョン管理が難しい

最近はまた Windows Server Containers の実運用に関して、いろいろと考えたり調べたりしているのですが、Windows では絶対に避けられないものとして Windows Update があります。

そして現時点での Windows Server Containers には以下のような要件があります。

Windows Server コンテナーは、ビルド番号が異なると起動をブロックされます (例: 10.0.14300.1030 (Technical Preview 5) と 10.0.14393 (Windows Server 2016 RTM))。 ビルド番号が一致し、リビジョン番号が異なる場合は、起動をブロックされません (例: 10.0.14393 (Windows Server 2016 RTM) と 10.0.14393.206 (Windows Server 2016 GA))。 ただし、技術的にはブロックされませんが、これは状況によっては正しく機能しない可能性がある構成であるため、運用環境ではサポートできません。

Windows コンテナーの要件 | Microsoft Docs

ドキュメントの内容を解釈すると、Windows Server Containers ではリビジョンまでホストとコンテナのバージョンを一致させないと、正しく動かない可能性があるし運用環境では実質使えないということでしょう。

ここで Docker の罠が出てくるわけです。普通に microsoft/windowsservercore と指定すると latest タグのイメージが落ちてくるので、リビジョンはその時の最新になり固定できません。現時点では面倒でもタグまでちゃんと指定するべきということなのでしょう。

# Windows Server Core のイメージを利用する
FROM microsoft/windowsservercore:10.0.14393.953

# IIS までインストールされたイメージを利用する
FROM microsoft/iis:windowsservercore-10.0.14393.953

# ASP.NET 4.6.2 までインストールされたイメージを利用する
FROM microsoft/aspnet:4.6.2-windowsservercore-10.0.14393.953

当然ながら Windows Update でリビジョンが変わった場合には、同様に変更する必要があります。

オンプレの仮想環境であれば、自分でバージョンやアップデートのタイミングをある程度決められるので latest でも良いかもしれないですが、Azure や AWS の場合は少し注意が必要そうです。

Azure の場合

Azure にある Windows Server 2016 with Containers を利用すると、予め Windows Server Core と Nano Server が pull された状態で起動することが出来ますが、タグが latest になっているので扱いにくいです。

最近の Windows Server Core だと多少は差分が利用されるみたいなので、5GB 落とし直しにはならないみたいですが時間はかかります。

f:id:shiba-yan:20170321211846p:plain

Dockerfile で latest を指定したイメージを実行しようとすると、イメージを作成した時点での latest になるので奇跡的にバージョンが一致していないと pull し直しになってしまいそうです。

ある意味公式である Azure VM のイメージがこれだと、正直なところ不安になってきます。

AWS の場合

EC2 の Windows Server 2016 Base with Containers ではイメージが pull されていないので、そのまま ECS のベースイメージとして使うと全てのインスタンスで pull が走ってしまって時間がかかります。

予め pull 済みの AMI を作っておいた方が良さそうです。User Data で pull と sysprep までやらせます。

function Get-OSVersion() {
    $buildLabEx = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\').BuildLabEx
    $osBuild = $buildLabEx.Substring(0, $buildLabEx.IndexOf(".", 6))

    return "10.0." + $osBuild
}

docker pull microsoft/windowsservercore:$(Get-OSVersion)
docker pull microsoft/iis:windowsservercore-$(Get-OSVersion)
docker pull microsoft/aspnet:4.6.2-windowsservercore-$(Get-OSVersion)

docker pull microsoft/nanoserver:$(Get-OSVersion)
docker pull microsoft/iis:nanoserver-$(Get-OSVersion)

cd "$env:ProgramData\Amazon\EC2-Windows\Launch\Scripts"
.\InitializeInstance.ps1 -Schedule
.\SysprepInstance.ps1

ホストとコンテナのバージョンは合わせる必要があるので、頑張ってレジストリから取得するようにしています。ECS クラスターを作成するのは面倒だったので、普通に EC2 のインスタンスを立ち上げました。

docker images を実行すると、各ベースとなるイメージが pull 済みになっているのが確認できます。

f:id:shiba-yan:20170321223738p:plain

AMI で用意されている Windows Server 2016 のバージョンと同じになっていることも確認できました。

f:id:shiba-yan:20170321224056p:plain

課題としては Windows Update のタイミングでリビジョンが上がるという点ですが、こればっかりは Windows Update の時に AMI を作り直して入れ替えるぐらいしかない気がしました。

リビジョンをまで指定しないといけないのは非常に扱いにくいですが、カーネルを共有している以上仕方ない部分だと思いました。docker pull が賢くなればましになるかもしれないですが、今はこれで精いっぱい。