しばたテックブログ

気分で書いている技術ブログです。

PowerShell Remoting over SSHを試す

PowerShell Core 6.0の正式リリースに伴い、本エントリの内容を新しいバージョンでやり直しました。
こちらのエントリを参照してください。

blog.shibata.tech


PowerShell on Linux(Mac)が公開された際の新機能の一つにSSHによるPSRemoting(PowerShell Remoting over SSH)があります。

本エントリではこの機能を試してみます。

PowerShell Remoting over SSHとは

ドキュメントでの表記がPowerShell Remoting over SSHPowerShell Remoting Protocol(PSRP) over SSHPSRP over OpenSSH等と若干揺れているのですが本エントリではPowerShell Remoting over SSHで統一しておきます。

従来のPowerShell Remoting Protocol(PSRP)では通信の下回りにHTTP/HTTPSを使いますが、PowerShell Remoting over SSHでは名前の通りSSHを使った通信を行います。

基本的な仕組みとしては、

  1. クライアント側はpowershell(.exe)がリモートセッション生成時にssh(.exe)を呼び出し、powershell(.exe)→ssh(.exe)のプロセス間通信を経由してサーバーへの通信を行う。
  2. サーバー側はSSHdのサブシステムにPowerShellを登録。
    クライアントからの接続があった場合はsshd(.exe)→powershell(.exe)とリモートシェルが実行される。

となっています。

仕様が公開されれいないため、ソースを読んだ限りでですが、PowerShell Remoting over SSHの仕組みはJobやPowerShell Directと同類でPSRPは(たぶん)使用しておらずWinRMにも依存していません。
このため、あくまでも私見ですが、PSRP over SSHという表記は正確でないと思われます。

このあたりはもう少し時間が経てば公式な情報も増えてくるかと思います。

PowerShell Remoting over SSHを試す

手順はGitHubDocsで公開されているのでこの手順をベースに行います。

https://github.com/PowerShell/PowerShell/tree/master/demos/SSHRemoting

試験環境

試験環境はVirtualBox上でWindows Server 2012 R2とCentOS 7.2.1511を使い双方向で通信させてみます。
これらのOSにした理由は単純に私が使い慣れているだけです。

他のOSでも細かい部分に違いはあるでしょうが基本的には同じ流れになると思います。

その他細かい条件は以下。

項目 Windows Server 2012 R2 CentOS 7.2.1511
基本設定 インストール直後の状態+最新のWindows Updateを実施 bento/centos7.2のBoxにyum updateを実施
IP 192.168.33.210 192.168.33.209
ユーザー vagrant, administrator vagrant, root

Windows → CentOSへの通信(パスワード認証)

最初にWindowsをクライアント、CentOSをサーバーにした場合の接続を試します。

CentOSにPowerShellをインストールします。  

# CentOS bash
# PowerShellのインストール
sudo yum install https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.9/powershell-6.0.0_alpha.91.el7.centos.x86_64.rpm -y

SSHdの設定変更を行います。
/etc/ssh/sshd_configに次の設定を追加します。

Subsystem powershell powershell -sshs -NoLogo -NoProfile

追加例)

# /etc/ssh/sshd_config

# override default of no subsystems
Subsystem       sftp    /usr/libexec/openssh/sftp-server
Subsystem powershell powershell -sshs -NoLogo -NoProfile

また、必要に応じてパスワード認証、鍵認証の可否を設定します。
今回は試験環境のデフォルト設定のままとしました。

# Boxのデフォルト設定
PasswordAuthentication yes

#RSAAuthentication yes
#PubkeyAuthentication yes

設定変更後はSSHdを再起動します。

# CentOS bash
sudo systemctl restart sshd.service

これでCentOS側の設定は完了です。

次にWindows側の設定をします。
標準でインストールされているPowerShell 4.0ではPowerShell Remoting over SSHできませんので、こちらにもPowerShell Coreをインストールします。

# Windows PowerShell 4.0
# PowerShell Coreのインストール
Invoke-WebRequest -Uri "https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.9/PowerShell_6.0.0.9-alpha.9-win81-x64.msi" -OutFile "PowerShell_6.0.0.9-alpha.9-win81-x64.msi"
Start-Process -FilePath msiexec.exe -ArgumentList @("/i", "$($pwd.Path)\PowerShell_6.0.0.9-alpha.9-win81-x64.msi", "/passive") -Wait -PassThru

