7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

「自分のPCでは動くのに、本番環境では動かない」
「新しいメンバーが開発環境を構築するのに丸1日かかる」

こんな経験はありませんか?Dockerを使えば、これらの問題を解決できます。

この記事では、Dockerの基本概念から実践的な使い方まで、段階的に解説します。記事を読み終える頃には、自信を持ってDockerを使った開発環境を構築できるようになっているはずです。

ただ Dockerは
コマンドを覚えるだけだと
次のような実務の壁で詰まりがちです。

  • composeは動くが 本番で再現しない
  • ボリュームの扱いを間違えて データが消える
  • ビルドキャッシュが効かず ずっと遅い
  • 開発環境は便利だが CIで壊れる

この記事は
単なるコマンド集ではなく
なぜそう設計するのか まで含めて整理します。

先に結論 迷ったらこの方針

開発composeと本番composeを分ける

  • 開発はホットリロード最優先
  • 本番は再現性と最小構成最優先

同じcomposeで両方を満たすのは難しいので
dev用とprod用を分ける方が結局速いです。

ビルドはキャッシュ前提でレイヤーを切る

Dockerfileの書き方で
体感速度が大きく変わります。
依存インストールとアプリコードのレイヤーを分離し
変更が多い部分でキャッシュを壊さないのがコツです。

永続化はボリューム 明示して扱う

何を残し 何を捨てるか を明示しないと
環境構築は再現できません。
DBなどの状態は named volume などで管理し
消して良い手順もセットで用意すると運用が楽です。

Dockerとは何か

コンテナ技術の概要

Dockerは、アプリケーションとその依存関係を「コンテナ」という軽量な仮想環境にパッケージングする技術です。

従来の仮想マシンとの違い

特徴 仮想マシン Docker
起動時間 数分 数秒
サイズ GB単位 MB単位
OS 各VMに完全なOS ホストOSのカーネルを共有
オーバーヘッド 大きい 小さい
分離レベル 完全 プロセスレベル

Dockerの基本概念

イメージ(Image)
アプリケーションとその実行に必要なすべてのファイル、設定、依存関係を含むテンプレート。読み取り専用。

コンテナ(Container)
イメージから作成された実行中のインスタンス。読み書き可能なレイヤーを持つ。

Dockerfile
イメージを作成するための設計図。テキストファイルにコマンドを記述。

Docker Hub
イメージを共有・配布するためのレジストリサービス。

Dockerのインストールと初期設定

Windows/Macの場合

Docker Desktopをインストールします。

# インストール確認
docker --version
docker compose version

Linuxの場合

# Ubuntu/Debianの場合
sudo apt update
sudo apt install docker.io docker-compose-v2

# サービスの起動
sudo systemctl start docker
sudo systemctl enable docker

# 現在のユーザーをdockerグループに追加(sudoなしで実行可能に)
sudo usermod -aG docker $USER
# 再ログインが必要

動作確認

# Hello Worldコンテナを実行
docker run hello-world

# 出力例
# Hello from Docker!
# This message shows that your installation appears to be working correctly.

基本的なDockerコマンド

イメージの操作

# イメージの検索
docker search nginx

# イメージのダウンロード
docker pull nginx:latest
docker pull node:20-alpine

# ローカルのイメージ一覧
docker images

# イメージの詳細情報
docker inspect nginx:latest

# イメージの削除
docker rmi nginx:latest

# 未使用イメージの一括削除
docker image prune -a

コンテナの操作

# コンテナの起動
docker run nginx

# バックグラウンドで起動(デタッチモード)
docker run -d nginx

# 名前を付けて起動
docker run -d --name my-nginx nginx

# ポートマッピング
docker run -d -p 8080:80 nginx
# ホストの8080ポートをコンテナの80ポートにマッピング

# 環境変数を設定
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql

# ボリュームマウント
docker run -d -v /host/path:/container/path nginx
docker run -d -v $(pwd):/app node:20

# 実行中のコンテナ一覧
docker ps

# すべてのコンテナ一覧(停止中含む)
docker ps -a

# コンテナのログ
docker logs my-nginx
docker logs -f my-nginx  # リアルタイム表示

