🐳
Dockerfileとdocker-compose.yml完全ガイド:初心者から上級者まで
Dockerfileとdocker-compose.yml完全ガイド:初心者から上級者まで
はじめに
DockerとDocker Composeは現代の開発において欠かせないツールです。この記事では、Dockerfileとdocker-compose.ymlの基礎から応用まで、実践的な例を交えながら解説します。
目次
Dockerfile基礎編
Dockerfileとは
Dockerfileは、Dockerイメージを作成するための設計図です。テキストファイルに一連の命令を記述し、それを元にDockerがイメージをビルドします。
基本的な命令
# ベースイメージの指定
FROM node:18-alpine
# 作業ディレクトリの設定
WORKDIR /app
# ファイルのコピー
COPY package*.json ./
# 依存関係のインストール
RUN npm ci --only=production
# アプリケーションコードのコピー
COPY . .
# ポートの公開
EXPOSE 3000
# コンテナ起動時のコマンド
CMD ["node", "index.js"]
主要な命令の説明
- FROM: ベースイメージを指定
- WORKDIR: コンテナ内の作業ディレクトリを設定
- COPY/ADD: ファイルをコンテナにコピー
- RUN: ビルド時にコマンドを実行
- EXPOSE: コンテナが使用するポートを宣言
- CMD/ENTRYPOINT: コンテナ起動時のコマンドを指定
Dockerfile応用編
マルチステージビルド
イメージサイズを削減する高度なテクニックです:
# ビルドステージ
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 実行ステージ
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]
レイヤーキャッシュの最適化
FROM python:3.11-slim
WORKDIR /app
# 依存関係ファイルを先にコピー(キャッシュ効率化)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# アプリケーションコードをコピー
COPY . .
CMD ["python", "app.py"]
セキュリティ強化
FROM node:18-alpine
# 非rootユーザーの作成
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# ファイルの所有権を設定
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# 非rootユーザーで実行
USER nodejs
EXPOSE 3000
CMD ["node", "index.js"]
ARGとENVの活用
# ビルド時の変数
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine
# 環境変数の設定
ENV NODE_ENV=production
ENV PORT=3000
WORKDIR /app
# ビルド引数の利用
ARG BUILD_DATE
ARG VCS_REF
LABEL build_date=$BUILD_DATE \
vcs_ref=$VCS_REF
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE $PORT
CMD ["node", "index.js"]
docker-compose.yml基礎編
docker-compose.ymlとは
複数のコンテナを定義し、まとめて管理するための設定ファイルです。
基本的な構成
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
depends_on:
- db
volumes:
- ./app:/app
- /app/node_modules
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
主要な設定項目
- version: Compose fileのバージョン
- services: コンテナの定義
- build: Dockerfileの場所
- image: 使用するイメージ
- ports: ポートマッピング
- environment: 環境変数
- volumes: データの永続化
- depends_on: サービスの依存関係
docker-compose.yml応用編
開発環境と本番環境の分離
# docker-compose.yml(ベース設定)
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
depends_on:
- db
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
# docker-compose.dev.yml(開発環境用)
version: '3.8'
services:
web:
build:
context: .
target: development
ports:
- "3000:3000"
volumes:
- ./src:/app/src
- ./public:/app/public
environment:
- NODE_ENV=development
- DEBUG=true
command: npm run dev
db:
ports:
- "5432:5432"
volumes:
- postgres_dev_data:/var/lib/postgresql/data
volumes:
postgres_dev_data:
# docker-compose.prod.yml(本番環境用)
version: '3.8'
services:
web:
build:
context: .
target: production
ports:
- "80:3000"
environment:
- NODE_ENV=production
restart: unless-stopped
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
db:
volumes:
- postgres_prod_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_prod_data:
使用方法:
# 開発環境
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
# 本番環境
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
ヘルスチェックの設定
version: '3.8'
services:
web:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
depends_on:
db:
condition: service_healthy
db:
image: postgres:15-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
ネットワークの詳細設定
version: '3.8'
services:
frontend:
build: ./frontend
networks:
- frontend-network
- backend-network
backend:
build: ./backend
networks:
- backend-network
- database-network
database:
image: postgres:15-alpine
networks:
- database-network
networks:
frontend-network:
driver: bridge
backend-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
database-network:
driver: bridge
internal: true # 外部からアクセス不可
シークレット管理
version: '3.8'
services:
web:
build: .
secrets:
- db_password
- api_key
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
API_KEY_FILE: /run/secrets/api_key
db:
image: postgres:15-alpine
secrets:
- db_password
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
file: ./secrets/api_key.txt
ベストプラクティス
1. イメージサイズの最小化
# 良い例:軽量なベースイメージを使用
FROM alpine:3.18
RUN apk add --no-cache python3 py3-pip
# 悪い例:不要なパッケージが含まれる
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3 python3-pip
2. .dockerignoreの活用
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.vscode
.idea
*.swp
*.swo
*~
3. ビルドキャッシュの最適化
# 頻繁に変更されないファイルを先にコピー
COPY package*.json ./
RUN npm ci
# 頻繁に変更されるファイルは後でコピー
COPY . .
4. セキュリティスキャン
# Dockerイメージのセキュリティスキャン
docker scout cves myimage:latest
# Trivyを使用したスキャン
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image myimage:latest
5. ログ管理
version: '3.8'
services:
web:
build: .
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
トラブルシューティング
1. ビルドが遅い
問題: Dockerビルドに時間がかかる
解決策:
- BuildKitを有効化:
DOCKER_BUILDKIT=1 docker build .
- キャッシュマウントの使用:
RUN \
pip install -r requirements.txt
2. コンテナ間の通信ができない
問題: サービス間で接続できない
解決策:
- サービス名を使用(localhostではなく)
- ネットワークの確認:
docker network ls
- DNSの確認:
docker exec container nslookup service_name
3. ボリュームの権限問題
問題: コンテナ内でファイルの読み書きができない
解決策:
# ユーザーIDを一致させる
ARG UID=1000
ARG GID=1000
RUN groupadd -g $GID appuser && \
useradd -m -u $UID -g $GID appuser
USER appuser
4. メモリ不足
問題: コンテナがOOMKillerに終了される
解決策:
services:
web:
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
高度なテクニック
1. ビルド時の条件分岐
# syntax=docker/dockerfile:1.4
FROM alpine:3.18
ARG INSTALL_DEV_TOOLS=false
RUN <<EOF
if [ "$INSTALL_DEV_TOOLS" = "true" ]; then
apk add --no-cache git vim curl
fi
EOF
2. heredocの活用
# syntax=docker/dockerfile:1.4
FROM python:3.11-slim
RUN <<EOF
apt-get update
apt-get install -y --no-install-recommends \
build-essential \
libpq-dev
apt-get clean
rm -rf /var/lib/apt/lists/*
EOF
3. Docker Composeでの環境変数の階層化
# .env.base
APP_NAME=myapp
LOG_LEVEL=info
# .env.dev
include .env.base
LOG_LEVEL=debug
DEBUG=true
# .env.prod
include .env.base
LOG_LEVEL=warning
DEBUG=false
4. 動的なポート割り当て
version: '3.8'
services:
web:
build: .
ports:
- "${PORT:-3000}:3000"
パフォーマンスチューニング
1. ビルドの並列化
# syntax=docker/dockerfile:1.4
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN \
CGO_ENABLED=0 go build -o app .
2. コンテナの起動順序制御
version: '3.8'
services:
web:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
command: >
sh -c "
until nc -z db 5432; do
echo 'Waiting for database...'
sleep 1
done
exec node index.js
"
まとめ
DockerfileとDocker Composeを効果的に使用することで、開発環境の構築からプロダクション環境へのデプロイまで、一貫性のある環境を提供できます。
重要なポイント:
- イメージサイズの最小化を心がける
- セキュリティを考慮した設計を行う
- 開発環境と本番環境を適切に分離する
- キャッシュを効果的に活用する
- ログとモニタリングを適切に設定する
これらの知識を活用して、より効率的で安全なコンテナ環境を構築してください。
Discussion
完全ガイドとありますが、
Compose
まわりが2023年6月末にEOLを迎えたCompose V1
に取り残されているように見えます。