Windows+Dockerの環境が重い問題をunisonで解決する


Windows + Dockerの開発環境でアプリケーションが重い問題をunisonというツールで解決したので共有します。
ネット上にいくつかunisonを使っている記事はあるのですが、より簡単に導入でき、アプリケーションへの影響が少ない方法にたどり着いたので記録を残します。

ちなみに自分はLaravelアプリケーションの開発でこの環境を使用しています。
3か月ほど運用していて、普通に開発している分には大きな問題はありませんでした。
composerでパッケージを全てバージョンアップした際に同期がおかしくなったぐらいです。
一応メリデメを上げると以下のとおりです。

  • メリット
    • アプリケーションの実行が早くなる
  • デメリット
    • 作業開始時にunisonクライアントを起動するひと手間が増える

なお、docker-composeを使用している前提の構成になっております。
それでは見ていきましょう。

大まかな構成について

unisonというファイル同期ツールを使います

以下の図のように、unisonクライアントをWindows側にインストールし、unisonサーバーをdocker-composeのサービスの1つとして起動します。
この2つのunison間でソースコードを同期します。
(既存のdocker-compose.ymlにunisonサーバを追加する事になります。)

unisonで同期したソースコードをDockerボリューム経由で他のコンテナにも共有します。

サンプルコードを用意しました

本記事の構成をすぐ試せるサンプルを用意しました。
詳しくはリポジトリのREADMEを参照ください。

リポジトリ: https://github.com/t-kuni/docker-unison-example

Unisonサーバーを起動します

docker-compose.ymlにunisonサーバーを追加します。

version: '3'
services:
  # Unisonサーバー
  unison:
    image: onnimonni/unison
    environment:
      - UNISON_DIR=/tmp/unison # 同期したファイルを書き込むフォルダを指定する
    ports:
      - "5000:5000"
    volumes:
      - app-code:/tmp/unison # Dockerボリュームをマウントするフォルダを指定する
    restart: always
  # その他のコンテナ
  apache:
    image: httpd:2.4
    volumes:
      - app-code:/usr/local/apache2/htdocs/ # その他のコンテナにも、Dockerボリューム経由でソースコードを共有する
    ports:
      - "8080:80"
volumes:
  app-code:

準備が出来たらdocker-compose up -dでコンテナを起動しましょう

Unisonクライアントをダウンロードします

以下のページからunisonクライアントをダウンロードします。

unisonクライアント: https://github.com/bcpierce00/unison/releases

サーバーのバージョンと合わせる必要があるため今回は2.51.2のクライアントをダウンロードします。

docker-compose.ymlと同じ階層にunisonフォルダを作成してunisonクライアントを配置します。

Unisonクライアントを起動します

unisonクライアントを起動するbatファイルを用意します。

docker-compose.ymlと同じフォルダにsync.batという名前で以下のコードを作成します。

:LOOP
    .\unison\unison . socket://192.168.99.100:5000/ ^
        -repeat watch ^
        -auto ^
        -batch ^
        -prefer newer ^
        -ignore "Path .git" ^
        -ignore "Path .idea" ^
        -ignore "Path node_modules"
goto :LOOP

上記のコードは、unisonを起動してカレントフォルダを同期しています。

IPアドレスの部分(192.168.99.100)にはコンテナのIPアドレスを入力してください。
また、まれにクライアントが落ちる事があるので無限ループで再起動するようにしています

unisonのオプションについて

unisonオプションの意味は以下の通りです。

  • -repeat watch
    • ファイルを監視し変更があれば同期を行います
  • -auto
    • コンフリクト時の確認を自動で許可する
  • -batch
    • 実行時の確認を行わない
  • prefer newer
    • コンフリクト時の解決方法として「より新しい物」を優先します
  • ignore
    • 同期しないファイルを指定します。

ignoreオプションについては、必要に応じて追加してください。
例えばLaravel環境ですとstoreage配下のいくつかのファイルは除外した方が良いです。

その他のオプションについては公式ドキュメントを参照してください。

準備が出来たらsync.batを起動します。
あとは自動的に同期を行ってくれます。

動作確認

以下のコードをindex.htmlとしてdocker-compose.ymlと同じフォルダに配置し、unisonで同期させます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>title</title>
</head>
<body>
    <h1>Hello unison!</h1>
    <p>このメッセージが表示されればunisonでの同期に成功しています</p>
    <p>index.htmlを書き換えて再同期されるか試してみてください</p>
</body>
</html>

192.168.99.100:8080(IPアドレスはコンテナのIPに置き換えてください)に接続して以下の画面が表示されればOKです。

同期が壊れた時は?

同期に使用しているDockerボリューム(サンプルではapp-code)をdocker volume rmで削除して、再同期してください。

以上です!