次にSSHをインストールします。
Zipの解凍をしたいので先ほどインストールたPowerShell Coreから以下の手順でインストールします。

# Windows PowerShell Core
# ssh.exeのインストール 
Invoke-WebRequest -Uri "https://github.com/PowerShell/Win32-OpenSSH/releases/download/5_30_2016/OpenSSH-Win64.zip" -OutFile "OpenSSH-Win64.zip"
Expand-Archive -Path ".\OpenSSH-Win64.zip" -DestinationPath "C:\"
[Environment]::SetEnvironmentVariable('PATH', [Environment]::GetEnvironmentVariable('PATH') + ';C:\OpenSSH-Win64')

インストール先はC:\OpenSSH-Win64としましたが、こちらについては必要に応じて変更しても構いません。
また、PowerShell Remoting over SSHではssh.exeに対してPATHが通っていること(正確にはssh.exeだけでコマンド呼び出しができること)が必須であるためPATHは必ず通す様にしてください。

これで準備が整いましたので実際に試してみます。

まずはNew-PSSessionでPSセッションを作成します。
-HostName(-ComputerNameではない)、-UserNameパラメーターを指定するとPowerShell Remoting over SSHで通信することになります。

# Windows PowerShell Core
$Session = New-PSSession -HostName 192.168.33.209 -UserName vagrant

実行すると以下の様にssh.exeを使ってサーバーに接続する際のあれやこれやを聞かれるので適切な情報を入力していきます。

# Windows PowerShell Core
PS C:\Users\Administrator> $Session = New-PSSession -HostName 192.168.33.209 -UserName vagrant
The authenticity of host '192.168.33.209 (192.168.33.209)' can't be established.

ECDSA key fingerprint is SHA256:*******************************************.
Are you sure you want to continue connecting (yes/no)?
Please type 'yes' or 'no':
vagrant@192.168.33.209's password:

入力後、エラーが出なければ成功です。
$Sessionの中身を確認すると以下の様になり、名前がSSHになっていることがわかります。
このセッションがssh.exeと紐づいています。

# Windows PowerShell Core
PS C:\Users\Administrator> $Session

 Id Name            ComputerName    ComputerType    State         Configuration
                                                                  Name
 -- ----            ------------    ------------    -----         -------------
  1 SSH1            192.168.33.209  RemoteMachine   Opened        DefaultShell

この$sessionを使いEnter-PSSessionしてリモート接続します。

# Windows PowerShell Core
Enter-PSSession -Session $Session

実行結果は以下の様になり、CentOSにリモート接続できました。

# Windows PowerShell Core → CentOS PowerShell
PS C:\Users\Administrator> Enter-PSSession -Session $Session
[192.168.33.209]: PS /home/vagrant> cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
[192.168.33.209]: PS /home/vagrant>

ちなみに既知の不具合としてリモートだとClear-Hostが使えません。
これはそのうち直ると思います。

# Windows PowerShell Core → CentOS PowerShell
# Clear-Hostはエラーになる
[192.168.33.209]: PS /home/vagrant> Clear-Host
TERM environment variable not set.

とりあえずエラーメッセージの通りに

$env:TERM="vt100"

等とTERM環境変数を適当に設定しておけば対処は可能です。

最後にRemove-PSSessionしてセッション情報を削除すると紐づいていたssh.exeも終了します。

# Windows PowerShell Core
Remove-PSSession -Session $Session
  
# 個別に消すのが面倒なら以下で一気に消しても良い
Get-PSSession | Remove-PSSession

Windows → CentOSへの通信(鍵認証)

鍵認証で通信する場合、基本的にSSHの鍵認証の方法と同一です。

先ずはWindows側でssh-keygen.exeで鍵を作ります。
鍵の種類やパスフレーズの有無は適当にしてください。

以下の実行例ではRSA2 4096Byte、パスフレーズ有りにしています。

