fbpx

Windows Server Containers を PowerShell で操作する #windows #docker

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

Windows Server Containers

前回の記事「Windows Server Containers を Docker で操作する」に引き続き、今回は PowerShell でコンテナを操作してみます。PowerShell を使う場合は、Docker デーモンは不要になります。

本稿では、以下の作業を PowerShell で行ってみたいと思います。

  • コンテナの作成
  • コンテナからコンテナイメージの作成
  • コンテナイメージのエクスポート

なお、Windows Server 2016 TP3 の環境は、前回の記事で構築したものを使用します。
/lab/11385

コンテナを作成する

まずは、インストールされているコンテナイメージを調べてみます。このイメージは、セットアップスクリプトによってインストールされたものです。

PS C:\> Get-ContainerImage
Name              Publisher    Version      IsOSImage
----              ---------    -------      ---------
WindowsServerCore CN=Microsoft 10.0.10514.0 True

このイメージから、コンテナを作成します。コンテナの名前は MyContainer にし、コマンドの戻り値(コンテナオブジェクト)を $ctn という変数で受け取ります。この変数は、後の操作で使用します。作成時に -SwitchName パラメーターを指定して、仮想スイッチに接続します。
作成されたコンテナは、停止状態となっています。

PS C:\> $ctn = New-Container -Name MyContainer -ContainerImageName WindowsServerCore -SwitchName "Virtual Switch"
PS C:\> $ctn
Name        State Uptime   ParentImageName
----        ----- ------   ---------------
MyContainer Off   00:00:00 WindowsServerCore

コンテナに追加したネットワークアダプタを確認するには、Get-ContainerNetworkAdapter を使うか、コンテナオブジェクト(この例では $ctn)の NetworkAdapters プロパティを参照することで可能です。

PS C:\> Get-ContainerNetworkAdapter $ctn
Connected                : True
DynamicMacAddressEnabled : True
Id                       : Microsoft:1F377C23-0DCA-48C7-B8EA-6FD2EB2F9112\32CDD3C5-58E3-44BD-9A50-CC7B1F3F2A2D
MacAddress               : 000000000000
Name                     : Network Adapter
SwitchId                 : 92c176c6-94c7-47f7-b371-87ebda987e25
SwitchName               : Virtual Switch
CimSession               : CimSession: .
ComputerName             : SV2016
IsDeleted                : False

コンテナ内の OS に変更を加える

コンテナを開始します。

PS C:\> Start-Container $ctn
PS C:\> $ctn
Name        State   Uptime           ParentImageName
----        -----   ------           ---------------
MyContainer Running 00:00:05.6280000 WindowsServerCore

コンテナの PowerShell session に入ります。

PS C:\> Enter-PSSession -ContainerId $ctn.Id -RunAsAdministrator
[6ff0a690-e8c]: PS C:\Windows\system32>

ユーザーを作成します。名前は CTN とし、適当なパスワードを設定します。その後、Administrators グループへ追加します。
net user(ユーザー一覧表示)でホスト名が取得できずにエラーとなっていますが、Windows コンテナの不具合(実装がまだ不完全)と思われます。

[6ff0a690-e8c]: PS C:\Windows\system32> net user /add CTN
The command completed successfully.

[6ff0a690-e8c]: PS C:\Windows\system32> net user CTN Password4Me
The command completed successfully.

[6ff0a690-e8c]: PS C:\Windows\system32> net localgroup Administrators /add CTN
The command completed successfully.

[6ff0a690-e8c]: PS C:\Windows\system32> net user
User accounts for \\       <- ホスト名が取得できていない
------------------------------------------------------------------------------
Administrator            CTN                      DefaultAccount
Guest
The command completed with one or more errors.

[6ff0a690-e8c]: PS C:\Windows\system32> net user CTN
User name                    CTN
Full Name
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never
Password last set            9/9/2015 3:30:24 PM
Password expires             10/21/2015 3:30:24 PM
Password changeable          9/9/2015 3:30:24 PM
Password required            Yes
User may change password     Yes
Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   Never
Logon hours allowed          All
Local Group Memberships      *Administrators       *Users
Global Group memberships     *None
The command completed successfully.

簡単なテキストファイルを作成します。

[6ff0a690-e8c]: PS C:\Windows\system32> echo "This is my container." > C:\Users\Public\Documents\readme.txt

[6ff0a690-e8c]: PS C:\Windows\system32> cat C:\Users\Public\Documents\readme.txt
This is my container.

適当なレジストリキーを作成します。ここでは、HKLM\SOFTWARE に CTN というキーを追加し、そこに Version = 1.0.0.0 という 値とデータを追加します。

[6ff0a690-e8c]: PS C:\Windows\system32> New-Item "HKLM:\SOFTWARE\CTN"
Hive: HKEY_LOCAL_MACHINE\SOFTWARE
Name                           Property
----                           --------
CTN

