Windows Server 2016およびWindows 10 バージョン1607からは、Dockerのサポートが追加されました。WindowsがDockerに対応したことで、“デスクトップアプリをDockerでコンテナ化したい”という声を聞いたことがありますが、実現不可能なことです(少なくとも現時点では)。チャレンジすることは止めませんが、無駄な努力に終わると思います。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
Dockerの技術は、主にクラウドアプリやサービスの開発現場で、開発とデプロイのスピードアップを図るために使用される技術です。GUIを持つデスクトップアプリのコンテナ化はそもそも想定されていません。
Linuxデスクトップの場合、X Window Systemの技術を利用してDockerコンテナ側でアプリケーション(Xクライアント)を実行し、Linuxデスクトップ側(Xサーバ)でそのGUIを表示するということは可能なようです(実際に試したことはありません)。
例えば、この方法でWebブラウザをDockerコンテナで動かすということができるようです。これは興味深いアイデアですが、Linuxデスクトップ側のXサーバに完全に依存しているため、完全なGUIアプリのコンテナ化とはいえないでしょう。
WindowsでGUIアプリを実行するには、ローカルコンソールに対話的にログオンするか、リモートデスクトップ接続のセッションにログオンしてデスクトップと対話する(あるいは「Microsoft RemoteApp」プログラムを通して対話する)必要があります。Windowsの現在の実装では、ローカルの対話的なログオンとリモートデスクトップ接続の両方が「Remote Desktop Services」(TermService)に依存しています。
以下の画面1は、「Windows Server, version 1909」で構築したDockerコンテナホストで、Windows Server Core バージョン1909のベースOSイメージ(mcr.microsoft.com/windows/servercore:1909)のWindowsコンテナを実行しているところです。
Remote Desktop Services(TermService)のサービスは停止状態で、起動しようとしてもスタートアップが無効化されていて失敗します。Server(lanmanserver)サービスやWindows Defender Firewall(mpssvc)サービスも無効化されているか機能しません。
そのため、Windowsコンテナはファイル共有を提供することもできませんし、「Windows Defenderファイアウォール」による保護もありません(WindowsコンテナはNATネットワークとホスト側のWindows Defenderファイアウォールで保護されます)。この制約はライセンス上の制約なのか、技術的な制約なのか分かりません。
次に画面2を見てください。同じように実行したWindowsコンテナとコンテナホストのそれぞれのプロセス一覧を表示したものです。GUIを利用できるコンテナホスト側では、Windows Sysinternalsの「Process Explorer」(procexp.exe)を使用しました。GUIを使用できないWindowsコンテナでは「PsList」(pslist.exe)を使用しています。
なお、Windowsコンテナ内でWindows Sysinternalsのツールを実行する場合は、初回実行時の「License Agreement」ウィンドウが表示されないように、「-accepteula」オプションを追加する必要があります。そうしないと、異次元の世界にダイアログボックスが表示され、返ってこないでしょう(異次元の世界は冗談です)。
「プロセス分離モード」(以前は「Windows Serverコンテナ」と呼ばれていたもの)でWindowsコンテナを実行すると、ホスト側で「Wininit.exe」(Windowsスタートアップアプリケーション)プロセスが新たに生成され、コンテナのユーザー環境が準備されます。
最終的に「docker run」コマンドに指定したコンテナで実行するコマンド(この例の場合は「cmd.exe」)は、新たな「Wininit.exe」のプロセスツリーの中に生成される「CExecSvc.exe」プロセスのさらに子/孫プロセスとして実行されます。ホスト側のコンテナ用の「Wininit.exe」のプロセスツリーは、プロセスIDを含め、コンテナ側に見えるプロセスツリーと一致しています。
ただし、重要な点が幾つかあります。このプロセスツリーには、対話型ログオンとログオフを担当する「winlogon.exe」(Windowsログオンアプリケーション)プロセスが存在しません。また、デスクトップとウィンドウの描画と合成を担当する「dwm.exe」(デスクトップウィンドウマネージャー)も存在しません。つまり、コンテナには対話的にログオンする方法も、デスクトップも存在しないのです。
WindowsコンテナのベースOSイメージとしては、「Windows Server Core」(mcr.microsoft.com/windows/servercore)と「Nano Server」(mcr.microsoft.com/windows/nanoserver)があります。「Windows Server 2019(1809)」がリリースされたときから、「Windows(mcr.microsoft.com/windows)」という巨大なイメージが利用可能になりました。このイメージでWindowsコンテナを実行し、ゲストOSの情報を調べてみると、「Windows 10 Enterprise」のイメージであり、Remote Desktop Servicesは実行中の状態でした。
また、Windows Server 2019(1809)のコンテナ関連の新機能の1つに、Docker Engine 19.03以降におけるWindowsコンテナでのGPUデバイスのサポートがあります。
この2つの話を目にすると、Windows 10 Enterpriseのデスクトップ全体、あるいはGUIアプリのコンテナ化の可能性について期待を高める人がいるかもしれません。
しかし残念でした。Windowsイメージでは、Remote Desktop Servicesは実行中の状態でしたが、ポート3389ではリスンしていない状態でした。
レジストリを見ると「fDenyTSConnections」でリモート接続が無効になっていたので、有効化した上でサービスを再起動してみましたが、ポート3389でリスンすることはありませんでした(画面3)。そして、GPUデバイスのサポートは、機械学習の高速化などを目的とした、GPUプログラミングのためのものです。決してグラフィックス表示を想定したものではありません。
Windowsイメージの用途は以下の公式ドキュメントで説明されていますが、Windows Server CoreのWindowsコンテナでアプリを開発するには解決できない依存関係がある場合に、完全なWindows APIセットを提供するものです。
リモートデスクトップ接続以外に、ネットワーク経由でWindowsコンテナのOS環境にリモート接続(もうGUIは関係なく)する方法がないか、幾つか試してみました。
Windows Server 2019(1809)からは「OpenSSH Server」がオプション機能としてサポートされましたが、Windows Server CoreやWindowsイメージのWindowsコンテナにインストールしようとしても拒否されました(画面4)。
「PowerShell Remoting」で接続できないものかと、ホスト側とコンテナ側の両方を構成し、コンテナ側に管理者アカウントを新規作成して試してみましたが、「Access is denied」で拒否されました(画面5)。
ちなみに、LinuxコンテナにPowerShell CoreとPowerShell Remotingのための関連コンポーネントをセットアップしてみたところ、Windows PowerShellからLinuxコンテナのPowerShell CoreにPowerShell Remotingで接続することは可能でした。興味のある方は筆者の個人ブログを参考にしてください。
実は、この失敗のときに初めて知ったのですが、Windows Server 2016からのHyper-V仮想マシンに対する「PowerShell Direct」機能は、Windowsコンテナにも対応していました。Hyper-V仮想マシンの場合は、「Enter-PSSession」コマンドレットや「Invoke-Command」コマンドレットで「-ComputerName」の代わりに「-VMName」または「-VMId」オプションで仮想マシンを指定することで、内部的なチャネルを通じてゲストOSのPowerShellセッションに接続することができます。
これらのコマンドレットは「-ContainerId」オプションにも対応しており、コンテナID(「docker ps」ではなく、「docker run -d」や「docker ps --no-trunc」で取得できる完全なコンテナID)を指定することで、実行中のWindowsコンテナ(Nano Serverは不可)にPowerShell Directで接続することができました(画面6)。しかし、これはネットワーク経由ではないので、今探している方法ではありません。
最後に、古いバージョンの「VNC Server」を試してみました。古いバージョンで試したのは、単にサイレントインストールの方法がすぐに判明したからです。GUIのないコンテナではGUIインストーラーは使えないので、インストール作業はコマンドラインだけで完結できるものである必要があります。サイレントインストールの説明は省きますが、結果は漆黒の小さな画面に接続できただけでした(画面7)。通常は、ローカルコンソールのログオン画面やデスクトップ(ログオン中の場合)に接続することになりますが、ログオン画面が存在しないのでしょう。
注意点として、WindowsコンテナのベースOSイメージを使用する際には、以下のMicrosoftのライセンス条項に従う必要があります。このライセンス条項は、Windowsコンテナの「C:\License.txt」でも確認できます。
Docker DesktopをインストールしたWindows 10では、WindowsコンテナのベースOSイメージを上限なく実行できますが、それが許可されるのはテストと開発目的のみです。仮にWindowsコンテナでGUIアプリケーションをコンテナ化できたとしても(不可能ですが)、それをDocker Desktopで実行してテストや開発目的以外で使うことは許可されていません。念のため。
GUIアプリをコンテナ化する目的が“セキュリティの分離”であるなら、Windows 10の「Windows Defender Application Guard(WDAG)」や「Windowsサンドボックス」のコンテナ技術が既に存在します(どちらもDockerのコンテナとは関係ありません)。
岩手県花巻市在住。Microsoft MVP:Cloud and Datacenter Management(2019-2020)。SIer、IT出版社、中堅企業のシステム管理者を経て、フリーのテクニカルライターに。Microsoft製品、テクノロジーを中心に、IT雑誌、Webサイトへの記事の寄稿、ドキュメント作成、事例取材などを手掛ける。個人ブログは『山市良のえぬなんとかわーるど』。近著は『ITプロフェッショナル向けWindowsトラブル解決 コマンド&テクニック集』(日経BP社)。
Copyright © ITmedia, Inc. All Rights Reserved.