# Windows PowerShell 4.0 (Coreでもたぶん良い)
PS C:\> cd C:\OpenSSH-Win64\
# ssh-keygen
PS C:\OpenSSH-Win64> .\ssh-keygen.exe -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (C:\Users\Administrator/.ssh/id_rsa):
Enter passphrase (empty for no passphrase): ********
Enter same passphrase again: ********
Your identification has been saved in C:\Users\Administrator/.ssh/id_rsa.
Your public key has been saved in C:\Users\Administrator/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:******************************************* Administrator@WIN-7JINTK1PS1K

The key's randomart image is:
+---[RSA 4096]----+
|                 |
|                 |
|                 |
|                 |
|                 |
|                 |
|                 |
|                 |
|                 |
+----[SHA256]-----+

あとは作った公開鍵(id_rsa.pub)をCentOS側に転送し~/.ssh/authorized_keysに追加するだけです。
以下の例では/vagrant/id_rsa.pubに鍵を転送しています。

# CentOS bash
# ユーザーはvagrantユーザー
cat /vagrant/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

これで鍵認証の準備は完了です。
鍵認証で接続する場合はNew-PSSession-KeyPathパラメーターを使用します。

実行例は以下

# Windows PowerShell Core
# エラーが出なければ成功
PS C:\> $Session = New-PSSession -HostName 192.168.33.209 -UserName vagrant -KeyPath ~\.ssh\id_rsa
Enter passphrase for key 'C:\Users\Administrator\.ssh/id_rsa': ********

# セッション情報を確認
PS C:\> $Session

 Id Name            ComputerName    ComputerType    State         Configuration
                                                                  Name
 -- ----            ------------    ------------    -----         -------------
  1 SSH1            192.168.33.209  RemoteMachine   Opened        DefaultShell

セッションが生成された後はパスワード認証の場合と同様です。

CentOS → Windowsへの通信(パスワード認証)

最後に、あまり需要があるとは思いませんが、CentOSをクライアント、Windowsをサーバーにした場合の接続を試します。
面倒なのでパスワード認証のみとします。

まずはWindows上でSSHdを動作させます。
基本的にはGitHub上のインストール手順に従うだけなので問題ないかと思います。

# Windows PowerShell 4.0
cd C:\OpenSSH-Win64\

# SSHdのインストール
.\install-sshd.ps1

# ホストキーの作成
.\ssh-keygen.exe -A

# Firewall設定
New-NetFirewallRule -Protocol TCP -LocalPort 22 -Direction Inbound -Action Allow -DisplayName SSH

# 鍵認証周りの設定+再起動
.\install-sshlsa.ps1
Restart-Computer

sshd_configの設定はCentOSの場合と同様でサブシステムにPowerShell(Coreの方)を登録します。

Subsystem powershell C:/Program Files/PowerShell/6.0.0.9/powershell.exe -sshs -NoLogo -NoProfile

追加例)

# C:\OpenSSH-Win64\sshd_config

# override default of no subsystems
Subsystem   sftp    C:/Program Files/OpenSSH/sftp-server.exe
Subsystem powershell C:/Program Files/PowerShell/6.0.0.9/powershell.exe -sshs -NoLogo -NoProfile

設定後はサービスを再起動します。

# Windows PowerShell 4.0(Coreでもよい)
Restart-Service sshd

これで準備は完了です。

CentOS側からWindowsへ接続してみます。

# CentOS PowerShell
PS /home/vagrant> $Session = New-PSSession -HostName 192.168.33.210 -UserName administrator
The authenticity of host '192.168.33.210 (192.168.33.210)' can't be established.
ECDSA key fingerprint is ***********************************************.
Are you sure you want to continue connecting (yes/no)? yes
administrator@192.168.33.210's password: ********

セッション情報はこんな感じです。

# CentOS PowerShell
PS /home/vagrant> $Session

 Id Name            ComputerName    ComputerType    State         ConfigurationName     Availability
 -- ----            ------------    ------------    -----         -----------------     ------------
  1 SSH1            192.168.33.210  RemoteMachine   Opened        DefaultShell             Available

Enter-PSSessionでWindowsへ接続できます。

# CentOS PowerShell
PS /home/vagrant> Enter-PSSession -Session $Session
[192.168.33.210]: PS C:\Users\Administrator\Documents>