[6ff0a690-e8c]: PS C:\Windows\system32> New-ItemProperty "HKLM:\SOFTWARE\CTN" "Version" -Value "1.0.0.0" -PropertyType String
Version      : 1.0.0.0
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\CTN
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE
PSChildName  : CTN
PSDrive      : HKLM
PSProvider   : Microsoft.PowerShell.Core\Registry

コンテナを停止する

exit でコンテナの PowerShell session から抜けた後、コンテナを停止します。

[6ff0a690-e8c]: PS C:\Windows\system32> exit

PS C:\> Stop-Container $ctn
PS C:\> $ctn
Name        State Uptime   ParentImageName
----        ----- ------   ---------------
MyContainer Off   00:00:00 WindowsServerCore

停止したコンテナから、新しいコンテナイメージを作成する

先ほど停止したコンテナのオブジェクトと、イメージ名、発行者、バージョンを指定して、新しいコンテナイメージを作成します。

PS C:\> New-ContainerImage $ctn -Name MyImage -Publisher CTN -Version 1.0.0.0
Name    Publisher Version IsOSImage
----    --------- ------- ---------
MyImage CN=CTN    1.0.0.0 False

PS C:\> Get-ContainerImage -Name MyImage | Select-Object *
Publisher    : CN=CTN
Name         : MyImage
Version      : 1.0.0.0
IsOSImage    : False
ParentImage  : ContainerImage (Name = 'WindowsServerCore') [Publisher = 'CN=Microsoft', Version = '10.0.10514.0']
FullName     : CN=CTN_MyImage_1.0.0.0
CimSession   : CimSession: .
ComputerName : SV2016
IsDeleted    : False

作成したイメージでコンテナを作成する

作成したイメージでコンテナを作成します。コンテナオブジェクトは $ctn2 という変数で受け取ります。作成後、コンテナを開始して、コンテナの PowerShell session に接続します。

PS C:\> $ctn2 = New-Container -Name MyContainer2 -ContainerImageName MyImage -SwitchName "Virtual Switch"
PS C:\> Start-Container $ctn2
PS C:\> Get-Container
Name         State   Uptime           ParentImageName
----         -----   ------           ---------------
MyContainer2 Running 00:00:06.8210000 MyImage
MyContainer  Off     00:00:00         WindowsServerCore

PS C:\> Enter-PSSession -ContainerId $ctn2.Id -RunAsAdministrator
[2881d8eb-41c]: PS C:\Windows\system32>

CTN ユーザーが存在していることを確認します。Administrators グループに追加されており、パスワードの有効期限なども同じになっています。

[2881d8eb-41c]: PS C:\Windows\system32> net user CTN
User name                    CTN
Full Name
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never
Password last set            9/9/2015 3:30:24 PM
Password expires             10/21/2015 3:30:24 PM
Password changeable          9/9/2015 3:30:24 PM
Password required            Yes
User may change password     Yes
Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   Never
Logon hours allowed          All
Local Group Memberships      *Administrators       *Users
Global Group memberships     *None
The command completed successfully.

テキストファイルを確認します。

[2881d8eb-41c]: PS C:\Windows\system32> cat C:\Users\Public\Documents\readme.txt
This is my container.

レジストリキー HKLM\SOFTWARE\CTN の値とデータを確認します。Version=1.0.0.0 が設定されています。

[2881d8eb-41c]: PS C:\Windows\system32> Get-ItemProperty "HKLM:\SOFTWARE\CTN" "Version"
Version      : 1.0.0.0
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\CTN
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE
PSChildName  : CTN
PSDrive      : HKLM
PSProvider   : Microsoft.PowerShell.Core\Registry

コンテナイメージをエクスポートする

先ほど作成したコンテナイメージ MyImage をエクスポートします。エクスポートすると、ファイルシステムやレジストリへの変更がパッケージ化され、Windows ランタイム(Windows ストア)アプリパッケージ形式(.appx)で保存されます。
詳しくは、以下を参照してください。
https://msdn.microsoft.com/ja-jp/library/windows/apps/hh464929.aspx

appx ファイルは、親イメージ WindowsServerCore の差分になります。よって、他のコンテナホストへインポートする場合は、そのホスト上に WindowsServerCore イメージが予め用意されていないと、エラーになります。

PS C:\> Export-ContainerImage -Name MyImage -Path C:\

PS C:\> ls -Filter *.appx
Directory: C:\
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2015/09/09     17:13      281571897 CN=CTN_MyImage_1.0.0.0.APPX

エクスポートしたパッケージの中身を確認する

アプリパッケージの中身を確認してみます。appx は zip 形式での圧縮ファイルなので、拡張子を .zip へ変更すれば、簡単にパッケージ内部を確認できます。
または、Windows SDK に付属の makeappx.exe を使用してアンパックします。
https://msdn.microsoft.com/en-us/library/windows/desktop/hh446767(v=vs.85).aspx

