Docker for Windowsで快適な環境を得るまでの そこそこ長い闘い

#2019年8月更新
2年の間にWindowsでのDocker開発環境が進化したのと
知人より凄い便利な機能を教えてもらったので共有します

##おさらい
今までの大雑把なおさらいとして
Windowsでのサーバ開発はDockerを使えば問題なく出来る
（実際私は2016年からWindowsでサーバ開発を行っている）
VirtualBoxなどを使い、boot2dockerを使いVM上のLinuxで開発も出来るが
Windows10 Pro64bitで Hyper-VをONにして Docker for Windowsで開発するとカッコイイ
ただし、WindowsにはBashがないのでシェルスクリプトが実行できない
WSLを使いDockerをインストールし、Docker for WindowsのExportを使えば良い
ただし、WSLのマウントポイントが /mnt/c/ になっているため、環境変数やsedを使いパスを変更する必要があり不便だった

##WSLのマウントポイントの変更
知り合いに教えてもらった。簡単にWSLのマウントポイントを変更できる！

/etc/wsl.conf ファイルでマウントポイントを設定できる
具体的には /を指定すると /cにマウントされる

```:/etc/wsl.conf
[automount]
root = /
options = "metadata"
```

これでマウントポイントが /cになり、今までの問題が全部解決してしまった！

Windowsで幸せなServer開発を行ってくださいね！


##更に便利に
ほんと、ここ数年のWindowsのDocker対応は進化が速く追いつくのが大変だ

###LCOW
https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/deploy-containers/linux-containers

今までのDockerはMoby Linux上で実行されていた
VM上にLinuxを立ち上げその上でDockerを実行していたが
LCOWではHyper-V分離を使い、よりオーバーヘッドが少ないコンテナ実行が出来るらしい
Docker for WindowsでExperimentalではあるがLCOWの使う事が出来る

###Windowsコンテナ
WindowsネイティブのDockerHostで、Windowsコンテナをネイティブ実行できる
今のところはCLIしか使えないので使ったことはないが
Windowsサーバの管理などで使う人は便利だと思われる

###WSL2
今までのWSLはLXCore という技術を使い、Linuxをエミュレートしている
完全なLinuxではないため、動かせない物がたくさんある
例えばDockerHostなど
WSL2は完全なLinux VMを使っているので、Linux機能を全部使う事が出来るらしい
例えばDockerHostも動かすことができる

そして、WSL2に最適化された WSL2 Dockerというものが作られた
https://engineering.docker.com/2019/06/docker-hearts-wsl-2/
7月末にプレリリースとの話だが

WSL2が、プレビュー版のWindowsをインストールする必要があり
私の環境では、OSインストールでブルースクリーン落ちするため
WSL2を試せていない・・

https://engineering.docker.com/2019/06/docker-hearts-wsl-2/



2年前までの情報
#はじめに
Macで開発する人も多いと思います。たしかにMacはBSDベースで開発便利ですが
Windowsこそ最高の開発環境である　という前提で、Windowsで最高の開発環境を構築しようと思います


結果だけ見たい人は下の方をｗ

Windowsのメリットは、ハードウェアの選択肢が多い事
特にゲームや人工知能開発には ハイスペックGPU選べるのが良いですね
DirectXも動きます

ではWindows開発の問題は何か？

一番は シェルです
WindowsにはBash等 Linuxと互換性のあるシェルがなく、コマンドプロンプトやパワーシェルという独特なシェルです
一般的には bash等のシェルスクリプトが使われるため、これは不利です

もう一つは、Windowsに PHPやらPythonやらApache・・・をインストールしたくない事。
そして、OSの機能。たとえばファイアウォール等の設定がLinuxと違う事やディレクトリ名
このあたりは、DockerやVMなどで開発すれば問題ないですね

ので、Dockerを使う前提で考えます
WindowsでDockerを使うためには 2つの方法があります
1つは DockerToolsを使う方法で、VirtualBox上のLinuxからDockerを使う方法で、Macでもこの方法ですし
Linux上なので シェル問題も解決するので、何も問題ありません
これで満足する人は DockerToolsを使ってください。
共有ディレクトリやポートフォワードも VirtualBoxの設定で可能なので　何も問題なく使えます

Windows10 Pro 64bitの人は Docker for Windowsを使う事が出来ます
ホスト型のVirtualBoxで動かすよりも、ハイパーバイザーで動くHyper-Vのほうが
オーバーヘッドが少なくより快適になるのではないかと期待しています
ただし、色々と不便があり　やっと快適に使う方法を手にしたので
少し環境構築が大変です
でも、最高の開発環境のために　頑張ります！


#シェル問題
##VirtualBoxを使う
LinuxをVMに入れるので何も問題ない
ただ、今回はより最高の環境のため Docer for Windowsを使うため、使用しない

##Windows専用のバッチファイルを作る
コマンドプロンプトやPowerShellを使えば Bashと同等の事はおそらく可能であるが管理コストが増えるし
普段使うシェルもBashのほうが慣れているので、出来れば避けたいところ

##Cygwinを使う
古典的な手法だが、Cygwinはいいぞ
ただし Dockerコンテナに入ろうとすると
cannot enable tty mode on non tty input
と怒られてしまうので Cygwinは使えない

##Gitのbashやmingwを使う
mingwを使えば問題ないらしいぞ！
ただし、あくまでWindows上なため、シェルの設定等あまり出来ないだろうし
パッケージもインストールできない