ここでWindows側でPowerShell Coreが実行されていのですが、現時点ではまだ、PowerShell Core→PowerShell 4.0(Desktop)とネストしてPowerShellを対話的に実行できない様で、実際にやってみるとハングしてしまいます。

ただし、powershell.exe -Command {ほげ}の様にコマンド実行であればネストして実行可能ですので、以下の例の様にPowerShell Coreにないコマンドレット(Get-NetFirewallRule)を実行することもできます。

# CentOS PowerShell → Windows PowerShell Core

# コマンドの実行結果に日本語があるのでShift-JISを有効に
[192.168.33.210]: PS C:\> [System.Text.Encoding]::RegisterProvider([System.Text.CodePagesEncodingProvider]::Instance)
[192.168.33.210]: PS C:\> $OutputEncoding = [System.Text.Encoding]::GetEncoding(932)

# CentOS PowerShell → Windows PowerShell Core → Windows PowerShell 4.0
[192.168.33.210]: PS C:\> powershell -Command { Get-NetFirewallRule -DisplayName *ssh* }


Name                    : {b467a636-88e4-4478-a408-e43a87356821}
ID                      : {b467a636-88e4-4478-a408-e43a87356821}
Group                   :
Platform                : {}
LSM                     : False
Profile                 : Any
Caption                 :
Description             :
ElementName             : SSH
InstanceID              : {b467a636-88e4-4478-a408-e43a87356821}
CommonName              :
PolicyKeywords          :
Enabled                 : 1
PolicyDecisionStrategy  : 2
PolicyRoles             :
ConditionListType       : 3
CreationClassName       : MSFT|FW|FirewallRule|{b467a636-88e4-4478-a408-e43a87356821}
ExecutionStrategy       : 2
Mandatory               :
PolicyRuleName          :
Priority                :
RuleUsage               :
SequencedActions        : 3
SystemCreationClassName :
SystemName              :
Action                  : 2
Direction               : 1
DisplayGroup            :
DisplayName             : SSH
EdgeTraversalPolicy     : 0
EnforcementStatus       : {0}
LocalOnlyMapping        : False
LooseSourceMapping      : False
Owner                   :
Platforms               : {}
PolicyStoreSource       : PersistentStore
PolicyStoreSourceType   : 1
PrimaryStatus           : 1
Profiles                : 0
RuleGroup               :
Status                  : 規則は、ストアから正常に解析されました。
StatusCode              : 65536
PSComputerName          :

最後に

とりあえずこんな感じです。
WindowsからLinuxへのPSRemoting、なかなか胸が熱くなります。

実はWindowsからLinuxへPSRPを使用した接続も可能なのですが、まだバギーな部分が多い様で、このあたりについては別の機会にエントリを書こうと思います。

【2016/09/16追記】

続き書きました。

stknohg.hatenablog.jp

【2017/08/15追記】

Windows 10 Creators Updateでも使える様になっていたので別エントリを起こしました。

blog.shibata.tech

PowerShell on LinuxをDocker上で試す

試した系の記事は既に多くの方がやっていますが、自分も一つくらいは書いとかないといけないかなと思ったので。

インストール手順

ぶっちゃけインストール手順はGitHubに載ってるのでそれを見れば十分です。
実のところ、わざわざこんなエントリ書く必要も無いのですが、そこはご愛敬ということでお許しくださいw

https://github.com/PowerShell/PowerShell/blob/master/docs/installation/docker.mdgithub.com

【2016/09/19変更】

PowerShell 6.0.0.Alpha10からDockerのインストール手順がガラッと変わってしまいました...
Alpha9では単純にサンプルとなるDockerfileだけ公開されていたのですが、いまはlaunch.shによりディストリビューションの選択、安定版や非安定版を設定することができる様になっています。

github.com

以降の内容はAlpha9から更新しませんが、Ubuntuで最低限のビルドを行う手順だ捉えていただければ、と思います。

PowerShell on LinuxをDocker上で試す

実行環境

今回試す環境は以下。

  • 64bit版 Windows 10 Pro RS1(1607)
  • Docker for Windows 1.12

GitHub上にあるDockerfileはUbuntuイメージをベースにしてるのでDocker for Windowsを使いました。
WindowsでなくてもLinuxイメージを扱える環境であれば何でも良いです。

