Windows上でDocker使ってはまった事一覧

#はじめに
(下書き中ですがプルリクは歓迎します。
 ~~完成するのは本(Docker実践活用ガイド)を流し切った時のよていです~~
 →18/06/11 どうも本とやりたい事が乖離してきたので
　最新っぽい別の本(Dockerによるアプリケーション開発環境構築ガイド)も
　併せてみていく事にしました。)

Docker実践活用ガイド、Dockerによるアプリケーション開発環境構築ガイドを
買ってコマンドを順次検証してみてるのですが、
どうにもWindowsだとドカはまりしますね…
本の内容をただ流したいだけなのに。 (´・ω:;.:...

ということで備忘として書き残しておこうと思います。

ちなみに私の環境は以下です

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/e0587225-dc8b-368c-19ed-936baa853cd1.png)

インストールに使ったのはこちら
![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/8cd67d01-6d9a-fba9-875d-b57b058c7fb6.png)

基本的に言及がなければWindowsPowerShellで操作してます。
PowerShellをあんまりよく知ってるわけでもないのだけど、そろそろPowerShellを
脊髄反射で使えるようになっとかないと辛い時代になっていくのかな…
という気もしているので。

#Docker実践活用ガイド編はまりぽいんつ(8章ぐらいまで)

##Docker for Windowsをインストールしてdocker hogehogeコマンド打つとおこられる
Vagrantとか使っててVirtualBox入れてる場合におきます。

・VirtualBoxはHyper-Vを裏で占有したいので使うにはHyper-Vを切らないと使えない
・DockerはHyper-Vを有効にしてないと使えない

