WSL(Windows Subsystem for Linux)でDockerをつかったWebアプリケーション開発をおこなう際の注意点
目次

これは無宗教ななびの :construction_worker: が書くDocker Advent Calendar 2017用記事です。前日はinductorさんの「Docker Meetupの中身まとめ」でした :whale: (写真はクリスマスを日本にひろめた明治屋 :christmas_tree:)
PROBLEM
- macOSとWindowsでWebアプリケーション開発をする際に
- 環境が異なって管理しづらい
- それならDockerで
- と思ったが、macOSはBashでWindowsはPowerShellなのか
- せめてPowerShellではなくBash...
- となると、いまWindowsでLinux環境をつかうならWSLか
- ただ、実際どこまで開発ができるかわからんしなあ
- となると、いまWindowsでLinux環境をつかうならWSLか
- せめてPowerShellではなくBash...
- と思ったが、macOSはBashでWindowsはPowerShellなのか
- それならDockerで
- 環境が異なって管理しづらい
SOLUTION
というわけで、この記事ではmacOSとWindowsによるWebアプリケーション開発について、どこまで共有できるか書いていきます。
前提条件として、当該WebアプリケーションはmacOSというより、Bash/Ubuntu14.04~のLinux環境で動くことを想定しています。macOSはHFS+やAPFSのUnicode正規化以外はおおよそLinux環境に適応できているという判断によります。
要は、WSLでDockerをつかったWebアプリケーション開発ができるかどうかという点に焦点をしぼります。
対象環境
- Windows 10 Pro 1709 16299.64
- Hyper-V 10.0.16299.15
- Docker for Windows 17.09.0-ce-win33
- Ubuntu 16.04 (Linux 4.4.0-43-Microsoft)
- Docker Client 1.12.6
Windowsの開発環境を構築する
まず、Windowsの開発環境の構築ですが、既知の情報をふまえつつTIPSを順次紹介します。
WSLのインストール
WSLのパッケージ管理は下記3つを押さえておけば問題ないでしょう。 1. apt - WSLではデーモンがつかえないのでDockerクライアントを入れましょう、Dockerデーモンの詳細は後ほど言及します 2. anyenv - プログラミング言語をバージョンごとにわけて使いたい場合はこちらをつかいましょう - exenvがビルドで失敗するためElixirインストールできないほかは、各言語問題なくビルドできます 3. nix - ElixirやHaskellのようにanyenvでインストールできない、あるいは、扱われいないパッケージはnixをつかいましょう - また、aptのバージョンが古すぎるパッケージもnixが最適です
ターミナルのインストール
WSLttyかConEmuをおすすめします。各々の特徴は下記のとおりですが、通常のWebアプリケーション開発であればWSLttyがいいでしょう。
- WSLtty
- Pros
- ConEmuとくらべてファイルの読込速度が速い (VMよりは遅い)
- EmacsでCtrl-SPC
set-markが機能する - 画面サイズの変更が柔軟
- Cons
- PowerShellなどほかのコンソールの呼び出しが面倒
- Pros
- ConEmu
- Pros
- PowerShellなどほかのコンソールの呼び出しが楽
- Cons
- ファイルの読込速度がおそい
- EmacsでCtrl-SPC
set-markが機能しない - 画面サイズの変更に制限がある
- Pros
WSLtty
WSL用ターミナルとしてのMinttyです。操作はMinttyとかわらず、元Cygwinづかいにはうれしい操作感です。というわけで、いつものごとく起動用ショートカットのターゲットを準備します。WSLは chsh がつかえないのでログイン時につかいたいシェルを指定します。もし、 screen をつかいたい場合は /run/screen ディレクトリを作成してからコマンド指定します。
%LOCALAPPDATA%\wsltty\bin\mintty.exe --wsl -o Locale=C -o Charset=UTF-8 /bin/wslbridge -t /bin/bash -c 'sudo mkdir /run/screen && sudo chmod 775 $_ && sudo chown root:utmp $_ && SHELL=/usr/bin/zsh screen'
ConEmu
WSL上で日本語を表示するため、また、WSLのLinux環境とWindows環境でターミナルをわけるため、ConEmuをつかいましょう。ConEmuをスマートにしたCmderはWSLとの相性がわるい1のでおすすめしません。
ConEmuの設定「Startup-Tasks」では、WSL用にパラメータ、コマンドを下記のように指定しています。
# task parameters
/icon "C:\Program Files\WindowsApps\CanonicalGroupLimited.UbuntuonWindows_1604.2017.922.0_x64__79rhkp1fndgsc\images\icon.ico"
# task command
bash -c 'sudo mkdir /run/screen && sudo chmod 775 $_ && sudo chown root:utmp $_ && SHELL=/usr/bin/zsh screen' -new_console:d:%USERPROFILE%
Docker for Windowsのインストール
WSLではDockerデーモンがつかえないのでNTFS (WSLからみるとdrvfs) 側で用意します。インストールはDockerのダウンロードページから手順通りおこないます。
構成は下記のようになります。

