メインコンテンツにスキップ

🐳 Dockerとは?

📖 定義

Dockerは、コンテナと呼ばれる隔離された環境でアプリケーションを実行するプラットフォームです。コンテナは、アプリケーションとすべての依存関係を1つにまとめ、どこでも同じように実行できるようにします。「私のマシンでは動く...」という問題を解決し、開発、テスト、デプロイを簡単で一貫性のあるものにします。

🎯 アナロジーで理解する

輸送コンテナ

Dockerを物流のコンテナに例えると:

従来の配送 (VM)
├─ 荷物ごとに異なる梱包
├─ サイズ/重量がバラバラ
├─ 輸送方法が異なる
└─ 非効率的、複雑

コンテナ配送 (Docker)
├─ 標準化されたコンテナ
├─ どんな荷物でも入れられる
├─ 船、トラック、列車どこでも同じ輸送
└─ 効率的、シンプル

Dockerコンテナ = 標準化されたソフトウェアパッケージ

アパート vs 一戸建て

仮想マシン (VM) = 一戸建て
├─ それぞれに完全なインフラが必要
├─ 土地、建物、電気、水道すべて別々
├─ コストが高い
└─ 起動が遅い

Dockerコンテナ = アパート
├─ 共通インフラを共有(土地、建物)
├─ 各戸は独立
├─ 効率的
└─ すぐに入居可能

⚙️ 動作原理

1. Dockerアーキテクチャ

┌─────────────────────────────────────┐
│ Docker Client (CLI) │
│ docker run, docker build, etc. │
└───────────────┬─────────────────────┘
│ API呼び出し
┌───────────────▼─────────────────────┐
│ Docker Daemon │
│ コンテナ/イメージ管理 │
└───────────────┬─────────────────────┘

┌───────────────▼─────────────────────┐
│ コンテナ(実行中のアプリ) │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │App 1│ │App 2│ │App 3│ │
│ └─────┘ └─────┘ └─────┘ │
└─────────────────────────────────────┘

┌───────────────▼─────────────────────┐
│ Host OS (Linux Kernel) │
└─────────────────────────────────────┘

2. イメージ vs コンテナ

イメージ = 設計図、クラス
├─ 読み取り専用
├─ レイヤー構造
├─ 再利用可能
└─ 例:ubuntu、node、nginx

コンテナ = 実行インスタンス、オブジェクト
├─ イメージから作成
├─ 実行可能
├─ 隔離された環境
└─ 複数作成可能

関係:
イメージ → コンテナ1
→ コンテナ2
→ コンテナ3

3. Dockerfile → イメージ → コンテナ

1. Dockerfileを書く(レシピ)
├─ FROM node:18
├─ COPY package.json .
├─ RUN npm install
└─ CMD ["npm", "start"]

2. イメージをビルド(調理)
docker build -t my-app .

3. コンテナを実行(提供)
docker run -p 3000:3000 my-app

💡 実践例

Dockerfileの作成

# Node.jsアプリケーションのDockerfile

# ベースイメージ
FROM node:18-alpine

# 作業ディレクトリを設定
WORKDIR /app

# package.jsonをコピー
COPY package*.json ./

# 依存関係をインストール
RUN npm ci --only=production

# ソースコードをコピー
COPY . .

# ポートを公開
EXPOSE 3000

# 環境変数
ENV NODE_ENV=production

# コンテナ起動時に実行するコマンド
CMD ["node", "server.js"]

イメージのビルドと実行

# 1. イメージをビルド
docker build -t my-node-app:1.0 .
# -t: タグ(名前:バージョン)
# .: 現在のディレクトリのDockerfileを使用

# 2. イメージを確認
docker images
# REPOSITORY TAG IMAGE ID CREATED
# my-node-app 1.0 abc123 2分前

# 3. コンテナを実行
docker run -d \
--name my-app \
-p 3000:3000 \
-e NODE_ENV=production \
my-node-app:1.0

# -d: バックグラウンド実行
# --name: コンテナ名
# -p: ポートマッピング(ホスト:コンテナ)
# -e: 環境変数

# 4. 実行中のコンテナを確認
docker ps

# 5. ログを確認
docker logs my-app

# 6. コンテナ内部にアクセス
docker exec -it my-app sh

# 7. コンテナを停止
docker stop my-app

# 8. コンテナを削除
docker rm my-app

