1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Dockerってなんだ?〜「コンテナ」の正体を理解して開発環境を革命する完全ガイド〜

1
Posted at

この記事の対象読者

  • Linuxの基本コマンドは使えるが、Dockerを「なんとなく」使っている方
  • docker runは叩けるけど、コンテナと仮想マシンの違いを説明できない方
  • WSL2上でDockerを使っているが、イメージ・レイヤー・ボリュームの仕組みを理解したい方

この記事で得られること

  • コンテナの正体: 仮想マシンとの根本的な違いをカーネルレベルで理解できる
  • Dockerの全体像: イメージ、コンテナ、ボリューム、ネットワークの関係が図解でわかる
  • 実践力: Dockerfileの書き方、マルチステージビルド、GPUコンテナの構築まで身につく

この記事で扱わないこと

  • Docker Composeによる複数コンテナの管理(次回記事で扱います)
  • Docker Swarm / Kubernetesによるオーケストレーション
  • Docker Desktop の GUI操作の詳細

1. Dockerとの出会い

「Docker使ってみて」と言われて、よくわからないままdocker runした。あの日から何も変わっていない。

これ、私のことです。PyTorchの環境構築で「Dockerイメージ使えば一発ですよ」と言われ、言われるがままdocker run。動いた。でも「なぜ動いたのか」「何が起きているのか」は理解していなかった。

ある日、RTX 5090を買ってCUDA環境をDockerで構築しようとしたら、コンテナ内からGPUが見えない。docker buildしたらイメージが30GBを超えてWSL2のディスクが溢れる。ボリュームマウントしたはずのデータが消える。全部「Dockerの仕組みを理解していなかった」のが原因でした。

Dockerを一言で説明するなら、「アプリケーションとその実行環境をまるごとパッケージ化して、どこでも同じように動かすためのコンテナプラットフォーム」です。

料理に例えるなら、仮想マシンが「キッチンごと引っ越す」なら、Dockerは「レシピと食材をジップロックに詰めて持っていく」。キッチン(OS)は共有するから軽い。でもジップロックの中身は完全に独立しているから、他の料理と混ざらない。

ここまでで、Dockerのざっくりしたイメージが掴めたでしょうか。次は、この記事で使う用語を整理しておきましょう。


2. 前提知識の確認

本題に入る前に、この記事で頻出する用語を確認します。

2.1 コンテナ とは

Linuxカーネルのnamespace(名前空間)cgroups(コントロールグループ)を利用して、プロセスを隔離した実行環境のことです。仮想マシンと違い、独自のOSカーネルを持ちません。ホストOSのカーネルを共有するため、起動が速く、軽量です。

2.2 イメージ とは

コンテナの「設計図」です。アプリケーションのコード、ランタイム、ライブラリ、設定ファイルなどを含む読み取り専用のテンプレート。イメージから何個でもコンテナを作成できます。

2.3 レイヤー とは

Dockerイメージは複数の読み取り専用レイヤーの積み重ねで構成されています。Dockerfileの各命令(FROM, RUN, COPY等)が1つのレイヤーを作ります。共通のレイヤーは複数イメージ間で共有されるため、ディスクを節約できます。

2.4 レジストリ とは

Dockerイメージを保存・配布するサービスです。最も有名なのはDocker Hubhub.docker.com)。他にGitHub Container Registry(ghcr.io)、Amazon ECR、Google Artifact Registryなどがあります。

これらの用語が押さえられたら、Dockerの背景を見ていきましょう。


3. Dockerが生まれた背景

3.1 「うちの環境では動くんだけど...」問題

Dockerが登場する前、ソフトウェアのデプロイには根深い問題がありました。

「It works on my machine(私のマシンでは動く)」

開発者のPCでは動くのに、本番サーバーに持っていくと動かない。Pythonのバージョンが違う、ライブラリのバージョンが違う、OS自体が違う。この問題を根本的に解決するために、2013年にSolomon Hykes率いるdotCloud社(後にDocker社に改名)がDockerをオープンソースとしてリリースしました。

3.2 仮想マシンではダメだったのか

「環境ごとパッケージ化」は仮想マシンでもできました。VMwareやVirtualBoxで仮想マシンのイメージを配布すれば、同じ環境を再現できます。しかし:

