「Dockerが重い」と嘆く前に。開発環境のボトルネックを物理で叩き直す技術

「Dockerが重い」と嘆く前に。開発環境のボトルネックを物理で叩き直す技術

「Docker Desktopは重いからMacでは限界がある」
そう言って、スペック不足を理由に思考停止しているエンジニアをよく見かける。だが、ハッキリ言おう。それはハードウェアのせいではなく、君の「設計の怠慢」だ。

Dockerは魔法ではない。仕組みを理解せず、ただ`docker-compose up`を叩くだけでは、いつまで経っても環境構築の沼から抜け出せない。本番環境とローカル開発環境のギャップに苦しみ、マイグレーションのたびにコンテナを全消去して時間を溶かす。そんな泥沼から脱却するための、現実的かつ泥臭い最適化の手法を共有する。


1. ファイル同期の「地獄」をvirtiofsで解決する

Mac環境でDockerが遅い最大の要因は、ホストとコンテナ間のファイル同期(オーバーヘッド)にある。特に`node_modules`や`vendor`配下の大量のファイルを同期対象に含めれば、CPU負荷が跳ね上がるのは自明の理だ。

まず確認すべきは、Docker Desktopの設定だ。`virtiofs`を有効にしているか?
gRPC FUSEからvirtiofsへの移行は、ファイルシステムパフォーマンスを劇的に改善する。まだ設定していないなら、今すぐ設定画面を開け。

さらに、`docker-compose.yml`でのマウント設定を最適化する。

services:
  app:
    volumes:
      - .:/app:delegated  # 必須。ホスト側の変更をコンテナに即時反映させつつ同期を緩和する
      - /app/node_modules # コンテナ内でのみ管理し、ホストと同期させない(匿名ボリューム)

`:delegated`を付けることで、ホストの変更をコンテナが認識する優先度を下げ、オーバーヘッドを大幅に削減できる。これを知っているか否かで、開発のテンポは別物になる。


2. マルチステージビルドでイメージを「極限」まで削る

「とりあえず全部入り」のDockerfileは、ビルド時間の無駄を生む最大の戦犯だ。Python環境であれば、ビルドに必要なコンパイラやヘッダファイルと、実行に必要なランタイムを明確に分ける。

# ビルドステージ:依存関係の解決とビルドに集中
FROM python:3.11-slim AS builder
RUN apt-get update && apt-get install -y --no-install-recommends gcc python3-dev
WORKDIR /build
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

# 実行ステージ:軽量なイメージのみを使用
FROM python:3.11-slim
WORKDIR /app
# ビルド済みパッケージのみをコピー
COPY --from=builder /root/.local /root/.local
COPY . .

# パスを通す泥臭い工夫
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]

`--no-cache-dir`や`--no-install-recommends`を徹底するだけで、イメージサイズは半分以下になり、キャッシュのヒット率も向上する。これは「なんとなく」でイメージを作っている奴らとの決定的な差だ。


3. 「全消去」という悪癖を捨てるDB運用

マイグレーションでハマり、`docker-compose down -v`でDBごと吹き飛ばす。これを繰り返しているうちは、一生「再現性のある環境」なんて作れない。

DBの状態管理は「マイグレーションツール」と「初期化スクリプト」の分離が鉄則だ。

Makefileによる運用自動化

コンテナを再構築するのではなく、スキーマをクリーンにしてから最新のマイグレーションを当てるフローを確立しろ。

# 開発効率を上げるためのMakefile例
.PHONY: migrate reset-db

migrate:
	docker compose exec app alembic upgrade head

# 破壊的なリセットではなく、スキーマをリセットして再構築
reset-db:
	docker compose exec db psql -U postgres -d my_db -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
	docker compose exec app alembic upgrade head

こうすれば、コンテナを再起動するコストを払わずに、数秒でDBをクリーンな状態に戻せる。


4. 今日から始める「爆速」開発のためのチェックリスト

Dockerの重さに不満があるなら、まずは以下の3点を今すぐ確認しろ。

1. `.dockerignore`の徹底: `.git`, `.venv`, `__pycache__`, `node_modules`は含んでいるか?ここを無視するだけで同期負荷は激減する。
2. `command`の分離: `docker-compose.yml`の`command`でマイグレーションを自動実行するな。アプリケーションの起動とDBのマイグレーションはライフサイクルが違う。手動で制御しろ。
3. 計測の習慣化: `docker stats`をターミナルに常駐させろ。どのコンテナがメモリを食い、どのプロセスがCPUを回しているのかを数字で把握しない限り、最適化など不可能だ。

最後に

「ツールが重い」と嘆く暇があったら、そのツールの挙動をプロファイリングし、設計を見直せ。エンジニアの本分は、制約の中でいかに快適な開発体験(DX)を自作自演で作り上げるかにある。

Dockerはただの道具だ。君が主導権を握るか、道具に使われて時間を浪費し続けるか。すべては今日、君がキーボードを叩いて設定ファイルに書く「一行」にかかっている。