結果、排他的にどちらかを選ぶ事になります。
Windowsコンテナも使えるDocker for Windowsの利点を享受するには、
結局Hyper-Vをオンにするしかないわけで…　(ﾉ∀`)ｱﾁｬｰ
※なんかのHyper-Vが使えるVM環境を噛まして、その下で更に
　Docker環境とVirturalBox環境を持つという手は無いわけではないけれど、
　どう考えても面倒くさすぎるよね。

##インストールして再起動後、Dockerが起動しない
ショートカットを叩いても右下にクジラのアイコンが出てこない感じの挙動です。
なおサービスもサービスに紐づくプロセスも動いてるけど返事がなく、
サービス再起動してもやっぱり返事がない感じの動きをしてました。

結論はWindows10の高速シャットダウンが悪さをしていた。
こういう機能はそりゃ相性問題バリバリにあるよね…。

以下、設定方法です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/3edc2d30-1580-b317-b8d0-526aa75b14d4.png)
Windows+Rでファイル名を指定して実行で「powercfg.cpl」

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/8ab6c856-8c38-21ff-9319-fad97e7b4568.png)
「電源ボタンの動作の選択」を選択

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/01234636-42a9-5a82-e7f2-974a989da53c.png)
「現在利用可能ではない設定を変更します」を選択

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/0f50a480-e0e0-a43a-b98e-7e46a29b3b13.png)
高速シャットダウンを切ろう

その後再起動すると、Windowsの起動がちょっぴり遅くはなりますが
起動毎にハイバネーションの様な挙動ではなくて、
昔ながらの０からファイルを読み込んで立ち上がるようになります。

結果、動きました。

##コンテナがものによっては動くがものによっては動かない
Windowsコンテナを使うモードになってるけど、
呼んでるのがLinuxコンテナなのでダメという事らしい

ログはこんな感じ

```powershell
PS D:\> docker run -h hos -it ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
C:\Program Files\Docker\Docker\Resources\bin\docker.exe: no matching manifest for windows/amd64 in the manifest list entries.
See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'.
PS D:\>
```

以下、設定方法です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/83160b98-0618-69c1-0095-eb5dcdca6a8d.png)
これを選んで表示が「Switch to Windows Containers...」ってなったら動くようになる


##ローカルディレクトリがマウントできない

```powershell
PS D:\> docker run -it -v d:/dockerwork:/dockerwork ubuntu /bin/bash
C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error response from daemon: Drive sharing seems blocked by a firewall.
See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'.
```

こんなん出ておこられたわけですよ。
なんかdockerのネットワークが識別されていないネットワークになって
セキュリティ的にアレやな…　ってWindowsが判別するので弾かれるんだそうな。

以下、設定方法です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/4af5b7ad-051d-b376-3f2a-8ad98b7cf2d2.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/16a30bff-81cc-1919-4bdb-2d798e32d80f.png)

この設定を…
![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/722366dc-fe5b-3e2c-4165-55f743c76c4c.png)
こうだ。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/42a8cbfb-b020-6853-5401-d03e788eed9d.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/0368b494-cdcb-7993-12bf-38b66d629627.png)
つながった。

##CPU制限の時のパフォーマンス測定の話
こんなのぶっちゃけdocker関係ないんだけど、
本(Docker実践活用ガイド)には、timeコマンドを使えって
しれっと例で書いてる。でも標準のWindows環境にそんなものはないので
PowerShellの measure-command で代用しましょう。
(今考えるとcygwin上で叩くのも手ですね。こういう場合は。)

```powershell
measure-command{docker run --cpuset-cpus=0  -it ubuntu 
perl -e 'for $p(0...7){if(fork()==0){$a=0;for $i(1..2**26){$a++;};last;}}; while(wait()>0){}'}
```

こんな感じ。見やすいように改行してるけど、1行で書いてね。

##errorcodeの確認方法(本の中ではメモリ制限時のメモリ確保エラーの時のエラーコード確認)
これもあんまりDocker関係ない気はする。
コマンドプロンプトだと%ERRORLEVEL%を見る事になるし、

```
C:\WINDOWS\system32>docker run --memory=50m --memory-swap=50m -it ubuntu dd if=/dev/zero of=/dev/null bs=100M count=1
C:\WINDOWS\system32>echo %ERRORLEVEL%
137
C:\WINDOWS\system32>
```

PowerShellだと$LastExitCodeですね。

```powershell
PS D:\> docker run --memory=50m --memory-swap=50m -it ubuntu dd if=/dev/zero of=/dev/null bs=100M count=1
PS D:\> echo $LastExitCode
137
```

良く取れました。

##docker-machineを使ってみる段でドカはまりする
知ってる人には当たり前の話だと思うのですが、docker-machineを使うには
VirtualBoxを使ってごにょごにょ…　という情報が世の中には山積しています、が、
これはWindows以外の環境の話(たぶんみんなMac使ってるねんな…)

上でも書きましたが、そもそもの話として
・VirtualBoxはHyper-Vを切らないと使えない
・Windows用のDockerはHyper-Vを入れないと使えない
という一休さん顔負けのとんちで将軍様に切腹を命じられたような気分になっていたわけですよ。

そして結論としてはWindowsでDockerを使いたければ「全てHyper-Vに寄せる」のが正解だそうです。
なので -d で設定するのはvirtualboxではなく hyperv が正解らしい…

ということがわかって、現行の最新ver(docker-machine ver0.14)で

```powershell
docker-machine create -d hyperv default
```

の様なコマンドを打ったところ…

```powershell
PS C:\WINDOWS\system32> docker-machine_014.exe create -d hyperv default2
Running pre-create checks...
Error with pre-create check: "Hyper-V PowerShell Module is not available"
PS C:\WINDOWS\system32>
```

謎エラー。

経緯はよく理解できていないのですが、結論からいうと
ver0.13→0.14のVerUP時に動かなくなってるらしいです。

さてダウングレードしましょう　という事になるわけですが
どうダウングレードしたらええんや？　となるわけですね。

私の場合はchocolateyを入れており、
Pathの優先順が

C:\Program Files\Docker\Docker\resources\bin
C:\programdata\chocolatey\bin

だったので

```powershell
choco install docker-machine --version 0.13 --allow-downgrade -y
```

としてやって
C:\programdata\chocolatey\bin　に
docker-machine.exe

ができている事を確認、
C:\Program Files\Docker\Docker\resources\bin の
docker-machine.exe　を　docker-machine_014.exe　にリネームする事で
「docker-machine」コマンドの向き先を振り替えました。
(exeをコピーして上被せもためしてみたが、なぜかうまく動かなかった。
 相対参照で何かしらの設定ファイル読んでるとかするんでしょうねきっと。)

結果…

![image.png](https://qiita-image-store.s3.amazonaws.com/0/144657/ddd773d0-a85d-6859-7f13-2a04dc668725.png)

動いたー！　(∩´∀｀)∩

##docker-machineで定義したホストをdockerで動かす際のはまりぽいんつ
普通にdockerを使う分には要らんのですが、docker-machineをつかってDockerホストを利用するためには
docker-machine env hogehogehost コマンドを打って、
出てきたコマンドをコンソールで叩く必要があると。

で、手で叩いたりコピペするのは面倒なのでUnixShell環境だと以下のようなeval関数で処理するわけですな。

```bash
eval $(docker-machine env hogehogehost)
```

だがしかし、PowerShell単体だとこんなのないわけです。
で、どうするかというと

```powershell
docker-machine env hogehogehost | Invoke-Expression
```

こうする。
PowerShellではどうもInvoke-Expressionがいわゆるところのコマンドライン実行らしい。
結果、こうなる（はず）。

```powershell
PS C:\WINDOWS\system32> Get-ChildItem env:

Name                           Value
----                           -----
ALLUSERSPROFILE                C:\ProgramData
APPDATA                        C:\Users\******\AppData\Roaming
～～～～～～～
　　中略
～～～～～～～
ComSpec                        C:\WINDOWS\system32\cmd.exe
DOCKER_CERT_PATH               C:\Users\******\.docker\machine\machines\hogehogehost
DOCKER_HOST                    tcp://192.168.101.118:2376
DOCKER_MACHINE_NAME            hogehogehost
DOCKER_TLS_VERIFY              1
DriverData                     C:\Windows\System32\Drivers\DriverData
～～～～～～～
　　以下略
～～～～～～～
```

まさかのパイプラインだとは思いもしなかった。わからんではないが。
※ちなみに docker-machine env コマンドにおける --shell オプションは
　今自分が使っている環境以外の環境変数設定コマンドを取るためのものらしいので、
　それで何か外部コマンドが呼べたりはしないみたい。混乱しがちだし間違ってるページも見た覚えはある…

##curlが無い件
厳密にいうと代替はある

```bash
curl -X PUT -d 'bar' http://192.168.101.118:8500/v1/kv/foo
```
というコマンドは

```powershell
PS C:\WINDOWS\system32> Invoke-WebRequest -Uri "http://192.168.101.118:8500/v1/kv/foo" -Method PUT -Body "bar"


StatusCode        : 200
StatusDescription : OK
Content           : true
RawContent        : HTTP/1.1 200 OK
                    Content-Length: 4
                    Content-Type: application/json
                    Date: Fri, 08 Jun 2018 05:48:08 GMT

                    true
Forms             : {}
Headers           : {[Content-Length, 4], [Content-Type, application/json], [Date, Fri, 08 Jun 2018 05:48:08 GMT]}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 4
```

こんな感じ(上記例はConsulへのキーバリュー登録)
戻り値もとれるよ

```powershell
PS C:\WINDOWS\system32> Invoke-WebRequest -Uri "http://192.168.101.118:8500/v1/kv/foo"

StatusCode        : 200
StatusDescription : OK
Content           : [{"CreateIndex":14,"ModifyIndex":14,"LockIndex":0,"Key":"foo","Flags":0,"Value":"YmFy"}]
RawContent        : HTTP/1.1 200 OK
                    X-Consul-Index: 14
                    X-Consul-Knownleader: true
                    X-Consul-Lastcontact: 0
                    Content-Length: 88
                    Content-Type: application/json
                    Date: Fri, 08 Jun 2018 05:48:49 GMT

                    [{"CreateIndex":14,...
Forms             : {}
Headers           : {[X-Consul-Index, 14], [X-Consul-Knownleader, true], [X-Consul-Lastcontact, 0], [Content-Length, 88]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 88

PS C:\WINDOWS\system32> [System.Text.Encoding]::Default.GetString([System.Convert]::FromBase64String("YmFy"))
bar
```

だいたいこんな感じ。

##docker-machine create でconsul+docker swarm環境を組む時に
以下の様なコマンドでswarm環境は上がった

```posh
docker-machine create --driver hyperv `
  --swarm `
  --swarm-master `
  --swarm-discovery="consul://192.168.101.129:8500/swarm" `
  swarm-manager

docker-machine create --driver hyperv `
  --swarm `
  --swarm-discovery="consul://192.168.101.129:8500/swarm" `
  swarm-node1

docker-machine create --driver hyperv `
  --swarm `
  --swarm-discovery="consul://192.168.101.129:8500/swarm" `
  swarm-node2
```

でもなんか動かない。理由は不明(解決するまで追っかけてない)。

```posh
PS D:\dockerwork> docker-machine ls
NAME             ACTIVE      DRIVER   STATE     URL                          SWARM                     DOCKER        ERRORS
default          -           hyperv   Running   tcp://192.168.101.101:2376                             v18.05.0-ce
swarm-keystore   -           hyperv   Running   tcp://192.168.101.129:2376                             v18.05.0-ce
swarm-manager2   * (swarm)   hyperv   Running   tcp://192.168.101.133:2376   swarm-manager2 (master)   v18.05.0-ce
swarm-node1      -           hyperv   Running   tcp://192.168.101.134:2376   swarm-manager2            v18.05.0-ce
swarm-node2      -           hyperv   Running   tcp://192.168.101.135:2376   swarm-manager2            v18.05.0-ce
PS D:\dockerwork> docker-compose up -d
Creating network "dockerwork_default" with the default driver
ERROR: Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
PS D:\dockerwork> docker swarm init
Error response from daemon: 404 page not found
PS D:\dockerwork>
```

#Dockerによるアプリケーション開発環境構築ガイド編はまりぽいんつ
##docker save コマンドは-oオプション、docker loadコマンドは-iオプションを使わないとできたTarファイルが読めない
おそらくエンコードの関係でしょうね。
読める例(-o,-iオプションを正しく使ってるケース)

```powershell
PS D:\dockerwork\images> docker save -o .\hoge.tar sampledocker1234/ubuntu_with_php:1_0
PS D:\dockerwork\images> docker load -i hoge.tar
884843836da3: Loading layer [==================================================>]    100MB/100MB
Loaded image: sampledocker1234/ubuntu_with_php:1_0
PS D:\dockerwork\images>
```

読めない例(リダイレクションはダメらしい)

```powershell
PS D:\dockerwork\images> docker save sampledocker1234/ubuntu_with_php:1_0 > hogehoge.tar
PS D:\dockerwork\images> docker rmi sampledocker1234/ubuntu_with_php:1_0
Untagged: sampledocker1234/ubuntu_with_php:1_0
Deleted: sha256:93c71a21bc59fd509238bbfaa14c1b2eabd8772e958f067ded2cb42b4ccbee7c
Deleted: sha256:c60ceb6990faa013efc102887bf3c8fe644654d5115e64f3827866e6fa7e67a3
PS D:\dockerwork\images> cat hogehoge.tar | docker load
Error processing tar file(exit status 1): archive/tar: invalid tar header
PS D:\dockerwork\images> docker load -i hogehoge.tar
Error processing tar file(exit status 1): archive/tar: invalid tar header
PS D:\dockerwork\images>
```

読めない例(パイプラインでロードするのもダメらしい)

```powershell
PS D:\dockerwork\images> docker save -o .\hoge.tar sampledocker1234/ubuntu_with_php:1_0
PS D:\dockerwork\images> cat hoge.tar | docker load
Error processing tar file(exit status 1): archive/tar: invalid tar header
PS D:\dockerwork\images> 
```

#本関係ないやつ
##Docker for Windowsで標準でdocker run -v hogehoge:hogehogeするときのローカルフォルダには縛りがある
なんか標準だと、c:\usersの下しかマウントを許可してくれないらしい。
Windows上での開発だと、c:\usersの下にワークディレクトリを作るのが一番幸せそう…


##おわりに(まだ終わってないけど)

やっぱしエコシステムに乗る場合はみんな使ってるMacとかあるほうが無難ですな…
解決の過程は面白いんだけど。