Dockerを使い始めたばかりの頃、1つのコンテナの中にOS、Webサーバー、データベース、アプリケーションのすべてを詰め込んでいませんか?
それは「動くけれど、Dockerの真価を発揮できていない」状態かもしれません。
この記事では、システムにおいてDockerコンテナを「機能ごとに分離」する理由と、それらがどのように連携(融合)して一つのシステムとして機能するのか、実例を交えて解説します。
1. なぜコンテナを分けるのか?(メリットとデメリット)
「1コンテナ=1プロセス(役割)」がDockerの基本原則です。では、なぜわざわざ分ける必要があるのでしょうか。
メリット:柔軟性と堅牢性の向上
- スケーラビリティ(拡張性)
- アクセスが集中した際、データベースはそのままで「Webサーバーのコンテナだけ」を3つに増やす、といった部分的な増強が可能になります。
- 保守・更新のしやすさ
- 「Pythonのバージョンを上げたい」という時に、データベースのコンテナには一切触れずに、アプリのコンテナだけを差し替えることができます。影響範囲を最小限に抑えられます。
- 耐障害性
- アプリのコードにバグがあってアプリコンテナが落ちても、データベースコンテナは生きているため、データの破損リスクが下がります。
デメリット:構成の複雑化
- ネットワーク管理の手間
- コンテナ同士が通信するためのネットワーク設定が必要になります。「localhost」で繋がっていたものが、明示的な通信設定をしないと繋がらなくなります。
- デバッグの難易度
- ログが複数のコンテナに散らばるため、エラーの原因がどこにあるのか(アプリなのか、DBなのか、通信なのか)を追うのに工夫が必要です。
2. どうやって分離し、融合させるのか?
分離と融合の鍵となるのは、Docker Compose(またはKubernetesなどのオーケストレーションツール)です。
分離(Separation)のやり方
「Dockerfileを分ける」ことから始まります。
- Webサーバー用: Nginxの公式イメージをベースにしたDockerfile
- アプリ用: Python/Node.js等のランタイムを含んだDockerfile
- DB用: MySQL/PostgreSQL等の公式イメージ(Dockerfile不要な場合も多い)
融合(Fusion)のやり方
バラバラになったコンテナを、docker-compose.yml という設計図で接着します。
- 仮想ネットワーク: 自動的に作成される内部ネットワークでコンテナ同士を繋ぎます。
-
サービス名解決: IPアドレスの代わりに、「サービス名(例:
db)」で通信できるようにします。
3. 実践例:Webアプリケーションの3層構造
具体的に、一般的なWebシステム(Webサーバー + アプリケーション + データベース)を構築する場合を見てみましょう。
構成概要
- Frontend (Web Server): Nginx(静的ファイルの配信、リバースプロキシ)
- Backend (App): Python Flask(ビジネスロジック)
- Database: PostgreSQL(データ保存)
docker-compose.yml による融合
以下は、この3つを連携させるための定義ファイルのイメージです。
version: '3.8'
services:
# --- 1. Webサーバー (入り口) ---
web:
image: nginx:latest
ports:
- "80:80"
depends_on:
- app # appが起動してからwebを起動する
networks:
- my-network
# --- 2. アプリケーション (処理担当) ---
app:
build: ./app # ./appフォルダのDockerfileを使ってビルド
environment:
- DB_HOST=db # "db"という名前で接続先を指定
networks:
- my-network
# --- 3. データベース (保存担当) ---
db:
image: postgres:13
volumes:
- db-data:/var/lib/postgresql/data # データ永続化
networks:
- my-network
# コンテナ同士が会話するための専用回線
networks:
my-network:
# DBデータを消さないための保管庫
volumes:
db-data:
システムとしての動作フロー
ユーザーがアクセスした時、システム内部では以下のようにバケツリレーが行われます。
-
ユーザー がブラウザで
http://localhostにアクセス。 - Webコンテナ (Nginx) がリクエストを受け取り、処理が必要なものは Appコンテナ へ転送します。
-
Appコンテナ は、環境変数で渡されたホスト名
dbを使って DBコンテナ に接続し、データを取得します。 - 結果が逆順でユーザーに返されます。
これが「分離されているが、システムとして融合している」状態です。
まとめ:マイクロサービスへの第一歩
コンテナを分離することは、最初は設定ファイルが増えて面倒に感じるかもしれません。しかし、システムが成長し、チーム開発になった時、その恩恵は絶大です。
- DB担当者は
dbコンテナだけを気にする。 - フロント担当者は
webコンテナだけをいじる。
このように役割を明確に切り分ける設計こそが、モダンな開発現場で求められるスキルです。まずは身近なシステムを docker-compose で分割することから始めてみませんか?