はじめに
最近Docker for MacのMutagen-based cachingを使うという記事が話題になっていたが、mutagen単体でDockerコンテナと連携するやり方が英語の記事を含めてもなかなか見つけられなかったのでまとめておく。
なお、本記事の方法ではMutagen-based cachengは利用しないため、Dockerはstable版のままでよい(上記記事の設定は試していないため動作の違い等は不明)。
またここで扱っているのはmutagenのsync
でforward
についてはこちらの記事に載っている。
環境
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.6
BuildVersion: 18G5033
$ docker -v
Docker version 19.03.8, build afacb8b
$ docker-compose -v
docker-compose version 1.25.5, build 8a1c60f6
準備
1. インストール
公式に書いてある通り。投稿時のバージョンは0.11.4。
$ brew install mutagen-io/mutagen/mutagen
$ mutagen version
0.11.4
2. デーモン起動
$ mutagen daemon start
3. コンテナ起動
テスト用に用意したdocker-compose.ymlは以下。
version: '3.7'
services:
web:
image: php:7.4-apache
container_name: web
ports:
- 80:80
db:
image: mysql:8.0
container_name: db
environment:
MYSQL_ROOT_PASSWORD: root
$ docker-compose up -d
手動で使う
1. セッションの作成
$ mutagen sync create --name=mutagen-test --default-file-mode-beta=644 . docker://web/var/www/html
こちらのコマンドでmutagen-test
という名前でカレントディレクトリ(alpha)の内容をwebコンテナの/var/www/html(beta)と同期するセッションを作成できる。なぜsource
とdest
ではなくalpha
とbeta
なのかと疑問だったが、mutagenは双方向に同期できるためのようだ。
--default-file-mode-beta=644
はbeta(コンテナ)側のファイルパーミッションを644
にする設定。mutagenのデフォルトではパーミッションがディレクトリ700
、ファイル600
になる(参考)ので、ここで指定して(もしくは--default-owner-beta=www-data
として)おかないと、今回のようにapacheから参照したい場合にパーミッションエラーになる。
セッションを作成した時点で同期が始まる。これまで使っていてファイルが消えたりしたことはないが、万が一に備えてバージョン管理されている状態で行った方がよい。
2. 同期の状況の確認
- 実行時点
$ mutagen sync list
--------------------------------------------------------------------------------
Name: mutage-test
Identifier: sync_pPfc22rlD8RcEDldZ9CbMTJzTnRszZHfokhkZtopw7a
Alpha:
URL: /tmp/mutagen
Connection state: Connected
Beta:
URL: docker://web/var/www/html
DOCKER_HOST=
DOCKER_TLS_VERIFY=
DOCKER_CERT_PATH=
Connection state: Connected
Status: Watching for changes
- リアルタイム
$ mutagen sync monitor
Name: mutagen-test
Identifier: sync_pPfc22rlD8RcEDldZ9CbMTJzTnRszZHfokhkZtopw7a
Labels: None
Alpha: /tmp/mutagen
Beta: docker://web/var/www/html
DOCKER_HOST=
DOCKER_TLS_VERIFY=
DOCKER_CERT_PATH=
Status: Watching for changes
セッション作成直後の最初の同期中にmonitorを見ているとStatus: Staging files on beta: 41% (9191/22567)
などといった状態になり、これがStatus: Watching for changes
になったら同期完了。
ファイルの量やマシンスペックにもよると思われるが、上記の22567ファイルの規模(今回のものとは別のプロジェクト)で20秒程度だった。monitorは同期が完了しても勝手には終わらないので^Cで抜ける。
3. 動作確認
- 新規作成
$ ls
docker-compose.yml
$ echo '<?php echo "It works!";' > index.php
$ docker-compose exec web ls -la
total 20
drwxrwxrwx 1 www-data www-data 4096 Jun 4 05:29 .
drwxr-xr-x 1 root root 4096 May 15 12:41 ..
-rw-r--r-- 1 root root 206 Jun 4 05:28 docker-compose.yml
-rw-r--r-- 1 root root 24 Jun 4 05:29 index.php
$ curl localhost
It works!
- 編集
$ echo '<?php echo "It works fine!";' > index.php
$ curl localhost
It works fine!
ちゃんと同期されているようだ。
今回はサイズも小さいので一瞬だが、実プロジェクトでは数秒のラグはある(コンテナでファイル自動生成などをしてすぐにホストでgit status
で見るとまだ反映されていなかったりする)。
4. セッションの終了
$ mutagen sync terminate mutagen-test
$ mutagen sync list
Error: no matching sessions exist
5. 手動の問題点
最初はこれでしばらく使っていたが、例えばセッション実行中にコンテナを落とすと、Status: [Errored] Connecting to beta
となり同期エラーになったり、そこからdocker-compose up -d
で再度コンテナを起動しても、Status: Halted due to one-sided root emptying
となって同期はできずセッションを作り直さなければならないという問題があった。
先述のオーナーやパーミッションは設定ファイルに書くこともできるが、コンテナとの連携も合わせて一括管理したいなあと思っていたところ、次のmutagen project
を使う方法を見つけた。
mutagen projectを使う
mutagenにはprojectという機能があり、セッションの作成や終了といったライフサイクルと任意のコマンドを組み合わせて設定ファイルで管理し実行できる。
公式のexamplesがわかりやすい。
今回は簡略化した以下のmutagen.ymlを使用する。
beforeCreate:
- docker-compose up -d
afterTerminate:
- docker-compose down
sync:
defaults:
ignore:
vcs: true
mutage-test:
alpha: "."
beta: "docker://web/var/www/html"
mode: "two-way-resolved"
configurationAlpha:
permissions:
defaultFileMode: 644
defaultDirectoryMode: 755
configurationBeta:
permissions:
defaultOwner: www-data
defaultGroup: www-data
defaultFileMode: 644
defaultDirectoryMode: 755
beforeCreate
でセッション作成前にコンテナを起動、afterTerminate
でセッション終了後にコンテナも終了する。
また、sync
の項目にセッションの設定を書いておける。
ここではalphaのパーミッションも設定しているが、これはフレームワークなどのファイル自動生成やcomposerやnpmでのライブラリのインストールをコンテナ上で行った場合に700
や600
でホストに同期されるのを防ぐためである。
公式ではafterCreate
で同期完了までのwaitを入れている。同期が速いといっても多少のラグはあるので、実プロジェクトで採用する際は真似しておくと、同期完了前にアクセスしてファイルが見つからないなどのエラーを避けられる。
docker-compose.yml
と同階層に置いてバージョン管理しておく。
1. セッションの開始
$ mutagen project start
Started Mutagen daemon in background (terminate with "mutagen daemon stop")
> docker-compose up -d
Creating network "mutagen_default" with the default driver
Creating web ... done
Creating db ... done
Created session sync_3bwd2dlhwaFrNNeUNRe4WYegNxOdPjEj3swQ8Xx1Hz6
セッション開始前にコンテナが起動しているのが確認できる。デーモンが起動していなかった場合はそっちも起動してくれて便利。
セッション実行中はmutagen.yml.lock
というファイルができるので.gitignore
に追加しておくとよい。
2. セッションの終了
$ mutagen project terminate
> docker-compose down
Stopping web ... done
Stopping db ... done
Removing web ... done
Removing db ... done
Removing network mutagen_default
3. コマンドの実行
また、composerやnpmなどのscriptsと同様に任意のコマンドを定義できるようになっている。以下を設定ファイルに追加する。
commands:
repl: docker-compose exec web php -a
db: docker-compose exec db mysql -uroot -p
$ mutagen project start # セッションを終了していない場合は不要
$ mutagen project run repl
Interactive shell
php > echo 'hello';
hello
php > ^D
$ mutagen project run db
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.20 MySQL Community Server - GPL
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
おわりに
mutagen project
を利用することで、mutagenとdocker-composeを連携できて便利だった。
現状そこまで不満もないのでDockerのMutagen-based cachingがstableになるまではこの方法を使おうと思う。
参考
- DXを大幅に低下させるDocker for Macを捨ててMac最速のDocker環境を手に入れる ( こちらの記事でmutagenなるものを知りました。ありがとうございます。)
- 公式ドキュメント
- Improving performance for Docker on Mac computers when using named volumes
- Speeding Up Docker Development on the Mac