「Dockerって、結局何が嬉しいの?」
「コマンドは打てるようになったけど、実務でどう設計・運用すればいいかわからない」
本記事は、そんな疑問を抱える開発者に向けて、Dockerの基本概念から実務で本当に使う実用的な知識までを、地に足の着いた粒度で解説した完全ガイドです。
📑 目次
- なぜ今Dockerなのか?(コンテナと仮想化)
- Dockerの全体像と核心概念(イメージ・コンテナ・レジストリ)
- 基本コマンド10選(これだけで日常業務の8割はカバー)
- Dockerfileの書き方とベストプラクティス
- Docker Composeによる複数コンテナの管理
- 実務で役立つ開発環境構築の実例(Web API + DB)
- 永続化(Volume)とネットワークの考え方
- 実務トラブルシューティングと運用ノウハウ
1. なぜ今Dockerなのか?(コンテナと仮想化)
従来の「仮想マシン(VM)」との違い
これまで使われていたVirtualBoxやVMwareなどの「ハイパーバイザ型仮想化」は、ホストOSの上にゲストOS(UbuntuやWindowsなど)を丸ごと立ち上げる仕組みでした。
- VMのデメリット: 起動が遅い(数分)、メモリやディスクの消費が大きい。
- Docker(コンテナ)の強み: ホストOSのカーネルを共有し、プロセスレベルで孤立した空間を作る。そのため起動が秒単位で、動作が非常に軽量。
「自分の環境では動いたのに」を過去のものにする
Dockerの本質は「環境のコード化(Infrastructure as Code)」です。
開発環境・テスト環境・本番環境をすべて同じDockerイメージから生成することで、OSの違いやライブラリのバージョン差異によるトラブルを根絶できます。
2. Dockerの全体像と核心概念
Dockerを理解するための3大要素:
- Dockerfile(レシピ): コンテナを作るための構成手順書。
- Docker Image(金型・金型から作られたテンプレート): アプリケーションと実行環境がパッケージ化された不変のファイル。
- Docker Container(実体・実家): イメージを元に作成された、実際に動いているプロセス空間。
[Dockerfile] --- (build) ---> [Docker Image] --- (run) ---> [Docker Container]
3. 基本コマンド10選
実務の日常操作で使う基本コマンド一覧です。
| コマンド | 説明 |
|---|---|
docker run <image> |
イメージからコンテナを作成して起動 |
docker ps |
実行中のコンテナ一覧を表示(-a で停止中も含む) |
docker stop <container> |
コンテナを停止 |
docker rm <container> |
コンテナを削除 |
docker rmi <image> |
イメージを削除 |
docker exec -it <container> bash |
起動中のコンテナに入って操作 |
docker logs -f <container> |
コンテナのログをリアルタイム表示 |
docker build -t <name> . |
Dockerfileからイメージを作成 |
docker images |
ローカルに保存されているイメージ一覧を表示 |
docker system prune |
未使用のコンテナ・イメージ・キャッシュを一括削除 |
4. Dockerfileの書き方とベストプラクティス
実務でそのまま使える、Node.jsアプリケーション用の標準的なDockerfileの例です。
# 1. 軽量なベースイメージを指定
FROM node:20-alpine AS builder
# 2. 作業ディレクリの設定
WORKDIR /app
# 3. 依存関係のキャッシュを活かすため package.json のみを先にコピー
COPY package*.json ./
# 4. 依存ライブラリのインストール
RUN npm ci
# 5. ソースコードのコピー
COPY . .
# 6. アプリケーションのビルド
RUN npm run build
# --- マルチステージビルド(本番軽量化) ---
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# 必要なファイルだけを前のステージからコピー
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
EXPOSE 3000
CMD ["node", "dist/main.js"]
実務でのポイント
-
レイヤーキャッシュの活用: 変更頻度の低いファイル(
package.json等)を先にコピーしてnpm installを行うことで、ビルド時間を劇的に短縮します。 - マルチステージビルド: ビルド用環境と実行用環境を分けることで、イメージサイズを数百MBから数兆MB単位まで軽量化できます。
5. Docker Composeによる複数コンテナの管理
Webアプリケーション、データベース、キャッシュサーバーなどをまとめて起動・管理するには docker-compose.yml を使用します。
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
depends_on:
- db
volumes:
- .:/app
- /app/node_modules
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
よく使う Compose コマンド
-
docker compose up -d: バックグラウンドで全サービス起動 -
docker compose down: コンテナ・ネットワークの削除停止 -
docker compose logs -f app: 特定サービスのログ監視
6. 実務で役立つ開発環境構築の実例
上記の docker-compose.yml では、サービス名 db がそのままネットワーク内部のホスト名になります。
-
アプリからの接続文字列:
postgres://user:pass@db:5432/mydb - ホスト(自分のPC)から
localhost:5432でDBクライアントツール(DBeaverやTablePlusなど)を繋ぎつつ、アプリコンテナ同士はDocker内部ネットワークで名前解決をして通信します。
7. 永続化(Volume)とネットワークの考え方
データの永続化(Volumes vs Bind Mounts)
コンテナは破棄されると内部のデータも消滅します。そのため、データの保持が必要な場合は2つの手法を使い分けます。
- Named Volume(
postgres_data:/var/lib/postgresql/data):
- Dockerが管理する領域。DBのデータなど、パフォーマンスと永続性が求められるものに利用。
- Bind Mount(
.:/app):
- ホストPCのディレクトリを直接マウント。開発中のローカルコード変更をコンテナへ即座に反映(ホットリロード)させたい場合に利用。
8. 実務トラブルシューティングと運用ノウハウ
よくあるトラブルと対処法
1. ディスク容量が圧迫される
ビルドキャッシュや不要なイメージが溜まりやすいため、定期的にクリーンアップを行います。
docker system prune -a --volumes
2. ポート衝突エラー(address already in use)
ローカルで起動している既存サービス(ローカルのPostgreSQLなど)や、別プロジェクトのDockerコンテナが同じポートを使っていることが原因です。
docker ps で確認するか、docker-compose.yml の左側のポート番号を変更します(例: "5433:5432")。
3. パーミッションエラー(Linux環境)
コンテナ内で作成されたファイルの所有者が root になり、ホスト側で編集できなくなる問題です。Dockerfile 内で適切な USER を指定するか、Composeで user: "${UID}:${GID}" を設定して回避します。
まとめとして、まずは 「Dockerfileを書く」→「Composeで動かす」 という一連の流れを手元で試すところから始めてみてください!