Dockerfile

(Alpha9時点の)Dockerfileの内容はこんな感じ。
ベースイメージに対してPowerShell on Linuxのインストール手順をひとつづつRUNしてるだけなのでとても分かりやすいですね。

FROM ubuntu:16.04

RUN apt-get update && apt-get install -y curl libunwind8 libicu55 libcurl3
RUN curl -LO https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.9/powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb
RUN dpkg -i powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb

Entrypoint [ "powershell" ]

※補足として最後により新しいDockerfileを記載しておきますのでそちらも参考にしてください。

docker build

このDockerfileを適当なディレクトリに配置してdocker buildします。
以下の例はC:\TempにDockerfileを置いた場合です。

cd C:\Temp\
docker build -t powershell .

実行結果はこんな感じです。
各Stepにエラーが無ければOKです。

PS C:\Temp> docker build -t powershell .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:16.04
16.04: Pulling from library/ubuntu

952132ac251a: Pull complete
82659f8f1b76: Pull complete
c19118ca682d: Pull complete
8296858250fe: Pull complete
24e0251a0e2c: Pull complete
Digest: sha256:f4691c96e6bbaa99d99ebafd9af1b68ace2aa2128ae95a60369c506dd6e6f6ab
Status: Downloaded newer image for ubuntu:16.04
 ---> bd3d4369aebc
Step 2 : RUN apt-get update && apt-get install -y curl  libunwind8 libicu55
 ---> Running in 19bfb1cee4a8
Get:1 http://archive.ubuntu.com/ubuntu xenial InRelease [247 kB]

・・・ (中略) ・・・

Updating certificates in /etc/ssl/certs...
173 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
 ---> c43bd397c1af
Removing intermediate container 19bfb1cee4a8
Step 3 : RUN curl -LO https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.9/powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb
 ---> Running in b93ca6e75e85
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   628    0   628    0     0    340      0 --:--:--  0:00:01 --:--:--   340
100 39.0M  100 39.0M    0     0  82054      0  0:08:18  0:08:18 --:--:-- 90143
 ---> f1d271970597
Removing intermediate container b93ca6e75e85
Step 4 : RUN dpkg -i powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb
 ---> Running in 9eefe54aa684
Selecting previously unselected package powershell.
(Reading database ... 7831 files and directories currently installed.)
Preparing to unpack powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb ...
Unpacking powershell (6.0.0-alpha.9-1) ...
Setting up powershell (6.0.0-alpha.9-1) ...
 ---> b3ae5c7c67e8
Removing intermediate container 9eefe54aa684
Step 5 : ENTRYPOINT powershell
 ---> Running in 678e61405749
 ---> 017f3d9a7bd0
Removing intermediate container 678e61405749
Successfully built 017f3d9a7bd0
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context wil
l have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.

結果の確認

docker imageコマンドで作成したイメージを確認すると以下の様になり、powershellが出来ていることがわかります。

PS C:\Temp> docker images
REPOSITORY                            TAG                 IMAGE ID            CREATED             SIZE
ubuntu                                16.04               bd3d4369aebc        9 hours ago         126.6 MB
powershell                            latest              017f3d9a7bd0        14 hours ago        381.6 MB

docker run

docker runコマンドで作成したイメージからコンテナを起動します。
-itオプションで対話モードでpowershellを起動します。

docker run -it powershell

実行した結果は以下の様になります。

f:id:stknohg:20160828125714p:plain

ホスト環境がWindowsなので若干カーソルの挙動に怪しいところがありますがお試しで使うに分には十分です。
これで気軽にPowerShell on Linuxを試せますね。

おまけ

海外のMVPの方がAlpine LinuxでPowerShellを動かせないか画策している様です。

github.com

Alpine Linuxで動かすことができればベースイメージのサイズも減りますしDockerでPowerShell試すのがもっと気軽になりそうですね。

最新のDockerfile

【2016/09/19 追記】
【2016/10/19 更新】

現時点(alpha11)でのUbuntu16.04安定版のDockerfileの内容です。
本エントリの内容はこちらのDockerfileでも試して動作を確認しています。

FROM ubuntu:xenial
MAINTAINER Andrew Schwartzmeyer <andschwa@microsoft.com>

