Docker Composeで「開発環境が激重」という呪いを解く。泥沼から脱却する実践的アーキテクチャ
朝、PCを開いて`docker-compose up`を叩く。コンテナは立ち上がるが、なぜかMacのファンが爆音で回り出し、CPU使用率は100%に張り付く。コードを一行修正してブラウザをリロードしても、反映されるのは数秒後……。あの絶望感に、いつまで付き合うつもりだ?
「Dockerを使えば環境構築が楽になる」なんてのは幻想だ。無策で組んだDocker構成は、ただの「PCを熱暴走させるための装置」に過ぎない。今回は、数々の失敗を経てたどり着いた、開発効率を最大化するための「捨てていい構成、守るべき鉄則」を叩き込む。
1. なぜDockerは「爆速」で動かないのか?
原因はシンプルだ。Docker DesktopにおけるホストOSとコンテナ間のファイル同期(バインドマウント)のコストにある。
macOSやWindowsのファイルシステム(APFS/NTFS)と、コンテナ内のLinuxファイルシステムの間で、OSのカーネルを跨いだイベント監視が走る。特に`node_modules`のような数万もの小ファイルが混在するディレクトリをマウントすると、OS間のAPI通信が飽和し、I/O待ちでシステム全体が死ぬ。
解決策:マウントの「聖域」を守る
`docker-compose.yml`で、同期不要なディレクトリを「匿名ボリューム」として切り離すのが鉄則だ。
services:
app:
build: .
volumes:
- .:/app # ソースコードは同期する
- /app/node_modules # 匿名ボリューム化:ホスト側と同期させない
# VirtioFSを有効化しているなら、これだけで劇的に変わる
こうすることで、コンテナ内でのパッケージインストール処理がホスト側のファイルシステムを汚染せず、かつI/Oのボトルネックも回避できる。
2. パーミッション問題は「逃げ」ない。スマートに解決せよ
`sudo chown -R $USER:$USER .` を叩くたびに、自分自身が敗北しているような気分にならないか? 権限エラーが出るたびにファイルを書き換えるのは、泥縄式の手法だ。
シニアなやり方は、Dockerfileのビルド時にホストのUID/GIDを環境変数として受け取り、コンテナ内のユーザーにマッピングすることだ。
# Dockerfile
ARG USER_ID=1000
ARG GROUP_ID=1000
RUN groupadd -g ${GROUP_ID} appuser && \
useradd -u ${USER_ID} -g appuser -m appuser
USER appuser
さらに、`docker-compose.yml`で以下のように呼び出す。
services:
app:
build:
context: .
args:
USER_ID: ${UID:-1000}
GROUP_ID: ${GID:-1000}
これで、コンテナ内で生成されたファイルもホスト側で自由に編集できる。「権限で詰む」というストレスから一生解放される。
3. 「複雑な構成」は未来の自分への罠
本番環境のマルチステージビルドを開発環境に持ち込むな。開発で重要なのは「ビルドキャッシュの再利用性」だ。
| 環境 | 優先すべき指標 | 構成のポイント |
|---|---|---|
| 開発 | 速度・柔軟性 | キャッシュ効率重視、ビルド手順を簡素化 |
| 本番 | セキュリティ・サイズ | マルチステージで不要なものを削ぎ落とす |
大規模プロジェクトになればなるほど、`docker-compose.yml`を継承(`extends`)させろ。共通設定を`base.yml`に切り出し、開発用には`dev.yml`をオーバーライドする。
# docker-compose.yml (開発用メイン)
include:
- base.yml
services:
app:
extends:
file: base.yml
service: app
command: npm run dev # 開発用コマンドを上書き
4. データベースという「資産」を死守する
開発環境で最もやってはいけないミス、それは「コンテナ削除と共にDBデータが消える」ことだ。DBのデータディレクトリを永続化するのは、エンジニアとしての最低限の教養だ。
services:
db:
image: postgres:15
volumes:
- db-data:/var/lib/postgresql/data # 名前付きボリュームで永続化
volumes:
db-data: # Docker管理下に置くことで、OS間のパス依存を排除
バインドマウント(ホストのディレクトリを指定)は使うな。ファイルシステムの仕様差でPostgreSQLが起動しなくなるトラブルは、もう見飽きた。Dockerに管理させるのが、最も平和な選択肢だ。
結論:道具に振り回されるな
Dockerはあくまで「コードを書くための環境」を整える道具に過ぎない。設定を複雑化させ、シェルスクリプトを大量に仕込み、環境構築そのものを複雑なパズルに仕立て上げるのは、エンジニアリングの敗北だ。
- 匿名ボリュームでI/Oを最適化せよ
- UIDを動的にマッピングして権限問題を撲滅せよ
- 名前付きボリュームでデータを保護せよ