DockerクライアントからDockerデーモンにつなぐには、セキュリティリスクはありますが、 DOCKER_HOST をつかうのが簡易的です。Docker for WindowsとDockerクライアント、各々設定します。
1. Docker for WindowsよりDockerデーモンを「Expose daemon on tcp://localhost:2375 without TLS」として設定
2. WSL上のDockerクライアントに DOCKER_HOST=tcp://0.0.0.0:2375 を設定
WSLには下記のようなaliasを用意しておくといいでしょう。
export DOCKER_HOST=tcp://0.0.0.0:2375
alias docker="DOCKER_HOST=${DOCKER_HOST} docker"
alias docker-compose="docker-compose -H ${DOCKER_HOST}"
さて、WSLからDocker for Windowsはどの程度つかえるのか
WSLがlxfs、Docker for WindowsがNTFS (drvfs) 上で動いていることからわかるように、ファイルシステム上の制約があります。具体的には下記4点です。
- Docker for WindowsはNTFS (WSLからみるとdrvfs
/mnt/) 上のファイルしかVolumeマウントできません - WSLはLinux形式のパスしか扱えません、
C:\Devのようなドライブ名にコロンをつけたURIスキーマは扱えません - WSL上のdocker-composeはパスを絶対参照しかできません、相対参照できません2
- WSL上のnpm/yarnによるJSビルドをNTFS (drvfs)上でおこなうとエラーになります3
ひとつずつ解決方法を見ていきましょう。
1. Docker for WindowsはNTFS (WSLからみるとdrvfs /mnt/) 上のファイルしかVolumeマウントできません
開発用ディレクトリをNTFS上につくりましょう。普段からWindowsで開発されている方はCドライブ直下につくっているとおもいます。
2. WSLはLinux形式のパスしか扱えません、ドライブ名にコロンをつけたURIスキーマは扱えません
NTFSからのパス参照とWSLからのパス参照を共通化するために、WSLに各ドライブのシンボリックリンクをはりましょう。
$ ln -s /mnt/c /C
# 開発ディレクトリはこんな感じで参照できます
$ ls -al /C/Dev
total 0
drwxrwxrwx 0 root root 512 Oct 27 00:54 .
drwxrwxrwx 0 root root 512 Dec 8 07:49 ..
drwxrwxrwx 0 root root 512 Jul 14 03:06 app-test-1
drwxrwxrwx 0 root root 512 Oct 25 00:38 app-test-2
3. WSL上のdocker-composeはパスを絶対参照しかできません、相対参照できません
各OS間での違いを吸収するため、プロジェクトに PRJ_ROOT のような環境変数を用意しましょう。
services:
app-front:
image: 561534604247952616898.dkr.ecr.amazonaws.com/test/front
volumes:
- ${PRJ_ROOT}/front:/var/www/front
4. WSL上のnpm/yarnによるJSビルドをNTFS (drvfs)上でおこなうとエラーになります
こちらはFall Creators Updateのデグレですが、更新プログラム (KB4051963) でこの問題が修正されました :tada:
もし更新プログラムが適用できない場合は、シンボリックリンクでNTFS上のnode_modulesディレクトリをWSLに移しましょう。
$ mkdir /home/foo/tmp/app-test-1/front/node_modules
$ ln -s /home/foo/tmp/app-test-1/front/node_modules /C/Dev/app-test-1/front/node_modules
WRAPUP
まだ未検証な部分はのこっていますが、ひととおりmacOSとWindowsによるWebアプリケーション開発は共有できるところまできている、と言えそうです。
随時、気になる課題が出てきたら追記します。