問題 仮想マシン Docker
サイズ 数GB〜数十GB(OS込み) 数MB〜数百MB(カーネル不要)
起動時間 数分 数秒以下
リソース消費 OS分のメモリ・CPUが必要 ホストOSとカーネルを共有
密度 1台に数個〜十数個 1台に数百個
イメージ共有 巨大ファイルのコピー レイヤー共有で効率的
【仮想マシン】                    【Docker コンテナ】
┌─────┐ ┌─────┐ ┌─────┐        ┌─────┐ ┌─────┐ ┌─────┐
│App A│ │App B│ │App C│        │App A│ │App B│ │App C│
├─────┤ ├─────┤ ├─────┤        ├─────┤ ├─────┤ ├─────┤
│Libs │ │Libs │ │Libs │        │Libs │ │Libs │ │Libs │
├─────┤ ├─────┤ ├─────┤        └──┬──┘ └──┬──┘ └──┬──┘
│Guest│ │Guest│ │Guest│           │      │      │
│ OS  │ │ OS  │ │ OS  │        ┌──┴──────┴──────┴──┐
├─────┴─┴─────┴─┴─────┤        │  Docker Engine     │
│    ハイパーバイザー     │        ├────────────────────┤
├──────────────────────┤        │   ホスト OS         │
│     ホスト OS         │        │  (カーネル共有)     │
├──────────────────────┤        ├────────────────────┤
│    ハードウェア        │        │    ハードウェア      │
└──────────────────────┘        └────────────────────┘

OS×3 = 重い                      OS×1 = 軽い

3.3 Dockerのエコシステム(2026年現在)

Dockerは単一のツールではなく、巨大なエコシステムに成長しています。

コンポーネント 役割 2026年現在のバージョン
Docker Engine コンテナランタイム v29.x
Docker Desktop Win/Mac向け統合環境 v4.42+
Docker Compose 複数コンテナの定義・管理 v5.x(Go SDK搭載)
Docker Hub 公式イメージレジストリ -
Docker Buildx マルチプラットフォームビルド v0.22+
Docker Scout イメージのセキュリティ分析 -
Docker Model Runner LLM推論の実行基盤(新機能) -

2026年の注目: Docker Desktop 4.42以降でDocker Model Runnerが搭載されました。docker modelコマンドでLLMモデルの管理・推論が可能に。OpenAI互換APIやAnthropic互換APIを公開でき、さらにDocker MCP ToolkitでMCPサーバーの管理もできるようになっています。AI開発者にとってDockerの重要性はますます増しています。

背景がわかったところで、基本的な仕組みを見ていきましょう。


4. 基本概念と仕組み

4.1 コンテナの隔離メカニズム

Dockerコンテナの「隔離」は、Linuxカーネルの2つの機能で実現されています。

namespace(名前空間) — 「何が見えるか」を制御

namespace 隔離対象 効果
PID プロセスID コンテナ内のプロセスはホストの他のプロセスが見えない
NET ネットワーク コンテナ固有のIPアドレス・ポート空間
MNT マウントポイント コンテナ固有のファイルシステム
UTS ホスト名 コンテナ固有のホスト名
IPC プロセス間通信 共有メモリの分離
USER UID/GID コンテナ内のroot ≠ ホストのroot

cgroups(コントロールグループ) — 「どれだけ使えるか」を制御

リソース 制御内容
CPU 使用率の上限、優先度
メモリ 使用量の上限
ディスクI/O 読み書き速度の制限
ネットワーク 帯域幅の制限

4.2 イメージとレイヤーの仕組み

Dockerイメージの構造を理解するのが、Docker習得の最大の鍵です。

Dockerfile:                     生成されるレイヤー:
┌─────────────────────┐        ┌─────────────────────┐
│ FROM python:3.12    │───────→│ Layer 1: Python基盤  │ ← 200MB(共有可能)
├─────────────────────┤        ├─────────────────────┤
│ COPY requirements.. │───────→│ Layer 2: requirements│ ← 1KB
├─────────────────────┤        ├─────────────────────┤
│ RUN pip install ... │───────→│ Layer 3: pip packages│ ← 500MB
├─────────────────────┤        ├─────────────────────┤
│ COPY . .            │───────→│ Layer 4: アプリコード │ ← 10MB
├─────────────────────┤        ├─────────────────────┤
│ CMD ["python",...]  │───────→│ Layer 5: 起動設定     │ ← メタデータのみ
└─────────────────────┘        └─────────────────────┘

イメージ = すべてのレイヤーの合計(読み取り専用)
コンテナ = イメージ + 書き込み可能レイヤー(薄い1層)

