Docker Machine 入門(Hyper-Vの場合)

# 背景
前回
[Docker Machine 入門(AWSの場合)](http://qiita.com/ohhara_shiojiri/items/9fbb32ecdb999e2df523)
の続きで、 今回はWindows10proのローカルHyper-V環境でDocker Machineを紹介します。
最新のDocker for Windowsは従来のDocker ToolboxのVirtualBoxからHyper-Vに移行して共存も出来ないので、Windowsの方で最新のDockerを追いかけるならVirtualBoxは捨てましょう。
それ以外の方は従来通りDocker ToolboxでVirtualBoxを利用します。
あと注意点として、Hyper-VとはいえMicrosoftのWindowsコンテナとはまた別物です。

参考資料として、Docker関係の投稿は以下にあります。
- [Docker 再入門3 2016](http://qiita.com/ohhara_shiojiri/items/cabc644f8a4d1aaf2e36)
- [Docker 再入門2 2016](http://qiita.com/ohhara_shiojiri/items/31a76913cbfdd9d2fe13)
- [Docker 再入門1 2016](http://qiita.com/ohhara_shiojiri/items/98573b074185381d46c8)
- [Docker 入門](http://www.slideshare.net/ShinichiroOhhara/docker-39456836) (SlideShare)

# 動作環境
- ThinkPad X1 Carbon OS:Windows 10 Pro (Hyper-V)

# Docker Machine(再掲)
Docker Engineが動作するにはLinuxカーネルが必要ですが、ホストOSがLinuxの場合はともかく、WindowsやMacOSの場合はVMなどで用意する必要があります。
また、ローカルの開発環境だけでなく本番環境のクラウド側にも必要になります。
このDocker Engineが動作する環境を構築するツールがDocker Machineです。
Docker環境の自動構築ツール、いわゆるオーケストレーションツールがこのDocker Machineです。
2015年8月にDocker Toolboxが登場して大きく状況が変わり、WindowsやMacOSではBoot2Dockerに代わりDocker Machineが推奨されています。
ローカルのVirtualboxだけではなく対応するドライバによって複数の異なる環境下でDockerが構築出来ます。

## インストール(再掲)
Docker Machineのインストール方法については、[Docker 再入門1 2016](http://qiita.com/ohhara_shiojiri/items/98573b074185381d46c8)にて紹介済みですので、参照して見てください。
Docker for windows の場合にはDocker Engineと共に一緒にインストールされています。

## Hyper-V環境設定
ローカル環境ではBoot2Dockerの仮想マシン(VM)をHyper-Vのハイパーバイザーで作成する必要があります。
また、Docker for Windowsをインストールしただけでは、ローカルのNATアダプターしか無い為に外部から接続が出来ません。
外部接続用のネットワークを追加で用意する必要があります。
公式ページの解説は以下の通りです。

[Microsoft Hyper-V](https://docs.docker.com/machine/drivers/hyper-v/)(docker.com)

では実際の日本語Windows10pro環境での様子を以下に紹介します。

「Hyper-Vマネージャー」を起動します。
![hyper-v_M_1.PNG](https://qiita-image-store.s3.amazonaws.com/0/35898/0e5ba8f8-5356-f702-277e-02b16ed698dc.png)
操作メニューから「仮想スイッチ マネージャー」を起動します。
![hyper-v_M_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/35898/33c97459-8b71-1b26-a267-e6efbf773ac7.png)
「仮想スイッチの作成」から以下の様に仮想スイッチを作成します。
名前は標準の適当なものでも良いですが、コマンド入力でネットワークアダプタを指定する事も後々考慮しておきます。
外部ネットワークには外部接続出来るデバイスを指定します。ここでは有線のEthernetデバイスを指定しています。
![hyper-v_M_3.PNG](https://qiita-image-store.s3.amazonaws.com/0/35898/2605b2b4-c2e4-9c66-dcc6-9a8dc1803e92.png)
追加した仮想スイッチを既存のDocker VMである「MobyLinuxVM」に追加します。
「仮想マシン」の項目から「MobyLinuxVM」を選んで右クリックで「設定」のメニューを選択します。
![hyper-v_M_4.PNG](https://qiita-image-store.s3.amazonaws.com/0/35898/3580cfe0-ae8a-8b91-0eb6-daddc859bba0.png)
ここで「ハードウェアの追加」で先程作成した仮想スイッチを「ネットワークアダプタ」から設定します。
![hyper-v_M_5.PNG](https://qiita-image-store.s3.amazonaws.com/0/35898/543538f0-1a61-b35a-d7d4-78b6ccb1e663.png)
設定を有効にする為にPCを必ず再起動します。

## PowerShell
Dockerの操作は管理者権限で起動したPowerShellにて行います。コマンドプロンプトでも一応操作出来るようですが、ここでは考慮しません。

## Dockerの動作確認
PowerShellにてバージョン表示やHello Worldさせてみます。

```
PS C:\WINDOWS\system32> docker version
Client:
 Version:      1.12.1
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   23cf638
 Built:        Thu Aug 18 17:52:38 2016
 OS/Arch:      windows/amd64

Server:
 Version:      1.12.1
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   23cf638
 Built:        Thu Aug 18 17:52:38 2016
 OS/Arch:      linux/amd64

PS C:\WINDOWS\system32> docker-machine version
docker-machine.exe version 0.8.1, build 41b3b25

PS C:\WINDOWS\system32> docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
 https://hub.docker.com

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/
```

問題無く動作しているので、nginxのコンテナを動かしてみます。

```
PS C:\WINDOWS\system32> docker run -d -p 8000:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
43c265008fae: Pull complete
e4c030a565b1: Pull complete
685b7631c1ce: Pull complete
Digest: sha256:
Status: Downloaded newer image for nginx:latest

PS C:\WINDOWS\system32> docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
abc123456789        nginx               "nginx -g 'daemon off"   7 seconds ago       Up 7 seconds        443/tcp, 0.0.0.0:8000->80/tcp   elegant_hypatia
```

Dockerコンテナも問題なく起動しました。webブラウザで "localhost:8000" に接続するとnginxの標準ページが表示されました。
以降のテストと混乱しないように念のためローカルのコンテナは止めて削除しておきましょう。

```
PS C:\WINDOWS\system32> docker stop abc123456789

PS C:\WINDOWS\system32> docker rm abc123456789
```

## Hyper-VでDocker Machineを動かす
準備が出来たので、Docker Machineを動かしてみましょう。
AWSの時と違って今度はドライバーにhypervを指定して起動させます。

```
PS C:\WINDOWS\system32> docker-machine create --driver hyperv default
Running pre-create checks...
(default) No default Boot2Docker ISO found locally, downloading the latest release...
(default) Latest release for github.com/boot2docker/boot2docker is v1.12.3
(default) Downloading C:\Users\user\.docker\machine\cache\boot2docker.iso from https://github.com/boot2docker/boot2doc
ker/releases/download/v1.12.3/boot2docker.iso...
(default) 0%....10%....20%....30%....40%....50%....60%....70%....80%....90%....100%
Creating machine...
(default) Copying C:\Users\user\.docker\machine\cache\boot2docker.iso to C:\Users\user\.docker\machine\machines\default\boot2docker.iso...
(default) Creating SSH key...
(default) Creating VM...
(default) Using switch "Primary Virtual Switch"
(default) Creating VHD
(default) Starting VM...
(default) Waiting for host to start...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe env default
```

Boot2Dockerのイメージファイルをgithubからダウンロードして来て、Hyper-Vにてdefaultの名前で起動しています。
一度イメージをダウンロードすれば次回からはローカルのキャッシュから流用するので、次回起動時は速くなります。
SSH鍵の作成やVHDディスクの作成などの過程が表示されていきます。

### docker-machine ls
作成したDocker Machineの状態を一覧表示します。

```
PS C:\WINDOWS\system32> docker-machine ls
NAME      ACTIVE   DRIVER   STATE     URL                        SWARM   DOCKER    ERRORS
default   -        hyperv   Running   tcp://192.168.10.10:2376           v1.12.3
```

### docker-machine ssh マシン名
作成したDocker MachieのインスタンスにSSHログインが簡単に出来ます。

```
PS C:\WINDOWS\system32> docker-machine ssh default
                        ##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
           \______ o           __/
             \    \         __/
              \____\_______/
 _                 _   ____     _            _
| |__   ___   ___ | |_|___ \ __| | ___   ___| | _____ _ __
| '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
| |_) | (_) | (_) | |_ / __/ (_| | (_) | (__|   <  __/ |
|_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
Boot2Docker version 1.12.3, build HEAD : 7fc7575 - Thu Oct 27 17:23:17 UTC 2016
Docker version 1.12.3, build 6b644ec
```

そのままDocker Engineが動作するか確認してみます。

```
docker@default:~$ docker version
Client:
 Version:      1.12.3
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   6b644ec
 Built:        Wed Oct 26 23:26:11 2016
 OS/Arch:      linux/amd64

Server:
 Version:      1.12.3
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   6b644ec
 Built:        Wed Oct 26 23:26:11 2016
 OS/Arch:      linux/amd64
```

Boot2Dockerの公式イメージから作成していますので、問題無く動作しています。

### docker-machine ip マシン名
作成したEC2インスタンスのIPアドレスを表示します。

```
PS C:\WINDOWS\system32> docker-machine ip default
192.168.10.10
```

外部ネットワークのDHCPサーバーから自動取得されたIPアドレスが付与されますので、ここのIPアドレスに対してサービスが動作します。

### docker-machine inspect マシン名
詳しい内容を表示します。

```
PS C:\WINDOWS\system32> docker-machine inspect default
{
    "ConfigVersion": 3,
    "Driver": {
        "IPAddress": "192.168.10.10",
        "MachineName": "default",
        "SSHUser": "docker",
        "SSHPort": 22,

・・・中略・・・

        }
    },
    "Name": "default"
}
```

### docker-machine env マシン名
dockerコマンドの環境変数を特定のDocker Machineに変更します。
コマンドを実行すると環境変数が表示されるので、最終行の指示にあるようにコマンドでシェル環境を特定のDocker Machineへ変更させます。
元に戻す場合は、-uのオプションを使用します。

```
PS C:\WINDOWS\system32> docker-machine env -u
Remove-Item Env:\\DOCKER_TLS_VERIFY
Remove-Item Env:\\DOCKER_HOST
Remove-Item Env:\\DOCKER_CERT_PATH
Remove-Item Env:\\DOCKER_MACHINE_NAME
# Run this command to configure your shell:
# & "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env -u | Invoke-Expression
```

以下の例では、ローカル環境からHyper-Vのdefaultに変更しています。

```
PS C:\WINDOWS\system32> docker-machine env default
$Env:DOCKER_TLS_VERIFY = "1"
$Env:DOCKER_HOST = "tcp://192.168.10.10:2376"
$Env:DOCKER_CERT_PATH = "C:\Users\user\.docker\machine\machines\default"
$Env:DOCKER_MACHINE_NAME = "default"
# Run this command to configure your shell:
# & "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env default | Invoke-Expression
```

```
PS C:\WINDOWS\system32> & "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env default | Invoke-Expression
```

一見ローカル環境のPowerShellのままですが、Dockerの対象はHyper-V側のDocker Machine(default)を操作します。
このまま直接、dockerコマンドでnginxをTCP 8000番で実行してみましょう。

```
PS C:\WINDOWS\system32> docker run -d -p 8000:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx

43c265008fae: Pull complete
e4c030a565b1: Pull complete
685b7631c1ce: Pull complete
Digest: sha256:
Status: Downloaded newer image for nginx:latest
```

自動的に、Docker Hubからnginxのイメージがダウンロードされてnginxサービスが実行されます。
しかしこれはローカル環境ではなく、Hyper-V側のDocker Machine(default)で実行しています。
では、動作確認の為にcurlコマンドやwebブラウザで該当IPアドレスを表示させてみます。

```
PS C:\WINDOWS\system32> curl http://192.168.10.10:8000


StatusCode        : 200
StatusDescription : OK
Content           : <!DOCTYPE html>
                    <html>
                    <head>
                    <title>Welcome to nginx!</title>

・・・以下略・・・
```

webブラウザでも8000番ポート指定でnginx標準ページが表示されるはずです。
では、SSHでDocker Machine(default)へログインして中身の動作確認をしてみましょう。

```
PS C:\WINDOWS\system32> docker-machine ssh default
                        ##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
           \______ o           __/
             \    \         __/
              \____\_______/
 _                 _   ____     _            _
| |__   ___   ___ | |_|___ \ __| | ___   ___| | _____ _ __
| '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
| |_) | (_) | (_) | |_ / __/ (_| | (_) | (__|   <  __/ |
|_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
Boot2Docker version 1.12.3, build HEAD : 7fc7575 - Thu Oct 27 17:23:17 UTC 2016
Docker version 1.12.3, build 6b644ec

docker@default:~$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
6d64c90ee2fe        nginx               "nginx -g 'daemon off"   9 minutes ago       Up 9 minutes        443/tcp, 0.0.0.0:8000->80/tcp   kickass_kilby

docker@default:~$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              e43d811ce2f4        11 days ago         181.5 MB
```

ちゃんとDocker Hubからイメージがダウンロードされて実行されているのが確認できました。
では一度、ローカルにexitで戻りましょう。
また、ローカル環境に戻しておきます。

```
docker@default:~$ exit

PS C:\WINDOWS\system32> docker-machine env -u
Remove-Item Env:\\DOCKER_TLS_VERIFY
Remove-Item Env:\\DOCKER_HOST
Remove-Item Env:\\DOCKER_CERT_PATH
Remove-Item Env:\\DOCKER_MACHINE_NAME
# Run this command to configure your shell:
# & "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env -u | Invoke-Expression

PS C:\WINDOWS\system32> & "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env -u | Invoke-Expression
```

### docker-machine stop マシン名
Hyper-VのDocker Machine(default)を停止します。

```
PS C:\WINDOWS\system32> docker-machine stop default
Stopping "default"...
(default) Waiting for host to stop...
Machine "default" was stopped.

PS C:\WINDOWS\system32> docker-machine ls
NAME      ACTIVE   DRIVER   STATE     URL   SWARM   DOCKER    ERRORS
default   -        hyperv   Stopped                 Unknown
```

### docker-machine restart マシン名
停止したHyper-VのDocker Machine(default)を再起動します。

```
PS C:\WINDOWS\system32> docker-machine restart default
Restarting "default"...
Starting "default"...
(default) Waiting for host to start...
Machine "default" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Waiting for SSH to be available...
Detecting the provisioner...
Restarted machines may have new IP addresses. You may need to re-run the `docker-machine env` command.

PS C:\WINDOWS\system32> docker-machine ls
NAME      ACTIVE   DRIVER   STATE     URL                        SWARM   DOCKER    ERRORS
default   -        hyperv   Running   tcp://192.168.10.10:2376           v1.12.3
```

### docker-machine rm マシン名
Hyper-VのDocker Machine(default)を削除します。

```
PS C:\WINDOWS\system32> docker-machine rm default
About to remove default
Are you sure? (y/n):y
Successfully removed default

PS C:\WINDOWS\system32> docker-machine ls
NAME   ACTIVE   DRIVER   STATE   URL   SWARM   DOCKER   ERRORS
```

本当に削除するか問い合わせて来ますので、Yと答えると削除実行されます。