# 9. イメージを削除
docker rmi my-node-app:1.0

Docker Compose(複数コンテナの管理)

# docker-compose.yml

version: '3.8'

services:
# Webアプリケーション
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DB_HOST=database
depends_on:
- database
- redis
volumes:
- ./logs:/app/logs

# データベース
database:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=myapp
volumes:
- db-data:/var/lib/mysql
ports:
- "3306:3306"

# キャッシュ
redis:
image: redis:7-alpine
ports:
- "6379:6379"

# Nginx(リバースプロキシ)
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- web

volumes:
db-data:
# Docker Composeコマンド

# すべてのサービスを起動
docker-compose up -d

# ログを確認
docker-compose logs -f web

# 特定のサービスを再起動
docker-compose restart web

# サービスをスケーリング
docker-compose up -d --scale web=3

# すべてのサービスを停止して削除
docker-compose down

# ボリュームも削除
docker-compose down -v

実例:React + Node.js + MongoDB

# frontend/Dockerfile
FROM node:18-alpine AS build

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Nginxで静的ファイルを配信
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# backend/Dockerfile
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

EXPOSE 5000
CMD ["node", "server.js"]
# docker-compose.yml
version: '3.8'

services:
frontend:
build:
context: ./frontend
ports:
- "80:80"
depends_on:
- backend

backend:
build:
context: ./backend
ports:
- "5000:5000"
environment:
- MONGO_URL=mongodb://mongodb:27017/myapp
depends_on:
- mongodb

mongodb:
image: mongo:6
volumes:
- mongo-data:/data/db
ports:
- "27017:27017"

volumes:
mongo-data:

データボリュームの管理

# ボリュームを作成
docker volume create my-data

# ボリューム一覧
docker volume ls

# ボリュームをコンテナにマウント
docker run -v my-data:/app/data my-app

# ホストディレクトリをマウント(開発時に便利)
docker run -v $(pwd):/app my-app

# 読み取り専用でマウント
docker run -v $(pwd):/app:ro my-app

# ボリュームを削除
docker volume rm my-data

# 使用していないボリュームをすべて削除
docker volume prune

.dockerignoreファイル

# .dockerignore

# Git
.git
.gitignore

# Node
node_modules
npm-debug.log

# 環境設定
.env
.env.local

# ビルド出力
dist
build

# IDE
.vscode
.idea

# テスト
coverage
*.test.js

# ドキュメント
README.md
docs/

🤔 よくある質問

Q1. Docker vs 仮想マシン?

A:

仮想マシン (VM)
┌─────────────────┐ ┌─────────────────┐
│ App A │ │ App B │
│ Libs │ │ Libs │
│ Guest OS │ │ Guest OS │
│ (Linux) │ │ (Ubuntu) │
└─────────────────┘ └─────────────────┘
┌─────────────────────────────────────┐
│ Hypervisor (VMware等) │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Host OS │
└─────────────────────────────────────┘

Dockerコンテナ
┌───────┐ ┌───────┐ ┌───────┐
│ App A │ │ App B │ │ App C │
│ Libs │ │ Libs │ │ Libs │
└───────┘ └───────┘ └───────┘
┌─────────────────────────────┐
│ Docker Engine │
└─────────────────────────────┘
┌─────────────────────────────┐
│ Host OS (Linux Kernel) │
└─────────────────────────────┘

比較:
VM Docker
サイズ GB MB
起動 分 秒
隔離 完全 プロセスレベル
パフォーマンス オーバーヘッド大 ネイティブに近い
移植性 低い 高い

Q2. Dockerイメージレイヤーとは?

A:

FROM node:18          # レイヤー1: ベースイメージ
WORKDIR /app # レイヤー2: 作業ディレクトリ
COPY package.json . # レイヤー3: package.json
RUN npm install # レイヤー4: 依存関係のインストール
COPY . . # レイヤー5: ソースコード
CMD ["node", "app.js"]# レイヤー6: 起動コマンド

# レイヤーキャッシング
# - 変更されていないレイヤーは再利用
# - ビルド速度の向上

# ✅ 良い例: 頻繁に変更されるものを後に
COPY package.json .
RUN npm install # キャッシュされる(package.json変更なければ)
COPY . . # コード変更のみ

# ❌ 悪い例: 頻繁に変更されるものを先に
COPY . . # コード変更のたびに
RUN npm install # npm installが再実行!