拡張子を変更する方法が楽ですが、ここでは makeappx.exe を使ってみます。以下のコマンドで Windows Standalone SDK for Windows 10 のインストーラをダウンロードし、実行します。
※sdksetup.exe 実行後は、すぐにプロンプトが表示されますが、インストーラはバックグラウンドで動作しています。インストールが終わったかどうかを確認するには、sdksetup.exe のプロセスが終了したことを確認します。

PS C:\> wget -uri https://go.microsoft.com/fwlink/p/?LinkId=619296 -OutFile C:\sdksetup.exe

PS C:\> .\sdksetup.exe /features OptionId.WindowsSoftwareDevelopmentKit /q

makeappx.exe は、C:\Program Files (x86)\Windows Kits\10\bin\x64 配下にあります。これを実行して、イメージを C:\myimage へアンパックします。

PS C:\Program Files (x86)\Windows Kits\10\bin\x64> .\makeappx.exe unpack /p C:\CN=CTN_MyImage_1.0.0.0.APPX /d C:\myimage /nv
…

アンパックされたファイルの中に、readme.txt のペイロードファイルがあることを確認できます。AppManifest.xml には、コンテナイメージのバージョンや依存関係などが定義されています。

PS C:\> ls -Path C:\myimage
Directory: C:\myimage
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2015/09/09     17:18                Files
d-----       2015/09/09     17:20                Hives
-a----       2015/09/09     17:18        1836912 AppxBlockMap.xml
-a----       2015/09/09     17:18           2010 AppxManifest.xml
-a----       2015/09/09     17:20            600 tombstones.txt

PS C:\> ls -Recurse -Path C:\myimage -Filter readme.txt
Directory: C:\myimage\Files\Users\Public\Documents
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2015/09/09     17:18            264 readme.txt

PS C:\> cat C:\myimage\Files\Users\Public\Documents\readme.txt
_   _   ー‹           _ _・E           ,   __     __   __     __   _ ・E_     _ __ __     __    __ __ __     _     ___ __ __     __    __ __ __     __    __ __ __     __    __ __ __     __   _       0           T h i s   i s   m y   c o n t a i n e r .

レジストリハイブは Hives フォルダ配下にあります。Software_Delta に CTN キーが記録されています。

PS C:\> ls -Path C:\myimage\Hives
Directory: C:\myimage\Hives
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2015/09/09     17:20          20480 DefaultUser_Delta
-a----       2015/09/09     17:20          12288 Sam_Delta
-a----       2015/09/09     17:20           8192 Security_Delta
-a----       2015/09/09     17:20        1544192 Software_Delta
-a----       2015/09/09     17:20          90112 System_Delta

まとめ

PowerShell でコンテナの操作をしてみましたが、Docker とは設計思想の違いが感じられました。例えば、コンテナの起動時に、PowerShell ではコマンドの指定が不要であり、常にデタッチド・モードで起動しますが、Docker ではコンテナ OS で動かすコマンドの指定が必要です。ただし、どちらを使用しても最終的にはコンテナの起動やイメージの管理ができるので、馴染みやすい方を使用すればよいでしょう。
あと、現状では PowerShell と Docker 間でのコンテナやイメージの共有ができないので、「PowerShell で作成したイメージを、docker コマンドで Docker のレジストリへプッシュする」 といったことはできません。ここの改善にも期待したいところです。

最後に、検証環境で発生した不具合と思われる事象をまとめておきます。

  • コンテナ OS のホスト名の取得
    docker inspection, hostname コマンド, $env:COMPUTERNAME で返ってくる値が異なる。
  • 長い処理は応答が返ってこなくなる(固まる)
    Get-WindowsFeature, Add-WindowsFeature など。機能の追加ができなかった。
    wsc_02_001
  • リモートデスクトップ接続
    https://msdn.microsoft.com/virtualization/windowscontainers/about/work_in_progress
    このページの Accessing windows server container with Remote Desktop を参考に試したが、以下のエラーで接続できず。
    wsc_02_002
  • コンテナ OS で netstat コマンドを実行すると、ホスト OS や別のコンテナ OS の状態も返ってくる。
    [2881d8eb-41c]: PS C:\Windows\system32> netstat -ano
    Active Connections
    Proto Local Address Foreign Address State PID
     TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 2220
     TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 3140
     TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 632
     TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
     TCP 0.0.0.0:2179 0.0.0.0:0 LISTENING 1936
     TCP 0.0.0.0:3389 0.0.0.0:0 LISTENING 5176
     TCP 0.0.0.0:3389 0.0.0.0:0 LISTENING 860
     TCP 0.0.0.0:3389 0.0.0.0:0 LISTENING 4356
    

参考文献

Windows Containers
https://msdn.microsoft.com/virtualization/windowscontainers/containers_welcome
アプリパッケージと展開
https://msdn.microsoft.com/ja-jp/library/windows/desktop/hh464929.aspx
レジストリ構造
https://msdn.microsoft.com/ja-jp/library/Cc776231(v=WS.10).aspx

新規CTA