# コンテナの停止
docker stop my-nginx

# コンテナの削除
docker rm my-nginx

# 停止と同時に削除
docker rm -f my-nginx

# すべての停止中コンテナを削除
docker container prune

コンテナ内での操作

# コンテナ内でコマンドを実行
docker exec my-nginx ls -la

# コンテナ内でシェルを起動(対話モード)
docker exec -it my-nginx bash
docker exec -it my-nginx sh  # bashがない場合

# 起動時にシェルで入る
docker run -it ubuntu bash

Dockerfileの書き方

基本的なDockerfile

# ベースイメージを指定
FROM node:20-alpine

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

# 依存関係ファイルをコピー
COPY package*.json ./

# 依存関係をインストール
RUN npm ci

# アプリケーションのソースコードをコピー
COPY . .

# ポートを公開
EXPOSE 3000

# アプリケーションを起動
CMD ["npm", "start"]

Dockerfileのベストプラクティス

# 軽量なベースイメージを使用
FROM node:20-alpine
# NG: FROM node:20 (フルイメージは大きい)

# マルチステージビルドで最終イメージを軽量化
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]

# レイヤーキャッシュを活用
# 変更頻度の低いものを先にコピー
COPY package*.json ./
RUN npm ci
# ソースコードは後でコピー
COPY . .

# .dockerignoreファイルを使用
# .dockerignoreファイルに以下を記述
# node_modules
# .git
# *.log
# .env

# 非rootユーザーで実行
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs

# 具体的なタグを使用
FROM node:20.10.0-alpine
# NG: FROM node:latest

実践的なDockerfile例

Python Flask アプリケーション

FROM python:3.12-slim

WORKDIR /app

# 依存関係を先にインストール(キャッシュ活用)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# 非rootユーザーを作成
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser

EXPOSE 5000

CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]

Go アプリケーション(マルチステージビルド)

# ビルドステージ
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

# 実行ステージ
FROM scratch
COPY --from=builder /app/main /main
EXPOSE 8080
ENTRYPOINT ["/main"]

Docker Compose

Docker Composeとは

複数のコンテナを定義・管理するためのツールです。YAMLファイルで設定を記述します。

基本的なdocker-compose.yml

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
    depends_on:
      - db
      - redis

  db:
    image: postgres:16-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password

  redis:
    image: redis:7-alpine

volumes:
  postgres_data:

Docker Composeコマンド

# コンテナを起動
docker compose up

# バックグラウンドで起動
docker compose up -d

# 特定のサービスだけ起動
docker compose up -d web

# ビルドして起動
docker compose up --build

# ログを表示
docker compose logs
docker compose logs -f web

# コンテナを停止
docker compose down

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

# サービスの状態確認
docker compose ps

# 特定のサービスでコマンド実行
docker compose exec web bash
docker compose exec db psql -U user -d myapp

実践的なDocker Compose設定

開発環境と本番環境の分離

# docker-compose.yml(共通設定)
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
# docker-compose.override.yml(開発環境、自動的に読み込まれる)
services:
  web:
    build:
      target: development
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development

  db:
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: devpassword
# docker-compose.prod.yml(本番環境)
services:
  web:
    build:
      target: production
    ports:
      - "80:3000"
    environment:
      - NODE_ENV=production
    restart: always

  db:
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    restart: always

secrets:
  db_password:
    file: ./secrets/db_password.txt
# 本番環境で起動
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

ヘルスチェックの設定

services:
  web:
    build: .
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  db:
    image: postgres:16-alpine
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
      interval: 10s
      timeout: 5s
      retries: 5

実践的なユースケース

Node.js + React + PostgreSQL の開発環境

services:
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    volumes:
      - ./frontend:/app
      - /app/node_modules
    ports:
      - "3000:3000"
    environment:
      - REACT_APP_API_URL=http://localhost:4000

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
    volumes:
      - ./backend:/app
      - /app/node_modules
    ports:
      - "4000:4000"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data

  adminer:
    image: adminer
    ports:
      - "8080:8080"

volumes:
  postgres_data:
  redis_data:

Nginx リバースプロキシ構成

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - web

  web:
    build: .
    expose:
      - "3000"
    environment:
      - NODE_ENV=production
# nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream web {
        server web:3000;
    }

    server {
        listen 80;
        server_name localhost;

        location / {
            proxy_pass http://web;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_cache_bypass $http_upgrade;
        }
    }
}

ネットワークとボリューム

Dockerネットワーク

# ネットワーク一覧
docker network ls

# ネットワークの作成
docker network create my-network

# コンテナをネットワークに接続して起動
docker run -d --name web --network my-network nginx
docker run -d --name api --network my-network node:20

# 既存のコンテナをネットワークに接続
docker network connect my-network existing-container

# ネットワークの詳細確認
docker network inspect my-network

Docker Composeでは自動的にネットワークが作成されます。

services:
  web:
    networks:
      - frontend
      - backend

  api:
    networks:
      - backend

  db:
    networks:
      - backend

networks:
  frontend:
  backend:

ボリューム

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

# ボリューム一覧
docker volume ls

# ボリュームの詳細
docker volume inspect my-data

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

# 未使用ボリュームの一括削除
docker volume prune

ボリュームの種類

services:
  db:
    image: postgres:16-alpine
    volumes:
      # 名前付きボリューム(永続化、Dockerが管理)
      - postgres_data:/var/lib/postgresql/data
      
      # バインドマウント(ホストのディレクトリをマウント)
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
      
      # 匿名ボリューム
      - /var/log/postgresql

volumes:
  postgres_data:
    # 外部で作成したボリュームを使用
    # external: true

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

イメージのセキュリティ

# 信頼できるベースイメージを使用
FROM node:20-alpine

# 特定のバージョンを指定
FROM node:20.10.0-alpine

# 非rootユーザーで実行
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nextjs -u 1001
USER nextjs

# 必要最小限のパッケージのみインストール
RUN apk add --no-cache tini

# マルチステージビルドで不要なファイルを除外
FROM node:20-alpine AS builder
# ビルド処理

FROM node:20-alpine AS runner
# 必要なファイルのみコピー

シークレット管理

# Docker Composeでのシークレット管理
services:
  web:
    image: myapp
    secrets:
      - db_password
      - api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    environment: API_KEY
# Docker Swarmモードでのシークレット
docker secret create db_password ./password.txt

ネットワークセキュリティ

services:
  web:
    networks:
      - frontend

  api:
    networks:
      - frontend
      - backend
    # 内部ネットワークのみに公開
    expose:
      - "4000"

  db:
    networks:
      - backend
    # ポートを外部に公開しない

networks:
  frontend:
  backend:
    internal: true  # 外部からのアクセスを遮断

トラブルシューティング

よくある問題と解決策

コンテナが起動しない

# ログを確認
docker logs container-name

# 詳細情報を確認
docker inspect container-name

# インタラクティブモードで起動してデバッグ
docker run -it --entrypoint /bin/sh image-name

ポートが使用中

# 使用中のポートを確認
docker ps --format "{{.Ports}}"

# ホスト側で使用中のポートを確認
# Windows
netstat -ano | findstr :3000

# Linux/Mac
lsof -i :3000

ディスク容量不足

# Docker使用量を確認
docker system df

# 未使用リソースを一括削除
docker system prune -a --volumes

# 特定のリソースを削除
docker container prune
docker image prune -a
docker volume prune
docker network prune

ビルドが遅い

# BuildKitを有効化(高速化)
DOCKER_BUILDKIT=1 docker build .

# キャッシュを活用
docker build --cache-from myapp:latest .

まとめ

この記事では、Dockerの基礎から実践的な使い方まで解説しました。

学んだこと

トピック 内容
基本概念 イメージ、コンテナ、Dockerfile
基本コマンド run, build, exec, logs
Dockerfile ベストプラクティス、マルチステージビルド
Docker Compose 複数コンテナの管理、環境分離
ネットワーク コンテナ間通信、セキュリティ
ボリューム データの永続化
セキュリティ 非root実行、シークレット管理

Dockerを使いこなすことで、「自分のPCでは動く」問題を解消し、チーム全体の開発効率を大幅に向上させることができます。まずは小さなプロジェクトから始めて、徐々に複雑な構成に挑戦してみてください!

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?