##Windows Subsystem for Linux(Bash on Ubuntu on Windows)
Windows内のLinuxを使う！！
これが最も最強っぽい響きがあるので　あえてこれで挑戦します
（多分　mingw使うのが一番楽なんだけど・・）
シェルではなく Ubuntuなので aptで色々とインストールも出来たりします
カオス！
ただし　色々な問題があります

###不具合
日本語対応が怪しかったりするので日本語パスとかやめましょう
コンソールに高確率でゴミが残ります
vimなどよく固まる。大きいファイル扱うと固まります
その他いろいろと　不具合あります

β機能なので　温かい心が必要です！

###WSLも仮想IP上で動いているのでDocker for Windowsと直接通信出来ない
WSLは“アプリケーションのためのサンドボックス環境”で動いているようです
大問題です（が解決できます）
Docker for Windowsは ホストOS（Windows10）のHyper-V上で動いていますが
Bash on Winowsも ホストOSのHyper-Vで動いているためか
bashでdockerコマンドうっても　Bash on Windows上のdockerに接続にいきます
（そして Bash on WindowsのDockerは　対応してないのか落ちる）

という事で、 Bash on Winowsから　ホストのDockerを叩けるように　してみます！


#インストール
Docker for Windowsのインストールと Bash on Windowsをインストール
この辺の手順は　色々なサイトであるので　書かない
また Docker for Windowsには docker-composeも入っているので素晴らしい！
Hyper-Vの有効化や BIOSの有効化も忘れずに

##ドライブシェアの設定
![SnapCrab_NoName_2017-11-10_2-23-34_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/13916/2927ba93-4622-a15f-d9b3-aa2fabaff7da.png)

私のPCはCドライブしかないけど、複数ドライブある時は、シェアするドライブを指定します
また、チェックしたときに　Firewallがなんたら・・　と怒られる事がるので　その場合は
Firewallで445ポートをオープンすればよい
ただし　それだけではダメで　一度Windowsの ファイル共有サービスを削除してインストールすれば直るとのこと
https://qiita.com/shwld/items/7aad11ca53e2e5daad46

bashでdockerをうっても　コマンドがない！
それは Bash on Windowsに dockerクライアントがインストールされてないからです

##Bash on WindowsでDockerのインストール
Docker本家より

```bash
sudo apt-get install \
    apt-transport-https  ca-certificates curl \
    software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

sudo apt-get update
sudo apt-get install docker-ce
```
こんな感じでインストールできます
ただし　このままでは　起動しない Bash on WindowsのDockerをみにいくので
環境変数を設定し、ホストOSのDockerを見るようにします

##ホストのDockerを見に行く設定
```bash
export DOCKER_HOST='tcp://0.0.0.0:2375'
```
これを .bashrc に追加しておけば大丈夫です

そして、ホストのDockerにて 2357ポートを許可する必要があります
（私はこの設定をしらず　3か月 コマンドプロンプトで Dockerを使う不便を味わった）

![SnapCrab_NoName_2017-11-10_2-24-38_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/13916/75a960e0-8a26-ac0b-a259-a09472ffacef.png)

この Expose daemon on tcp://localhost:2375 without TLS
これをチェックする必要があります
もしかすると、TLSを使い dockerコマンド送る方法もあるのかもしれないけど、今回はそこは調べません

これで
$ docker hogehoge
で　ホストOSのDockerを動かすことができます

##docker-composeのバージョンアップ
```bash
$ docker-compose up
```

とすると、docker-composeのバージョンが古く、書式が通りませんでした・・・
docker-compose -v とすると version 1.3 でした
古い・・・

という事でバージョンアップします。
まずはホストOSですが、Dockerの公式より

https://docs.docker.com/compose/install/

のWindowsタブを見ます
ホストOSの PowerShellを管理者モードで起動し

```ps1
Invoke-WebRequest "https://github.com/docker/compose/releases/download/1.17.0/docker-compose-Windows-x86_64.exe" -UseBasicParsing -OutFile $Env:ProgramFiles\docker\docker-compose.exe
```

のようにします。　今回は 1.17.0を取得

インストールが完了しても、Bash on WindowsのDocker-composeはバージョンが古いので、まだ怒られます

##Bash on Windows上のdocker-compose バージョンアップ

上記URLの Linuxのところをみると

```bash
sudo curl -L https://github.com/docker/compose/releases/download/1.17.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
```

と書いてますが　今回は　pipで行おうと思います

http://docs.docker.jp/compose/install.html


https://bootstrap.pypa.io/get-pip.py
上記URLからダウンロードし get-pip.py という名前で保存し

```bash
$ sudo python get-pip.py
$ sudo pip install docker-compose
```

#結論
bash on windowsから　docker-compose up もちゃんと動いたし
bashも問題なく使える
ちょっと不具合はあるけど　今後解消されるのを待ちましょう

最強の開発環境完成です！！


#パス問題
Bash on WindowsでDockerを使えて便利になったけど相対パスを指定すると不具合が出る
例えば docker-compose.ymlで volumesを相対パスで設定

```yaml
    volumes:
      - .:/myapp
```
うまくマウントされない
原因は DockerのMobyLinuxVMと WSLのUbuntuのマウントパスの違いです
DockerはCドライブを /c にマウントしますが
WSLでは /mnt/c　をマウントします

https://github.com/Microsoft/WSL/issues/1854


##解決案1 環境変数
環境変数 $PWDを上書きして使う（むろん他の名前でもよい）
WSLのBash上では /mnt/c/... となっているので

```bash
$ PWD=echo $(pwd) | sed -e 's/^\/mnt//'
```

と、/mntを削除し 設定ファイルも環境変数を使うようにする

```yaml
    volumes:
      - $PWD:/myapp
```