ARG POWERSHELL_RELEASE=v6.0.0-alpha.11
ARG POWERSHELL_PACKAGE=powershell_6.0.0-alpha.11-1ubuntu1.16.04.1_amd64.deb

# Setup the locale
ENV LANG en_US.UTF-8
ENV LC_ALL $LANG
RUN locale-gen $LANG && update-locale

# Install dependencies and clean up
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        libc6 \
        libcurl3 \
        ca-certificates \
        libgcc1 \
        libicu55 \
        libssl1.0.0 \
        libstdc++6 \
        libtinfo5 \
        libunwind8 \
        libuuid1 \
        zlib1g \
        curl \
        git \
    && rm -rf /var/lib/apt/lists/*

# Install PowerShell package and clean up
RUN curl -SLO https://github.com/PowerShell/PowerShell/releases/download/$POWERSHELL_RELEASE/$POWERSHELL_PACKAGE \
    && dpkg -i $POWERSHELL_PACKAGE \
    && rm $POWERSHELL_PACKAGE

# Use array to avoid Docker prepending /bin/sh -c
ENTRYPOINT [ "powershell" ]

Windows 10のコンテナーとDocker for Windowsを共存させる

いろいろあってちょっと遅くなりましたが

stknohg.hatenablog.jp

の続きです。

2016/10/18 追記

バージョン 1.12.2 Bata26よりDocker for Windowsにdockerd.exeが同梱される様になりGUIでDocker Engineの切り替えができる様になりました。

stknohg.hatenablog.jp

dockerd.exeが同梱されているバージョンであれば以降の手順は不要です。

Windows 10コンテナーのDockerとDocker for Windows

念のため最初に触れておきますが、Windows 10コンテナーのDockerDocker for Windowsは全くの別物です。

Windows 10コンテナーのDockerはWindowsイメージを扱い、Docker Engineとしてdockerd.exeが提供されています。

Docker for WindowsDocker Toolboxの流れをくむツールで、Hyper-V上にLinux仮想マシン(Alpine Linux)を立て、その仮想マシン上にあるDocker EngineがLinuxイメージを扱います。
そして仮想マシンと通信するプロキシサーバーとしてcom.docker.service等が提供されています。

ちなみにクライアントであるdocker.exeは両者共通の様です。

Windows 10のコンテナーとDocker for Windowsを共存させる

以上をふまえてWindows 10のコンテナーとDocker for Windowsを共存させる方法について説明していきます。

0. はじめに

今回は前回の手順でWindows 10コンテナーのDockerをインストールした後にDocker for Windowsをインストールする手順とします。

1. Windows 10コンテナーのDockerの設定変更

理由は後述しますが、デフォルト設定ではWindows 10コンテナーのDockerとDocker for Windowsを同時に起動することはできません。
このため最初にWindows 10コンテナーのDockerサービスを停止しておきます。

# Windows 10コンテナーのDockerサービス(dockerd.exe)の停止
Stop-Service docker

また、現時点ではDocker for Windowsのインストール先はC:\Program Files\Docker\Docker固定です。
部分的にインストールディレクトリが被ってしまうのでWindows 10コンテナーのDockerサービスのインストールディレクトリを変えいておいた方が無難です。

本エントリではインストールディレクトリをC:\Program Files\DockerWinContainerに変更しておきます。

# リネーム
Move-Item 'C:\Program Files\Docker\' 'C:\Program Files\DockerWinContainer\'

# サービス解除+再登録
cd 'C:\Program Files\DockerWinContainer\'
.\dockerd --unregister-service
.\dockerd --register-service

2. Docker for Windowsのインストール

続けてDocker for Windowsをインストールします。
手順はMSIインストーラーを実行して画面の指示に従うだけなので特に私から言うことは無い感じです。

インストールするとPATHにdocker.exeのあるC:\Program Files\Docker\Docker\Resources\binが追加されるので、Windows 10コンテナーのDockerとどちらを優先させるかは適当に設定してくだい。

今回は前回設定したPATHを削除してC:\Program Files\Docker\Docker\Resources\binだけを見る様にします。
これはDocker for Windowsに付いているdocker.exeを使うということになります。

3. Windows 10のコンテナーとDocker for Windowsを共存させる

先ほど言った様にデフォルト設定ではWindows 10コンテナーのDockerとDocker for Windowsを同時に起動することはできません。
理由は単純で、どちらのDockerもデフォルトでは名前付きパイプで待ち受けを行うためポートの競合が起きてしまうのが原因です。

なのでWindows 10のコンテナーとDocker for Windowsを共存させるにはポートの競合が起きない様にどちらかの待ち受けポートを変えてやれば良いです。

今回はWindows 10コンテナーのDockerの方の設定を変えて共存させます。
Dockerの設定についてはMSDNの以下のサイトに詳しく記載されています。

msdn.microsoft.com

こちらによれば、Windows 10コンテナーのDocker Engineの設定はC:\ProgramData\Docker\config\daemon.jsonに設定します。
デフォルトではdaemon.jsonはありませんので新規に作る必要があります。

待ち受けの設定はhostsキーとなり、例えば以下の様にするとTCP 2375番ポートで待ち受けする様になります。

{
    "hosts": ["tcp://0.0.0.0:2375"]
}

PowerShellからだと以下の様な感じでファイルを追加できます。

# -Encodingはutf8だとBOM付きになるからダメ
@"
{
    "hosts": ["tcp://0.0.0.0:2375"]
}
"@ | Out-File -FilePath (Join-Path $env:ProgramData "Docker\config\daemon.json") -Encoding default

これでポートの競合を回避できます。
あとはWindows 10コンテナーのDocker、Docker for Windows両方を起動すればOKです。

4. 確認と接続先の切り替え

最後に起動の確認と両ツールの切り替え方法について説明します。

最初にサービスを確認して両ツールが起動されているのを確認します。

PS C:\> Get-Service *docker*

Status   Name               DisplayName
------   ----               -----------
Running  com.docker.service Docker for Windows Service
Running  docker             Docker Engine

この状態でdocker versionを実行してみます。

# docker.exeはDocker for Windowsについているやつ
PS C:\> where.exe docker
C:\Program Files\Docker\Docker\Resources\bin\docker.exe

# docker version
PS C:\> docker version
Client:
 Version:      1.12.0
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   8eab29e
 Built:        Thu Jul 28 21:04:48 2016
 OS/Arch:      windows/amd64
 Experimental: true

Server:
 Version:      1.12.0
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   8eab29e
 Built:        Thu Jul 28 21:04:48 2016
 OS/Arch:      linux/amd64
 Experimental: true

OS/Arch: linux/amd64とある様にDocker for Windowsに接続していることがわかります。
これはdocker.exeのデフォルトが名前付きパイプで接続する様になっているためです。

(Windowsに限った話ではないですが)Dockerの接続先を変更するにはDOCKER_HOST環境変数を設定してやれば良いです。
前項でWindows 10コンテナーのDocker EngineはTCP 2375版ポートで待ち受けする様にしましたのでDOCKER_HOST環境変数を以下の様に変更します。

$env:DOCKER_HOST="tcp://localhost:2375"

改めてdocker versionを実行すると以下の様に結果が変わります。

# 接続先変更
PS C:\> $env:DOCKER_HOST="tcp://localhost:2375"

# docker version
PS C:\> docker version
Client:
 Version:      1.12.0
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   8eab29e
 Built:        Thu Jul 28 21:04:48 2016
 OS/Arch:      windows/amd64
 Experimental: true

Server:
 Version:      1.13.0-dev
 API version:  1.25
 Go version:   go1.6.3
 Git commit:   85428a1
 Built:        Fri Aug  5 14:55:24 2016
 OS/Arch:      windows/amd64

OS/Arch: windows/amd64と接続先が切り替わっていることがわかります。

最後に

とりあえずこんな感じです。

ここまでの流れでわかるかと思いますが、クライアント目線で見た場合、Windows 10コンテナーのDockerとDocker for Windowsは単純に個別のDocker Engineであり、片方はLinuxイメージを、もう片方はWindowsイメージを扱うサーバーという体になります。

あとWindows 10コンテナーのDockerは正式にはなんて呼称すれば良いんでしょうね?
ブログ書いてて非常につらかったのでわかる方いましたら是非教えてください。