はじめに
本書は、Docker の基礎から本番運用・プラットフォーム設計まで一気通貫でカバーする実践的な書籍です。
第3版では Kubernetes との棲み分け、BuildKit、マルチアーキテクチャビルドなど、近年のエコシステムの変化も丁寧に反映されています。
第1章・第2章 Dockerとは何か、なぜ使うのか
Dockerが解決する本質的な問題
Dockerは2013年に初めて公開されました。それ以来、ソフトウェアのビルド・デリバリー・実行を一貫して効率化するツールとして、業界標準の地位を確立しています。
Dockerが生まれた背景には、チーム間コミュニケーションのオーバーヘッドという普遍的な課題があります。
「開発者がリリースできるものをオペレーターが正しくデプロイできるか?」という問いに対して、Dockerは依存関係ごとパッケージしたコンテナイメージという形で明確な答えを提示しています。
Dockerがもたらすワークフローの変化
従来のデプロイフローはこのような形でした。
- 開発者がリソースを要求
- 運用チームがプロビジョニング
- デプロイスクリプトを作成・調整
- 依存関係の追加インストール対応
- …(以下ループ)
これがDockerを導入すると次のように短縮されます。
- 開発者がDockerイメージをビルドしてレジストリにプッシュ
- 運用エンジニアが設定情報を付与
- 開発者がデプロイを実行
このシンプルな責務分離こそ、Dockerが多くの組織にとって価値を持つ理由です。
アーキテクチャの基礎
Dockerはクライアント/サーバモデルを採用しています。
-
Dockerクライアント(
dockerコマンド):ユーザーの指示を受け付けるCLI -
Dockerサーバ(
dockerd):コンテナのビルド・起動・管理を担うデーモン - コンテナレジストリ:イメージの保存・配布の中継地点
内部的には containerd → runc という階層でコンテナを管理しており、2017年にDockerは containerd をCNCFに寄贈しています。このことがKubernetesとの連携をより広い文脈で支えています。
Dockerが「仮想マシンではない」理由
コンテナはホストOSのカーネルを共有します。完全なOSを持つVMとは根本的に異なります。
| 観点 | 仮想マシン(VM) | コンテナ |
|---|---|---|
| 起動時間 | 分単位 | 秒以下 |
| ディスク使用量 | 数百MB〜GB | 数KB〜MB |
| カーネル | 独立 | ホストと共有 |
| 隔離レベル | 強い | 中程度 |
VirtualBoxやKVMのような「長寿命のサーバ抽象化」とは異なり、コンテナは使い捨て前提の軽量プロセスです。この設計思想がDevOpsパイプラインと相性抜群な理由になっています。
第3章 Dockerをインストールする
本章では主要OS(Linux・macOS・Windows)へのインストール方法を解説しています。
macOSとWindowsではDockerサーバを動かすために小さなLinux VMが内部で利用されており、Linux上では dockerd がネイティブに動作します。
Docker Desktopのライセンス変更(2022年以降)により、一定規模以上の企業利用は有償になっています。代替として podman や nerdctl も選択肢に挙げられています。
第4章 Dockerイメージを扱う
Dockerfileの基本構造
Dockerfileはイメージの設計図です。各命令が新しいレイヤーを生成します。
FROM node:18.13.0
ARG email="maintainer@example.com"
LABEL "maintainer"=$email
USER root
ENV APP_DIR /data/app
RUN apt-get -y update && \
apt-get -y install supervisor && \
mkdir -p /var/log/supervisor
COPY ./supervisord/conf.d/* /etc/supervisor/conf.d/
COPY *.js* $APP_DIR/
WORKDIR $APP_DIR
RUN npm install
CMD ["supervisord", "-n"]
主な命令の役割を整理します。
| 命令 | 役割 |
|---|---|
FROM |
ベースイメージの指定 |
ARG |
ビルド時のみ有効な変数 |
ENV |
実行時にも使える環境変数 |
RUN |
ビルド時のコマンド実行 |
COPY |
ファイルのコピー |
CMD |
コンテナ起動時のデフォルトコマンド |
ENTRYPOINT |
実行バイナリの固定 |
イメージを小さく保つポイント
レイヤーは加算的であることを押さえておく必要があります。後のステップでファイルを削除しても、前のレイヤーのサイズは減りません。
# NG:2つのRUNに分けると削除してもサイズは減らない
RUN dnf install -y httpd
RUN dnf clean all
# OK:1つのRUNにまとめることでレイヤーを小さく保てる
RUN dnf install -y httpd && \
dnf clean all
この工夫により、273MB → 44.8MB に削減できる実例が本書に示されています。
マルチステージビルド
本番イメージのサイズを最小化する最良の方法がマルチステージビルドです。
# ビルドステージ
FROM golang:alpine as builder
RUN CGO_ENABLED=0 go install -a github.com/spkane/scratch-helloworld@latest
# 本番ステージ
FROM scratch
COPY --from=builder /go/bin/scratch-helloworld /helloworld
EXPOSE 8080
CMD ["/helloworld"]
scratch という特殊な空イメージからスタートし、必要なバイナリだけをコピーすることで、3.4MB という超軽量イメージを実現できます。
レイヤーキャッシュを活かす順序設計
# 頻繁に変わるコードは後半に置く
FROM fedora
RUN dnf install -y httpd && dnf clean all # ← 変化が少ない
RUN mkdir -p /var/www/html # ← 変化が少ない
ADD index.html /var/www/html # ← 頻繁に変わる
変化の少ない処理を先頭に、コード追加は後半に配置することで、差分ビルドを高速化できます。
マルチアーキテクチャビルド
docker buildx を利用すると、linux/amd64 と linux/arm64 を同時にビルドできます。
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag docker.io/yourname/app:latest \
--push .
ARM対応クラウドインスタンスの普及とともに、マルチアーキテクチャ対応の重要性は増しています。
第5〜7章 コンテナの操作とデバッグ
ライフサイクルとリソース制限
# 起動・停止
docker container run --rm -d -p 8080:8080 myapp:latest
docker container stop <id>
# CPUとメモリを制限する(本番では必須)
docker container run --cpus="1.5" --memory="512m" myapp:latest
デバッグコマンド
docker container logs <id> # ログ確認
docker container exec -it <id> bash # シェルで入る
docker container stats # リソース監視
scratch ベースのようにシェルが存在しないコンテナは、nsenter や docker container export を組み合わせてデバッグします。
第8章 Docker Composeを探求する
Docker Composeは、複数コンテナの定義と起動を1ファイルで管理するツールです。
version: "3.9"
services:
web:
image: nginx:alpine
ports:
- "80:80"
depends_on:
- app
app:
build: .
environment:
- DATABASE_URL=postgres://db:5432/mydb
depends_on:
- db
db:
image: postgres:15
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
# バックグラウンドで起動
docker compose up -d
# 停止・削除
docker compose down
ローカル開発環境の構築や統合テストの実行に非常に便利です。本番用途では Kubernetes が推奨されますが、小規模構成であれば Compose でも十分な場面があります。
第9章 プロダクション・コンテナへのパス
本番稼働に向けて考慮すべき要素を整理しています。
外部依存の分離
ステートレスアプリケーションこそがコンテナに最適です。状態は以下に外部化します。
-
設定:環境変数(
ENV)または Secrets Manager - セッション・キャッシュ:Redis や Memcached
- 永続データ:PostgreSQL / MySQL などのDB、またはS3などのオブジェクトストレージ
イメージタグの管理
# NG:latestタグは本番では使わない
docker image pull myapp:latest
# OK:コミットハッシュやセマンティックバージョンで固定
docker image pull myapp:1.4.3
docker image pull myapp:a3f2c9d
latest タグはフローティングタグであり、ロールバック不能になるため本番環境では使用すべきではありません。
CI/CDパイプラインとの統合
コード変更 → Dockerfile build → テスト → レジストリへプッシュ → デプロイ
このパイプライン全体を標準化できることがDockerの真価です。
第10章 コンテナ・アット・スケール
単一ホストでの運用限界を超えるために、コンテナオーケストレーターが必要になります。
主なオーケストレーション選択肢
| ツール | 特徴 |
|---|---|
| Kubernetes(k8s) | 現在のデファクトスタンダード。機能豊富だが学習コスト高 |
| Docker Swarmモード | Dockerに組み込み。シンプルだがk8sに比べ機能が限られる |
| HashiCorp Nomad | Kubernetes以外の選択肢として根強い支持 |
本書ではKubernetesとSwarmモードの概要を扱いつつ、「まず小規模から始めてスケールの課題が生まれたらオーケストレーターを導入する」という現実的なアドバイスがなされています。
第11章 高度なトピック
ネットワークモード
| モード | 説明 |
|---|---|
| bridge(デフォルト) | 仮想ブリッジを介してコンテナ間通信 |
| host | ホストのネットワークインターフェースを直接使用 |
| none | ネットワーク無効 |
| overlay | Swarmモードでのクラスタ間通信 |
セキュリティの基本
- コンテナを
rootで動かさない(USER命令を使う) - SELinux / AppArmor ポリシーで隔離を強化
- イメージの脆弱性スキャン(Trivy等)を CI に組み込む
- Secrets は環境変数ではなく専用の管理システム(Vault、Kubernetes Secrets等)を使う
ルートレスコンテナ
dockerd 自体を非rootユーザーで動かすルートレスモードを利用することで、ホストへの影響をさらに限定できます。
# ルートレスモードの確認
DOCKER_HOST=unix:///run/user/1000/docker.sock docker version
第12章 広がる風景
Dockerエコシステムの主要ツールを整理しています。
| ツール | 説明 |
|---|---|
containerd |
Docker内部のコンテナランタイム。CNCFプロジェクト |
nerdctl |
containerd向けのDocker互換CLI |
podman |
デーモンレス・ルートレスなDocker互換ツール |
buildah |
Dockerfileなしでイメージを構築できるツール |
skopeo |
レジストリ間のイメージ操作ツール |
Kubernetesは v1.24 以降でDockerShimを廃止し、containerd を直接使用しています。ただし containerd 自体はDockerが開発・寄贈したものであり、エコシステムの繋がりは依然として強いです。
第13章・第14章 コンテナプラットフォームの設計と結論
コンテナ導入の成熟モデル
本書では組織がコンテナを採用していく際の段階を示しています。
- 個人の開発環境への導入(Docker Desktop)
- CI/CDパイプラインへの組み込み(イメージビルド・テスト自動化)
- ステージング環境のコンテナ化
- 本番環境への展開とオーケストレーター導入
- 不変性インフラ(Immutable Infrastructure)への移行
不変性インフラの考え方
変更する → ×
新しいイメージをビルドして入れ替える → ○
Fedora CoreOSのような「コンテナホスト向けに最適化されたOS」は、OSレベルでも不変性を実現しています。サーバにSSHしてパッチを当てる運用から脱却することが、Dockerの目指す姿の一つです。
Dockerが解決しない問題
本書は終章で正直にこう述べています。Dockerはすべての問題を解決しない、と。
| 課題 | Dockerの外で解決すべきこと |
|---|---|
| データの永続化 | 外部ストレージの設計 |
| セキュリティの完全な担保 | ネットワークポリシー・RBAC |
| 複雑なオーケストレーション | Kubernetes等の導入 |
| 監視・可観測性 | Prometheus / Grafana 等 |
まとめ
本書を通じて得られる視点を3点に絞ってまとめます。
1. Dockerの価値はツールではなくワークフローにある
docker run を覚えることより、「イメージで責務を分離する」という設計思想の内面化が重要です。
2. イメージ設計は奥深い
マルチステージビルド・レイヤー順序・BuildKitのキャッシュ活用など、パフォーマンスとセキュリティを両立するための知識は一冊を通じて積み上がります。
3. Dockerは入口であり、出口ではない
本番規模では Kubernetes との組み合わせが現実解です。本書はそのつなぎ目も意識して書かれており、「Dockerをきちんと理解した上でKubernetesへ」というステップアップの道筋を自然に示しています。
コンテナ技術を体系的に学び直したいエンジニアにとって、本書は整理の出発点として非常に優れた一冊です。