レイヤーキャッシュの法則: Dockerは各レイヤーをキャッシュします。Dockerfileの上から順に実行し、変更がないレイヤーはキャッシュを再利用します。だからCOPY requirements.txtCOPY . .より先に書くと、コードを変えてもpipのレイヤーはキャッシュが効いてビルドが速くなる。

4.3 ボリュームとバインドマウント

コンテナ内のデータは、コンテナを削除すると消えます。データを永続化するには:

方式 コマンド例 データの場所 用途
ボリューム -v mydata:/app/data Docker管理領域 DB、永続データ
バインドマウント -v $(pwd):/app ホストの任意パス 開発中のソースコード
tmpfs --tmpfs /tmp メモリ上 一時ファイル、秘密情報
┌──────────────────────────────────────────────┐
│                 ホスト OS                      │
│                                                │
│  ┌──────────────┐   ┌──────────────────────┐  │
│  │  Docker Volume │   │ ホストディレクトリ     │  │
│  │  /var/lib/     │   │ /home/user/project   │  │
│  │  docker/volumes│   │                      │  │
│  └──────┬───────┘   └──────────┬───────────┘  │
│         │                       │               │
│  ┌──────┴───────────────────────┴───────────┐  │
│  │            Docker コンテナ                 │  │
│  │  /app/data ←── ボリューム                  │  │
│  │  /app      ←── バインドマウント             │  │
│  │  /tmp      ←── tmpfs(メモリ上)            │  │
│  └──────────────────────────────────────────┘  │
└──────────────────────────────────────────────┘

WSL2でのバインドマウント注意: /mnt/c/(Windows側)をマウントすると9Pプロトコル経由になり極端に遅くなります。WSL2のLinux FS(/home/...)をマウント元にしてください。

4.4 ネットワーク

Dockerは複数のネットワークドライバを提供しています。

ドライバ 用途 特徴
bridge(デフォルト) 単一ホスト内 コンテナ間通信、NATでホストに公開
host パフォーマンス重視 ホストのネットワークを直接使用
none 完全隔離 ネットワークなし
overlay マルチホスト Docker Swarm / クラスタ環境向け

基本概念が理解できたところで、実際にコードを書いて動かしてみましょう。


5. 実践:実際に使ってみよう

5.1 環境構築

この記事の実践パートは、以下の環境で動作確認しています。

項目 バージョン
OS Windows 11 Pro 24H2 + WSL2
ディストロ Ubuntu 24.04 LTS
Docker Engine 29.x
Docker Desktop 4.42+
Docker Compose v5.x
GPU NVIDIA RTX 5090

5.2 環境別の設定ファイル(daemon.json)

Docker Engineの挙動はdaemon.jsonで制御します。

開発環境用(daemon.json.dev)

{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "features": {
    "buildkit": true
  },
  "debug": true,
  "dns": ["8.8.8.8", "8.8.4.4"],
  "default-address-pools": [
    {
      "base": "172.20.0.0/16",
      "size": 24
    }
  ]
}

本番環境用(daemon.json.prod)

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "5"
  },
  "storage-driver": "overlay2",
  "features": {
    "buildkit": true
  },
  "debug": false,
  "live-restore": true,
  "userland-proxy": false,
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 65536,
      "Soft": 65536
    }
  },
  "default-address-pools": [
    {
      "base": "172.30.0.0/16",
      "size": 24
    }
  ]
}

テスト/CI環境用(daemon.json.ci)

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "5m",
    "max-file": "1"
  },
  "storage-driver": "overlay2",
  "features": {
    "buildkit": true
  },
  "debug": false,
  "builder": {
    "gc": {
      "defaultKeepStorage": "5GB",
      "enabled": true
    }
  }
}

5.3 Dockerfileの書き方(基本から最適化まで)

初心者が書きがちなDockerfile(BAD)

# ❌ BAD: よくある初心者のDockerfile
FROM python:3.12

WORKDIR /app
COPY . .
RUN pip install -r requirements.txt

CMD ["python", "main.py"]

問題点:

  • COPY . .が先にあるため、コードを1行変えるだけでpip installが再実行される
  • フルサイズのPythonイメージ(約1GB)を使用
  • rootユーザーで実行(セキュリティリスク)
  • .dockerignoreがないとゴミファイルもコピーされる

最適化したDockerfile(GOOD)

# ✅ GOOD: 最適化されたDockerfile
# === ステージ1: ビルドステージ ===
FROM python:3.12-slim AS builder

WORKDIR /app

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

# === ステージ2: 実行ステージ ===
FROM python:3.12-slim AS runtime

