
ローカルでLaravelを動かしているだけなら、Dockerは要らない——これが、個人開発者が最初に直面する冷徹な現実だ。PHPのビルトインサーバーとMySQLをHomebrewで入れる程度で完結するなら、コンテナを立ち上げる合理性より、Dockerfileを書く時間のほうが遥かに重い。極端な話、composer create-project laravel/laravelからphp artisan serveまでを30秒で終えた方が、よほど生産的だ。
ただし、その「単一言語で閉じた構成」は意外と脆い。Redisが必要になる瞬間、Elasticsearchを触りたくなる瞬間、PHP 8.2と8.3の両方で動作確認を迫られる瞬間——そういう「もう一段」が積もった時、ホストOSに直でインストールしていた依存関係は牙を剥く。筆者がかつてPostgreSQL 13と14を共存させようとして、Homebrewのリンクで一日を潰した苦い記憶が、今でも蘇る。
本記事では、個人開発の現場で「Dockerを入れるべきライン」がどこにあるのかを、複数ミドルウェアの運用・環境の再現性・I/Oパフォーマンス・本番移行の4つの軸で整理していく。
Dockerが解決するのは「環境の汚染」ではなく「自分の首を絞める依存関係の積み重ね」だ。両者は似ているようで、深刻度がまるで違う。
単一構成か複数連携か:Docker導入の最初の分かれ道
個人開発の初期段階で、Dockerを無理に導入する必要は一切ない。例えば、フレームワーク標準のローカルサーバー(php artisan serveやpython manage.py runserver、Railsのbin/rails sなど)と、SQLiteないしHomebrewで入れたMySQLの組み合わせで動作するなら、その構成を素直に使い続けた方が幸せだ。学習コストを払い、DockerfileのCOPYとRUNの順番に四苦八苦しながら、本来書きたかったコードに辿り着けない——典型的な「DockerのためのDocker」開発に陥る。
しかし、Webサーバー(PHP/Python/Node.js)+ リレーショナルデータベース(MySQL/PostgreSQL)+ キャッシュサーバー(Redis/Memcached)の三つ巴になった瞬間、状況は一変する。HomebrewでPHPとRedisを別バージョンでインストールし、peclの拡張が衝突してphp.iniが二つに分裂した経験がある人間なら、Docker Composeのdocker-compose.yml一発で環境ごと封じ込められる安心感がどれほど大きいか、想像に難くない。
| 構成の複雑度 | Docker推奨度 | 理由 |
|---|---|---|
| 単一言語・DBなし or SQLiteのみ | ★☆☆☆☆ | ビルトインサーバーで十分、Dockerのオーバーヘッドが邪魔になる |
| Web + DB(1プロセス) | ★★☆☆☆ | ホスト直インストールでも回せるが、Dockerの再現性に将来価値あり |
| Web + DB + キャッシュ/キュー | ★★★★☆ | 依存関係が複雑化、Composeで一括管理するメリットが顕在化 |
| Web + DB + Cache + 検索エンジン + 監視 | ★★★★★ | もう人力では追えない、ComposeどころかComposeの分割が必要 |
結局のところ、最初の分かれ道は「プロセスをいくつ抱えているか」だ。一つなら要らない。三つを超えたら、もうDockerの領域にいる。
環境汚染を防ぐコンテナ技術の恩恵とホストOSへの影響
Dockerコンテナは、ホストOSのカーネルを共有するコンテナ型仮想化技術だ。従来のハイパーバイザー型VM(VirtualBoxやVMwareなど)と比較して、リソース消費が圧倒的に少なく、起動は秒単位で終わる。VMWareでLaravel環境を立ち上げるのに30秒、Dockerなら0.5秒——この速度差は、開発中の「ちょっと試して壊す」を百回繰り返す人間にとって、決定的な差になる。
ただし、コンテナ型仮想化には明確なトレードオフがある。ホストOSのカーネルに依存するため、Linuxカーネル上で動作する前提のコンテナをmacOSやWindowsで動かす場合、内部的にはLinux VMが動いている。Apple SiliconのMacでDocker Desktopを立ち上げると、内部でQEMUベースの軽量VMが走っており、これが「Docker for Macは遅い」の正体だ。
環境汚染という観点では、Dockerの寄与は絶大だ。Homebrewで[email protected]、[email protected]、[email protected]を切り替えようとして、/usr/local/etc/php/以下の設定ファイルがぐちゃぐちゃになった経験がある人間は多い。コンテナなら、各バージョンを独立したプロセスとして起動できる。docker run -it --rm php:8.3-cli php -vの一行で、PHP 8.3の環境をホストを汚さずに試せる。
「ホストOSが汚れる」は、家庭用PCなら笑い話で済むが、仕事の受託案件が並行して走る個人開発者の環境では致命傷になる。
Docker Composeによるインフラ管理の効率化と限界
docker-compose.ymlという単一のYAMLファイルに、Webサーバー、データベース、Redisを一括で書き出す——この単純さは、Dockerを個人開発に組み込む最大の動機になる。例えば、Laravelの開発環境なら、PHP-FPMコンテナ、MySQLコンテナ、Redisコンテナ、Nginxコンテナをdepends_onで順序制御しながら、docker compose up -d一発で揃えられる。
ただし、Docker Composeは万能薬ではない。docker-compose.ymlが膨らんで200行を超えたあたりから、「これは本当にComposeで管理すべきなのか?」という疑問が湧き上がる。Kubernetesへ移行する前の過渡期として使うなら良いが、Composeを本番環境の管理ツールとして扱い始めると、ヘルスチェック・ログローテーション・シークレット管理・オートスケーリングといった、本番運用に不可欠な機能が物足りなく感じられる。
現実的な落とし所は、ローカル開発環境とステージング環境までをComposeで完結させ、本番環境は別のオーケストレーションに任せるという線引きだ。個人開発の場合、本番環境をAWS ECSやGCP Cloud Runに置くなら、Composeのdocker-compose.ymlは「ローカル開発用の再現装置」として割り切るのが筋が良い。
| 環境 | Compose向き | 備考 |
|---|---|---|
| ローカル開発 | ◎ | チーム全員が同じ構成を再現できる |
| CI/CDの一時環境 | ○ | テスト並列化で使える |
| ステージング | △ | ログ/モニタリングツールとの連携は別途必要 |
| 本番 | × | ECS/GCP/Cloud Run/Kubernetesなど専用基盤に任せる |
筆者の経験上、Composeを本番に持ち込むと「最後の20%の運用要件」を自前で書く羽目になる。ALBのヘルスチェック一つとっても、ECSならTerraformの5行で済むものが、Composeなら自作のシェルスクリプトか、Nginxコンテナの設定に工夫を凝らす必要がある。
I/Oパフォーマンスと永続化:コンテナ特有の設計課題
コンテナ運用の現場には、Dockerを語るときに必ず出る二つの落とし穴がある。一つはI/Oパフォーマンスの劣化、もう一つはデータの揮発性だ。
まず、I/Oパフォーマンスの話。macOSやWindows(WSL 2)環境で、ホストとコンテナ間のファイル共有(bind mount)を行うと、I/Oが著しく低下する場合がある。Laravelのvendor/やNode.jsのnode_modules/をbind mountしている状態で、composer installやnpm installを回すと、信じられない時間がかかる。Docker Desktopのファイル共有実装が、ホストとコンテナ間のメタデータ同期で詰まるのが原因だ。
対策としては、コンテナ内にパッケージをインストールし、ホスト側ではソースコードだけをbind mountするという構成が定番になる。DockerfileでRUN composer installを焼き付け、ホストには./srcだけをマウントする。node_modulesも同じで、コンテナ内に閉じることでI/Oボトルネックの多くを回避できる。
次に、データの揮発性。Dockerコンテナ内のファイルシステムは、コンテナが削除された瞬間に消える。これは設計上の仕様であり、バグではない。MySQLのデータ、Redisのログ、アップロードされた画像ファイル——コンテナが消えれば全てゼロになる。これを防ぐには、ボリューム(Volume)またはバインドマウント(bind mount)の設定が必須だ。
# docker-compose.yml でのボリューム定義例(記事内では使わないが概念として)
services:
db:
image: mysql:8.0
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:ボリュームはDocker Engineが管理する領域に作られ、コンテナが削除されても残る。バインドマウントはホストの任意のディレクトリをマウントする方式で、開発中のファイル同期には便利だが、ホスト側のファイルシステムに依存する。
bind mountは便利だが、ホストとコンテナを「同期」するのではなく「共有」する。その違いを忘れてvendor/をそのままマウントすると、毎回CIのビルド時間に泣くことになる。本番環境への移行を見据えたコンテナ化の費用対効果
個人開発の最終目標は、多くの場合「ローカルのスクリプト」から「本番で動くWebサービス」への昇華だ。その昇華の段階で、Dockerを採用していたかどうかが効いてくる。
Dockerを使っていない場合、本番環境への移行は茨の道になる。VPSに直接apt-get install phpで入れた環境をそのまま使うなら、「ローカルと本番の差異」が問題になる。ローカルのmacOSでは動くが、Ubuntuでは動かないPHP拡張。ローカルではphp -mで出ているimagickが、本番ではundefined functionを返す——典型的な「動かない」パターンだ。
一方、Dockerfileで環境定義を書いていれば、本番でもそのイメージをそのまま起動できる。AWS ECS、Fargate、Cloud Run、Fly.io、Railway——こうしたコンテナ前提のプラットフォームでは、Dockerfileを書くことがそのまま本番デプロイの入口になる。docker buildしてdocker pushして、マネージドサービスにデプロイ、という流れがそのまま通用する。
ただし、本番運用にDockerを採用すると、別途コストが発生する。
1. コンテナレジストリの費用:Docker Hubのプライベートリポジトリは無料枠が限定的。AWS ECRやGCP Artifact Registryに移行すると、ストレージと転送量で月額数百〜数千円。
2. オーケストレーションの学習コスト:ECSやKubernetesの概念(タスク定義、サービス、Pod、Deployment)を理解する必要がある。
3. 監視・ログ収集の構築:コンテナは Ephemeral(揮発的)なので、ログを標準出力に集約し、CloudWatch LogsやDatadogに流す設計が必要。
個人開発の規模感で考えるなら、最初のVPS直接運用 → コンテナ化のステップを踏むのが現実的だ。最初からKubernetesで本番を動かすのは、よほどの覚悟がない限りオーバースペックになる。
VPSに直接インストール(初期)→ Docker Composeでローカル統一 → Dockerfile整備 → クラウドのコンテナサービスへ移行この段階的移行を前提に、最初の段階で「Dockerfileの書き方の癖」を掴んでおくことが、後々の移行コストを劇的に下げる。具体的には、ローカルと本番で同じDockerfileを使う、機密情報はビルド時引数ではなくランタイム環境変数で渡す、ヘルスチェック用のエンドポイントを必ず実装する——この三つを習慣づけるかどうかで、本番移行時の痛苦度が桁違いになる。
結局のところ、Dockerはどこで導入すべきか
ここまでの話を整理する。
Dockerを導入しなくて良い場面:
- 単一言語・単一プロセスのローカル開発
- SQLiteや小さなJSONで完結するプロトタイプ
- フレームワーク標準のローカルサーバーで問題なく動く規模
Dockerを導入すべき場面:
- Web + DB + キャッシュなど、複数プロセスが連携する構成
- 異なるPHP/Python/Nodeバージョンを同一ホストで扱う案件
- 本番環境をコンテナ前提のクラウドサービスに移行する計画がある
- チーム開発で「動く環境」を配布する必要が出た
無理に導入しない方が良い場面:
- 学習目的がDockerそのものになっている(本来のアプリ開発が停滞している)
- 単一VPSで動かす小規模サービスで、コンテナ化のメリットが見えない
力技で解決できる範囲(VPSに直接インストール、Homebrewで頑張る、PHPのバージョン切り替えをスクリプト化)は、確かに存在する。しかし、その力技の積み重ねが「環境再構築のたびに半日潰れる」という運用負債を生む。
Dockerの本質は、「自分の環境をコードで記述する」という行為にある。docker-compose.ymlは環境構築手順の実行可能な仕様書であり、半年後に自分が何をしていたか思い出すためのドキュメントでもある。その価値が要るプロジェクトかどうか——それが、個人開発でDockerを導入するかどうかの、最終的な判断基準になる。
結局のところ、ツールに振り回されるのではなく、自分の開発スタイルに合わせて取り入れるのが最優先だ。Dockerを使わないことが悪いわけでも、Dockerを使うことが善でもない。問題は「今の自分のフェーズで、どちらが時間を生むか」だけである。
Related reading: Docker Composeの内部ネットワークでコンテナ間通信ができる仕組み and 個人開発のサーバー選定:VPSによる低コスト管理とPaaSの自動化.