Q3. コンテナオーケストレーションとは?

A:

単一サーバー
┌─────────────────────┐
│ ┌───┐ ┌───┐ ┌───┐ │
│ │C1 │ │C2 │ │C3 │ │
│ └───┘ └───┘ └───┘ │
└─────────────────────┘

オーケストレーション (Kubernetes)
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Server1 │ │ Server2 │ │ Server3 │
│ ┌───┐ │ │ ┌───┐ │ │ ┌───┐ │
│ │C1 │ │ │ │C2 │ │ │ │C3 │ │
│ └───┘ │ │ └───┘ │ │ └───┘ │
└─────────┘ └─────────┘ └─────────┘

機能:
- 自動デプロイ
- スケーリング(自動拡張/縮小)
- ロードバランシング
- 自動復旧(コンテナが死んだら再起動)
- ローリングアップデート

ツール:
- Kubernetes(最も人気)
- Docker Swarm
- Amazon ECS

Q4. 開発環境でのDocker活用は?

A:

# シナリオ: チームメンバーごとに異なる環境

# チームメンバーA: macOS、Node 16
# チームメンバーB: Windows、Node 18
# チームメンバーC: Linux、Node 14

# 問題: 「私のマシンでは動く...」

# 解決策: Dockerで環境を統一

# docker-compose.yml
version: '3.8'
services:
app:
image: node:18
volumes:
- .:/app
working_dir: /app
command: npm run dev
ports:
- "3000:3000"

# すべてのチームメンバーが同じ環境を使用
docker-compose up

# メリット:
# 1. Node.jsのインストール不要
# 2. バージョンの統一
# 3. 依存関係の分離
# 4. 環境設定の共有

Q5. Dockerのセキュリティは?

A:

# ✅ セキュリティのベストプラクティス

# 1. 最小権限のベースイメージ
FROM node:18-alpine # ✅ 小さく安全
FROM node:18 # ❌ 不要なツールが多い

# 2. rootユーザーでない実行
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
USER nodejs # ✅ 権限を最小化

# 3. 機密情報の除外
# .dockerignoreに追加
.env
*.key
secrets/

# 4. マルチステージビルド(不要なツールを削除)
FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm run build

FROM node:18-alpine # 小さいイメージ
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/main.js"]

# 5. イメージのスキャン
docker scan my-image

# 6. 読み取り専用のルートファイルシステム
docker run --read-only my-app

# 7. リソース制限
docker run --memory="512m" --cpus="1" my-app

🎓 次のステップ

Dockerを理解したら、次を学んでみましょう:

  1. Gitとは?(作成予定)- バージョン管理とデプロイ
  2. Node.jsとは?(作成予定)- DockerでNodeアプリをデプロイ
  3. TDDとは? - Dockerでテストを実行

試してみる

# 1. Dockerのインストールを確認
docker --version

# 2. Hello World
docker run hello-world

# 3. Nginxを実行
docker run -d -p 8080:80 nginx
# http://localhost:8080にアクセス

# 4. コンテナを確認
docker ps

# 5. 停止と削除
docker stop <container-id>
docker rm <container-id>

# 6. 自分のアプリをコンテナ化
# - Dockerfileを作成
# - docker build
# - docker run

便利なコマンド

# イメージ管理
docker pull nginx # イメージをダウンロード
docker images # イメージ一覧
docker rmi nginx # イメージを削除

# コンテナ管理
docker run # コンテナを実行
docker ps # 実行中のコンテナ
docker ps -a # すべてのコンテナ
docker stop <id> # コンテナを停止
docker start <id> # コンテナを起動
docker restart <id> # コンテナを再起動
docker rm <id> # コンテナを削除

# ログとデバッグ
docker logs <id> # ログを確認
docker logs -f <id> # リアルタイムログ
docker exec -it <id> sh # コンテナ内部にアクセス
docker inspect <id> # 詳細情報

# クリーンアップ
docker system prune # 未使用リソースを削除
docker system prune -a # すべての未使用リソース
docker volume prune # 未使用ボリュームを削除

🎬 まとめ

Dockerは現代の開発に不可欠なツールです:

  • コンテナ: 隔離された実行環境
  • イメージ: アプリケーションパッケージ
  • 移植性: どこでも同じように実行
  • 効率性: 軽量で高速

「私のマシンでは動く」問題をDockerで解決しましょう! 🐳✨