# セキュリティ: 非rootユーザーを作成
RUN groupadd -r appuser && useradd -r -g appuser appuser

WORKDIR /app

# ビルドステージからpipパッケージだけコピー
COPY --from=builder /install /usr/local

# アプリコードをコピー
COPY --chown=appuser:appuser . .

# 非rootユーザーに切り替え
USER appuser

# ヘルスチェック
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')" || exit 1

EXPOSE 8080

CMD ["python", "main.py"]
# .dockerignore(必須)
.git
.gitignore
__pycache__
*.pyc
.env
.venv
node_modules
*.md
Dockerfile
docker-compose*.yml
.dockerignore

5.4 Docker操作の実践スクリプト

#!/usr/bin/env bash
# docker_guide.sh - Docker操作ガイドスクリプト
# 実行方法: bash docker_guide.sh

set -euo pipefail

echo "=========================================="
echo " Docker 実践ガイド"
echo "=========================================="

echo ""
echo "=== 1. Docker情報の確認 ==="
docker version --format '  Client: {{.Client.Version}} / Server: {{.Server.Version}}'
echo "  ストレージドライバ: $(docker info --format '{{.Driver}}')"
echo "  イメージ数: $(docker images -q | wc -l)"
echo "  コンテナ数: $(docker ps -aq | wc -l)(実行中: $(docker ps -q | wc -l))"
echo ""

echo "=== 2. イメージ操作 ==="
cat << 'EOF'
# イメージの取得
$ docker pull python:3.12-slim

# イメージの一覧
$ docker images

# イメージの詳細(レイヤー構造を確認)
$ docker history python:3.12-slim

# イメージサイズの確認
$ docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}"

# 不要イメージの削除
$ docker image prune          # ダングリングイメージのみ
$ docker image prune -a       # 未使用イメージもすべて
EOF
echo ""

echo "=== 3. コンテナ操作 ==="
cat << 'EOF'
# コンテナの起動(バックグラウンド)
$ docker run -d --name myapp -p 8080:8080 myimage

# コンテナに入る
$ docker exec -it myapp bash

# ログの確認
$ docker logs myapp -f --tail 100

# リソース使用状況のリアルタイム表示
$ docker stats

# コンテナの停止・削除
$ docker stop myapp
$ docker rm myapp

# 全停止コンテナの一括削除
$ docker container prune
EOF
echo ""

echo "=== 4. ボリューム操作 ==="
cat << 'EOF'
# ボリュームの作成
$ docker volume create mydata

# ボリューム一覧
$ docker volume ls

# ボリューム付きでコンテナ起動
$ docker run -d -v mydata:/app/data myimage

# バインドマウント(開発時に使用)
$ docker run -d -v $(pwd):/app myimage

# ボリュームの中身を確認(一時コンテナで)
$ docker run --rm -v mydata:/data busybox ls -la /data

# 不要ボリュームの削除
$ docker volume prune
EOF
echo ""

echo "=== 5. ディスク使用量の全体確認 ==="
echo "$ docker system df"
docker system df 2>/dev/null || echo "(Docker未起動)"
echo ""
echo "# 一括クリーンアップ(注意: 停止コンテナ、未使用イメージ・ボリュームを削除)"
echo '$ docker system prune -a --volumes'
echo ""

echo "=== 6. よく使うワンライナー ==="
cat << 'EOF'
# 全コンテナ停止
$ docker stop $(docker ps -q)

# 全コンテナ削除
$ docker rm $(docker ps -aq)

# イメージのサイズ順ソート
$ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -rh

# 特定コンテナのIPアドレス
$ docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container>

# コンテナ内の環境変数一覧
$ docker exec <container> env
EOF

echo ""
echo "=========================================="
echo "✅ ガイド完了!"

5.5 実行結果

マルチステージビルドの効果:

$ docker build -t myapp:optimized -f Dockerfile.good .

[+] Building 45.2s (12/12) FINISHED
 => [builder 1/3] FROM python:3.12-slim
 => [builder 2/3] COPY requirements.txt .
 => [builder 3/3] RUN pip install ...          ← キャッシュされる
 => [runtime 1/4] FROM python:3.12-slim
 => [runtime 2/4] RUN groupadd ...
 => [runtime 3/4] COPY --from=builder ...
 => [runtime 4/4] COPY . .
 => exporting to image

# イメージサイズの比較
$ docker images --format "{{.Repository}}:{{.Tag}}\t{{.Size}}"
myapp:naive        1.2GB     ← 最適化前
myapp:optimized    285MB     ← 最適化後(76%削減)

5.6 よくあるエラーと対処法

エラー 原因 対処法
Cannot connect to the Docker daemon Docker Engineが起動していない WSL2: Docker Desktopを起動。Linux: sudo systemctl start docker
port is already allocated 同じポートを使うコンテナが既に存在 docker psで確認 → 停止するか別ポートを指定(-p 8081:8080
no space left on device Dockerのディスク使用量が限界 docker system prune -a --volumesでクリーンアップ。WSL2の場合は.wslconfigの仮想ディスクサイズも確認
COPY failed: file not found .dockerignoreでコピー対象が除外されている、またはビルドコンテキスト外のファイル .dockerignoreを確認。docker buildのコンテキスト(.)に対象ファイルがあるか確認
RuntimeError: No CUDA GPUs are available GPUがコンテナに渡されていない docker run --gpus allを指定。NVIDIA Container Toolkitがインストールされているか確認
OOMKilled コンテナのメモリ上限超過 docker run -m 4gでメモリ上限を引き上げる。アプリのメモリリークも疑う

docker system prune -a --volumesは本番環境で絶対に実行しないでください。永続データを含むボリュームもすべて削除されます。開発環境でのクリーンアップ専用コマンドです。

5.7 環境診断スクリプト

#!/usr/bin/env python3
"""
Docker環境診断スクリプト
実行方法: python3 check_docker_env.py
"""

import subprocess
import json
import shutil
import sys
import os


def run_cmd(cmd: str) -> str:
    """コマンドを実行して結果を返す"""
    try:
        result = subprocess.run(
            cmd, shell=True, capture_output=True, text=True, timeout=15
        )
        return result.stdout.strip()
    except (subprocess.TimeoutExpired, Exception):
        return ""


def run_json(cmd: str) -> dict:
    """JSONを返すコマンドを実行"""
    output = run_cmd(cmd)
    try:
        return json.loads(output)
    except (json.JSONDecodeError, Exception):
        return {}


def check_docker_environment():
    """Docker環境を包括的にチェック"""
    issues = []
    warnings = []

    print("=" * 55)
    print(" Docker 環境診断レポート")
    print("=" * 55)

    # --- 1. Docker基本情報 ---
    print("\n🐳 Docker基本情報:")
    if not shutil.which("docker"):
        print("  ❌ Dockerがインストールされていません")
        return

    client_ver = run_cmd("docker version --format '{{.Client.Version}}' 2>/dev/null")
    server_ver = run_cmd("docker version --format '{{.Server.Version}}' 2>/dev/null")

    if client_ver:
        print(f"  Client: {client_ver}")
    if server_ver:
        print(f"  Server: {server_ver}")
    else:
        issues.append("Docker Engineに接続できません。Docker Desktopが起動しているか確認してください。")
        print("  ❌ Serverに接続不可")
        return

    # Compose
    compose_ver = run_cmd("docker compose version --short 2>/dev/null")
    print(f"  Compose: {compose_ver or '未インストール'}")

    # BuildKit
    buildkit = run_cmd("docker info --format '{{.ClientInfo.Plugins}}' 2>/dev/null")
    print(f"  BuildKit: {'有効' if 'buildx' in str(buildkit) else '要確認'}")

    # --- 2. リソース使用状況 ---
    print("\n📊 リソース使用状況:")
    df_output = run_cmd("docker system df --format '{{.Type}}\t{{.Size}}\t{{.Reclaimable}}' 2>/dev/null")
    if df_output:
        print(f"  {'種別':<15} {'使用量':<12} {'回収可能'}")
        for line in df_output.strip().split('\n'):
            parts = line.split('\t')
            if len(parts) >= 3:
                print(f"  {parts[0]:<15} {parts[1]:<12} {parts[2]}")

    # --- 3. コンテナ状況 ---
    print("\n📦 コンテナ状況:")
    running = run_cmd("docker ps -q 2>/dev/null | wc -l").strip()
    stopped = run_cmd("docker ps -aq --filter 'status=exited' 2>/dev/null | wc -l").strip()
    print(f"  実行中: {running}")
    print(f"  停止中: {stopped}")

    if int(stopped) > 10:
        warnings.append(f"停止中のコンテナが{stopped}個あります。`docker container prune`で削除を検討してください。")

    # --- 4. イメージ状況 ---
    print("\n🖼️  イメージ状況:")
    total_images = run_cmd("docker images -q 2>/dev/null | wc -l").strip()
    dangling = run_cmd("docker images -f 'dangling=true' -q 2>/dev/null | wc -l").strip()
    print(f"  合計: {total_images}")
    print(f"  ダングリング(未タグ): {dangling}")

    if int(dangling) > 5:
        warnings.append(f"ダングリングイメージが{dangling}個あります。`docker image prune`で削除を推奨します。")

    # 上位5イメージ
    top_images = run_cmd(
        "docker images --format '{{.Repository}}:{{.Tag}}\t{{.Size}}' 2>/dev/null | head -5"
    )
    if top_images:
        print("  上位5イメージ:")
        for line in top_images.strip().split('\n'):
            print(f"    {line}")

    # --- 5. GPU ---
    print("\n🎮 GPU (NVIDIA Container Toolkit):")
    nvidia_runtime = run_cmd(
        "docker info --format '{{.Runtimes}}' 2>/dev/null"
    )
    if "nvidia" in str(nvidia_runtime).lower():
        print("  NVIDIA Runtime: 有効 ✅")
        gpu_test = run_cmd(
            "docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu24.04 "
            "nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null"
        )
        if gpu_test:
            print(f"  GPU (コンテナ内): {gpu_test}")
        else:
            warnings.append("NVIDIA Runtimeは有効ですが、コンテナ内からGPUにアクセスできません。")
    else:
        print("  NVIDIA Runtime: 未検出")
        print("  → GPU不要なら問題なし。GPU利用時はNVIDIA Container Toolkitをインストール")

    # --- 6. ネットワーク ---
    print("\n🌐 ネットワーク:")
    networks = run_cmd(
        "docker network ls --format '{{.Name}} ({{.Driver}})' 2>/dev/null"
    )
    if networks:
        for line in networks.strip().split('\n'):
            print(f"  {line}")

    # --- 7. WSL2固有の確認 ---
    is_wsl = os.path.exists("/proc/sys/fs/binfmt_misc/WSLInterop")
    if is_wsl:
        print("\n🪟 WSL2固有チェック:")
        docker_context = run_cmd("docker context show 2>/dev/null")
        print(f"  コンテキスト: {docker_context}")

        # ディスク使用量
        vhdx_size = run_cmd(
            "ls -lh /mnt/wslg/distro/../../*.vhdx 2>/dev/null | awk '{print $5}' | head -1"
        )
        if vhdx_size:
            print(f"  VHDxサイズ: {vhdx_size}")

    # --- 結果サマリー ---
    print("\n" + "=" * 55)
    if issues:
        print("❌ 問題:")
        for issue in issues:
            print(f"  🔴 {issue}")
    if warnings:
        print("⚠️  注意:")
        for w in warnings:
            print(f"  🟡 {w}")
    if not issues and not warnings:
        print("✅ Docker環境は正常です!")
    print("=" * 55)


if __name__ == "__main__":
    check_docker_environment()

実装方法がわかったので、次は具体的なユースケースを見ていきます。


6. ユースケース別ガイド

6.1 ユースケース1: AI/ML開発のGPUコンテナ

想定読者: CUDA環境をDockerで構築し、PyTorchをコンテナ内で動かしたい方

推奨構成: Docker + NVIDIA Container Toolkit + CUDA base image

サンプルコード:

# Dockerfile.gpu - AI/ML開発用GPUコンテナ
# ビルド: docker build -t ai-dev -f Dockerfile.gpu .
# 実行:   docker run --gpus all -it -v $(pwd):/workspace ai-dev

# === ステージ1: 依存関係のインストール ===
FROM nvidia/cuda:12.4.1-devel-ubuntu24.04 AS builder

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3 python3-pip python3-venv \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --break-system-packages \
    --prefix=/install -r requirements.txt

# === ステージ2: 実行環境 ===
FROM nvidia/cuda:12.4.1-runtime-ubuntu24.04 AS runtime

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3 python3-pip \
    && rm -rf /var/lib/apt/lists/*

# 非rootユーザー
RUN groupadd -r mluser && useradd -r -g mluser -m mluser

WORKDIR /workspace

# ビルドステージからPythonパッケージをコピー
COPY --from=builder /install /usr/local

# CUDA環境変数
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility

USER mluser

CMD ["bash"]
# requirements.txt
torch==2.6.0
torchvision==0.21.0
torchaudio==2.6.0
numpy>=1.26
pandas>=2.2
matplotlib>=3.9
jupyter>=1.0
#!/usr/bin/env bash
# run_gpu_container.sh - GPUコンテナの起動
# 実行方法: bash run_gpu_container.sh

set -euo pipefail

IMAGE_NAME="ai-dev"
CONTAINER_NAME="ai-workspace"

echo "=== GPUコンテナ起動 ==="

# ビルド
echo "[1/2] イメージをビルド中..."
docker build -t "$IMAGE_NAME" -f Dockerfile.gpu .

# 起動
echo "[2/2] コンテナを起動中..."
docker run --gpus all -it --rm \
    --name "$CONTAINER_NAME" \
    -v "$(pwd)":/workspace \
    -p 8888:8888 \
    --shm-size=8g \
    "$IMAGE_NAME" \
    python3 -c "
import torch
print('PyTorch:', torch.__version__)
print('CUDA:', torch.cuda.is_available())
if torch.cuda.is_available():
    print('GPU:', torch.cuda.get_device_name(0))
    print('VRAM:', f\"{torch.cuda.get_device_properties(0).total_mem / 1024**3:.1f} GB\")
"

--shm-size=8gが重要です。PyTorchのDataLoaderは/dev/shm(共有メモリ)を使います。デフォルトの64MBでは足りずにクラッシュすることがあります。

6.2 ユースケース2: マルチステージビルドでWebアプリを軽量化

想定読者: Dockerイメージのサイズが肥大化して困っている方

推奨構成: マルチステージビルド + distrolessベースイメージ

サンプルコード:

# Dockerfile.web - マルチステージビルドの実例
# Node.js + TypeScript アプリを最小サイズにパッケージ

# === ステージ1: 依存関係 ===
FROM node:22-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev

# === ステージ2: ビルド ===
FROM node:22-slim AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

# === ステージ3: 実行(最小構成) ===
FROM gcr.io/distroless/nodejs22-debian12 AS runtime
WORKDIR /app

# depsステージから本番依存のみコピー
COPY --from=deps /app/node_modules ./node_modules
# builderステージからビルド成果物のみコピー
COPY --from=builder /app/dist ./dist

EXPOSE 3000
CMD ["dist/index.js"]
# ビルドしてサイズを比較
$ docker build -t myapp:multi -f Dockerfile.web .
$ docker images myapp
REPOSITORY   TAG     SIZE
myapp        naive   1.1GB     ← node:22 フルイメージ
myapp        slim    350MB     ← node:22-slim
myapp        multi   120MB     ← distroless + マルチステージ(89%削減)

6.3 ユースケース3: Dockerでのセキュリティベストプラクティス

想定読者: 本番環境にDockerコンテナをデプロイする予定がある方

推奨構成: 非rootユーザー + 読み取り専用FS + セキュリティスキャン

サンプルコード:

#!/usr/bin/env bash
# docker_security_check.sh - Dockerセキュリティチェック
# 実行方法: bash docker_security_check.sh <image_name>

set -euo pipefail

IMAGE="${1:?使用法: $0 <image_name>}"

echo "=========================================="
echo " Docker セキュリティチェック: $IMAGE"
echo "=========================================="

# --- 1. rootユーザーチェック ---
echo ""
echo "[1/5] ユーザー設定チェック..."
USER=$(docker inspect --format='{{.Config.User}}' "$IMAGE" 2>/dev/null)
if [ -z "$USER" ] || [ "$USER" = "root" ] || [ "$USER" = "0" ]; then
    echo "  ⚠️  rootユーザーで実行されます"
    echo "  → DockerfileにUSER命令を追加してください"
else
    echo "  ✅ 非rootユーザー: $USER"
fi

# --- 2. HEALTHCHECK ---
echo ""
echo "[2/5] HEALTHCHECKチェック..."
HEALTH=$(docker inspect --format='{{.Config.Healthcheck}}' "$IMAGE" 2>/dev/null)
if [ -z "$HEALTH" ] || [ "$HEALTH" = "<nil>" ]; then
    echo "  ⚠️  HEALTHCHECKが未設定"
    echo "  → DockerfileにHEALTHCHECK命令を追加してください"
else
    echo "  ✅ HEALTHCHECK設定あり"
fi

# --- 3. 公開ポート ---
echo ""
echo "[3/5] 公開ポートチェック..."
PORTS=$(docker inspect --format='{{range $k, $v := .Config.ExposedPorts}}{{$k}} {{end}}' "$IMAGE" 2>/dev/null)
if [ -n "$PORTS" ]; then
    echo "  公開ポート: $PORTS"
else
    echo "  公開ポートなし"
fi

# --- 4. イメージサイズ ---
echo ""
echo "[4/5] イメージサイズチェック..."
SIZE=$(docker images --format '{{.Size}}' "$IMAGE" 2>/dev/null | head -1)
echo "  サイズ: $SIZE"
if [[ "$SIZE" == *GB* ]]; then
    echo "  ⚠️  1GB超。マルチステージビルドでの最適化を検討してください"
fi

# --- 5. Docker Scout(脆弱性スキャン) ---
echo ""
echo "[5/5] 脆弱性スキャン..."
if docker scout version &>/dev/null 2>&1; then
    echo "  Docker Scout でスキャン中..."
    docker scout quickview "$IMAGE" 2>/dev/null || echo "  (スキャン結果省略)"
else
    echo "  ℹ️  Docker Scout未インストール"
    echo "  → docker scout quickview $IMAGE で脆弱性を確認できます"
fi

echo ""
echo "=========================================="
echo "📋 セキュリティ推奨事項:"
echo "  1. 非rootユーザーで実行(USER命令)"
echo "  2. 読み取り専用FS(docker run --read-only)"
echo "  3. 不要なcapabilityの削除(--cap-drop ALL --cap-add ...)"
echo "  4. HEALTHCHECKの設定"
echo "  5. 定期的なイメージ更新とスキャン"
echo "=========================================="

ユースケースを把握できたところで、この先の学習パスを確認しましょう。


7. 学習ロードマップ

この記事を読んだ後、次のステップとして以下をおすすめします。

初級者向け(まずはここから)

  1. 既存のイメージでコンテナを起動する: docker run -it ubuntu:24.04 bashでコンテナ内のUbuntuを触る
  2. 自分のDockerfileを書く: 簡単なPythonアプリをコンテナ化する
  3. 公式ドキュメント: Docker Get Started を一通り進める

中級者向け(実践に進む)

  1. マルチステージビルドを使いこなす: イメージサイズを最適化する
  2. Docker Composeで複数コンテナを管理: Webアプリ + DB + キャッシュの構成を作る
  3. CI/CDにDockerを組み込む: GitHub Actions + Dockerでテスト・デプロイを自動化

上級者向け(さらに深く)

  1. コンテナセキュリティ: Docker Scout、Trivy、Falcoによる脆弱性管理
  2. カスタムネットワーク: overlayネットワーク、サービスメッシュの理解
  3. containerd / runc の理解: Docker Engineの内部構造を深掘りする

8. まとめ

この記事では、Dockerについて以下を解説しました:

  1. コンテナの正体: namespace + cgroups によるLinuxカーネルレベルの隔離であり、仮想マシンとは根本的に異なること
  2. イメージの仕組み: レイヤー構造とキャッシュの法則、マルチステージビルドによる最適化
  3. データの永続化: ボリューム / バインドマウント / tmpfs の使い分け
  4. 実践: GPUコンテナ、マルチステージビルド、セキュリティチェック

私の所感

Dockerを「本当に理解した」と感じたのは、RTX 5090のBlackwellアーキテクチャ(sm_120)でCUDA Gapに直面し、WSL2 → Docker → コンテナ内CUDAの3段階でGPUパススルーを成功させた時です。Windows側のNVIDIAドライバ → WSL2のGPU-PV → Docker の--gpus allフラグ → コンテナ内のlibcuda.so。この一連の流れを理解していないと、どこで問題が起きているのか切り分けすらできませんでした。

2026年現在、DockerはDocker Engine v29、Compose v5(Go SDK搭載)、さらにDocker Model RunnerというLLM推論基盤まで搭載し始めています。Docker MCP ToolkitによるMCPサーバー管理も加わり、AIインフラとしてのDockerの重要性は増す一方です。

「docker runできる」から「Dockerを理解している」へ。レイヤー、ネットワーク、ボリューム、セキュリティ。これらを正しく理解すれば、Dockerは「おまじない」から「信頼できるインフラ」に変わります。


参考文献


この記事は「わかったつもりになってない?」シリーズの一部です。

No. タイトル 状態
1 Linuxってなんだ? ✅ 公開済み
2 Ubuntuってなんだ? ✅ 公開済み
3 WSLってなんだ? ✅ 公開済み
4 Dockerってなんだ?(この記事) ✅ 公開済み
5 Docker Composeってなんだ? 🔜 次回
6 Kubernetesってなんだ? 📝 準備中

📌 X(Twitter)でも技術情報を発信しています: @geneLab_999

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?