第2回スコープ・学習目標・今ここマップ
動作確認バージョン: Docker CE 29.4.3 / containerd 2.2.3 / runc 1.3.5 / nginx:1.27-alpine(実体: nginx 1.27.5)/ AlmaLinux 10.1(kernel 6.12.0-124.55.3.el10_1)(2026-05-09 時点・k8s-ops 実機検証済・SP_vol1-pre-03 起点)
本回は Kubernetes 実践教科書 第1巻(CKAD 対応・全 19 回)の第2回です。第1部「コンテナと Docker」の全 4 回のうち、第2回はイメージの取得からコンテナの起動・停止・削除・観察まで一通りの基本操作を扱います。
CKAD D1(Application Design and Build)と D3(Application Observability and Maintenance)の前提知識を固めるセクションです。
第1回からの継承状態確認(SP_vol1-pre-02 状態・第1回完走スナップショット SP_vol1-pre-01 を起点として SP_vol1-pre-02 取得後に演習を開始):
- k8s-ops(AlmaLinux 10.1・2 vCPU / 6 GB / 40 GB)に Docker CE 29.4.3 が導入済み
- developer ユーザーが docker グループに所属しており
sudoなしで docker コマンドを実行できる docker run hello-worldで hello-world イメージの取得と実行が確認済み
今ここマップ(第1巻 19 回中の現在位置):
第1部 コンテナとDocker
第1回: コンテナ技術概念 + Docker環境準備 [完了]
★ 第2回: Docker基本操作 ← 今ここ
第3回: Dockerfile + マルチステージビルド + JDK 25/Payara Micro
第4回: コンテナレジストリ + Trivy スキャン
第2部 Kubernetes基礎(第5〜6回)
第3部 アプリリソース(第7〜11回)
第4部 ワークロード戦略(第12〜14回)
第5部 セキュリティ基礎(第15〜16回)
第6部 パッケージ管理 + HTTPS公開(第17〜19回)
第2回を終えると、以下を習得した状態になります。
docker pull/docker run/docker stop/docker rmを一人で実施できる- コンテナライフサイクル(Created → Running → Paused → Stopped → Removed)を図示して説明できる
docker ps/docker logs/docker exec/docker inspectの基本操作ができる(D3 前提知識)- Volume と bind mount の違いを説明し、用途に合わせて使い分けられる(Docker コンテナのログ設計・stdout/stderr symlink 実装を含む)
- Nginx コンテナを起動してホストブラウザからアクセスできる
コンテナライフサイクル
コンテナには明確な状態(ライフサイクル)があります。状態遷移を理解することで、「コンテナが動かない」「出力が見えない」といった問題の原因を特定する際の思考の基礎になります。
コンテナの5つの状態:
| 状態 | 説明 | 主な遷移トリガー |
|---|---|---|
| Created | docker create でコンテナが作成されたが、まだ実行されていない | docker create 実行後 |
| Running | コンテナが起動して内部プロセスが実行中 | docker start / docker run 実行後 |
| Paused | cgroup freezer でプロセスが一時停止された状態(メモリは保持・実務での使用機会は限定的:メモリダンプ取得や開発デバッグ等の特殊用途で稀に使用) | docker pause 実行後 |
| Stopped(Exited) | コンテナ内のプロセスが終了した状態(コンテナのファイルシステムは残る) | docker stop / プロセス自然終了 |
| Removed | docker rm でコンテナが削除された状態(ファイルシステムも消える) | docker rm 実行後 |

状態遷移の流れをテキストで確認します。
[docker create]
|
[Created]
| [docker start]
[Running] <--- [docker restart]
| |
| [docker pause] | [docker stop / SIGTERM]
v v
[Paused] [Stopped/Exited]
| |
| [docker unpause] | [docker start]
+----------------------+
|
| [docker rm]
[Removed]
補足:docker run = docker create + docker start
通常は docker run を使うことがほとんどですが、内部では create → start の2ステップで動作しています。状態管理の観点から、この分解を知っておくと、docker ps -a(停止中も含む全コンテナ表示)の意味がわかりやすくなります。
K8s との橋渡し:Kubernetes の Pod ライフサイクル(Pending → Running → Succeeded / Failed)は、コンテナのライフサイクルを Pod という単位に昇華させたものです。第7回(Pod + Multi-container パターン)でこの関係を掘り下げます。
イメージとコンテナの関係
イメージとコンテナは似ているようで異なります。
- イメージ:コンテナを作成するための「テンプレート(設計図)」。読み取り専用のレイヤー構造。Docker Hub 等から
docker pullで取得する - コンテナ:イメージを元に作成した「実行インスタンス」。書き込み可能なレイヤーが追加されて動作する
1つのイメージから複数のコンテナを起動できます。
nginx:1.27-alpine イメージ(テンプレート)
|---> コンテナ A(名前: nginx-a / ポート: 8080)
|---> コンテナ B(名前: nginx-b / ポート: 8081)
+---> コンテナ C(名前: nginx-c / ポート: 8082)
イメージ自体は変わらず、コンテナごとに異なる設定(ポート・環境変数・Volume マウント先等)で起動できます。
Docker 29.x の docker images 出力フォーマット変更(重要):
Docker CE 29.x(containerd snapshotter ベース)では docker images の出力列が変わっています。
旧フォーマット(Docker 27.x 以前):
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest xxxxxxxx 2 weeks ago 193MB
新フォーマット(Docker 29.x・containerd snapshotter 使用時):
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
nginx:1.27-alpine 65645c7bb6a0 73MB 21.9MB
hello-world:latest f9078146db2e 21.8kB 9.49kB U
WARNING: This output is designed for human readability. For machine-readable output, please use --format.
主な変更点:
REPOSITORY/TAG→IMAGE(name:tag形式で一列に統合)SIZE→DISK USAGE/CONTENT SIZE/EXTRAの3列に分割- WARNING 行が末尾に追加される
この変更は第1回の progress.md に記録した技術発見です。本記事のコマンド出力例はすべて Docker 29.x 形式で記述します。
やってみよう ① docker pull / run / ps / stop / rm の基本操作
前提状態:SP_vol1-pre-02 状態(Docker CE 29.4.3 インストール済・developer ユーザーで sudo なし操作可能)
ステップ1:イメージを pull する
実行コマンド:
$ docker pull nginx:1.27-alpine
実行結果:
197eb75867ef: Pull complete
39c2ddfd6010: Pull complete
Digest: sha256:65645c7bb6a0661892a8b03b89d0743208a18dd2f3f17a54ef4b76fb8e2f2a10
Status: Downloaded newer image for nginx:1.27-alpine
docker.io/library/nginx:1.27-alpine
出力中の Digest: sha256:... はイメージの内容に基づく不変識別子(ダイジェスト)です。タグ 1.27-alpine は同じ名前でも内容が更新されることがありますが、ダイジェストはイメージのバイト列が変わらない限り同じ値となり、本番環境で「先週と同じイメージか?」を確実に検証する手段になります。
タグ戦略・latest タグの罠については第4回で詳述します。
ステップ2:イメージの確認
実行コマンド:
$ docker images
実行結果(Docker 29.x フォーマット):
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
nginx:1.27-alpine 65645c7bb6a0 73MB 21.9MB
hello-world:latest f9078146db2e 21.8kB 9.49kB U
WARNING: This output is designed for human readability. For machine-readable output, please use --format.
ステップ3:コンテナをバックグラウンドで起動(ポート公開)
実行コマンド:
$ docker run -d --name nginx-test -p 8080:80 nginx:1.27-alpine
実行結果(コンテナ ID が返る):
a3f8b2c1d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1
オプションの意味:
-d:バックグラウンド(detached)モードで起動--name nginx-test:コンテナに名前を付ける(指定しない場合は自動生成)-p 8080:80:ホストの 8080 ポートをコンテナの 80 ポートに転送
ステップ4:起動中のコンテナを確認
実行コマンド:
$ docker ps
実行結果:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a3f8b2c1d4e5 nginx:1.27-alpine "/docker-entrypoint.…" 10 seconds ago Up 9 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx-test
ステップ5:ホストブラウザからアクセス確認
k8s-ops の IP アドレスは環境により異なります。ip addr show または hostname -I | awk '{print $1}' で確認してください(本書著者環境では 192.168.1.122・読者向け Vagrantfile では 192.168.56.10 想定)。ホスト OS のブラウザで http://<k8s-ops の IP>:8080 にアクセスします(著者環境例: http://192.168.1.122:8080)。
「Welcome to nginx!」のデフォルトページが表示されれば Nginx コンテナが正常に動作しています。
curl でも確認できます(k8s-ops 上から):
実行コマンド:
$ curl -s http://localhost:8080 | head -5
実行結果(Nginx デフォルトページの冒頭):
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
ステップ6:コンテナを停止する
docker stop はデフォルトでコンテナのメインプロセスに SIGTERM を送り、10 秒待機しても終了しなければ SIGKILL で強制終了します(猶予秒数は --time / -t オプションで調整可能)。
これは Kubernetes の Pod 削除時に動作する terminationGracePeriodSeconds(デフォルト 30 秒)と同じ仕組みで、グレースフルシャットダウン設計の前提知識として第7回 Pod ライフサイクルで再度詳述します。
実行コマンド:
$ docker stop nginx-test
実行結果:
nginx-test
ステップ7:停止中のコンテナを確認
docker ps は起動中のコンテナのみ表示するため、停止中は -a オプションを付けます。-a は all の略で、Created / Exited / Paused 状態のコンテナも含めて全件を一覧化します。
実行コマンド:
$ docker ps -a
実行結果:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a3f8b2c1d4e5 nginx:1.27-alpine "/docker-entrypoint.…" 1 minute ago Exited (0) 10 seconds ago nginx-test
nginx-test が消えています。第1回で実行した hello-world コンテナが Exited 状態で残っているのが見えます(CONTAINER ID と NAMES は環境ごとに異なる値が表示されます)。これは第1回演習の残骸です。不要になった停止コンテナは適宜 docker rm で削除します。
ステップ8:コンテナを削除する
実行コマンド:
$ docker rm nginx-test
実行結果:
nginx-test
実行コマンド(削除確認):
$ docker ps -a
実行結果(nginx-test が消えている):
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
353de0e97213 hello-world "/hello" (第1回実行時) Exited (0) (第1回時刻) condescending_mirzakhani
補足:起動中コンテナの強制削除
停止してから削除する場合は docker stop → docker rm の2ステップが基本です。docker rm -f で起動中のコンテナを強制削除することもできますが、実行中のプロセスを突然終了させるためデータ損失のリスクがあります(ヒヤリハットセクションで詳述)。
docker logs / exec / inspect でコンテナを観察する
コンテナが動いているとき、あるいはエラーが出たとき、「コンテナの中で何が起きているか」を確認する手段が3つあります。これらは CKAD D3(Application Observability and Maintenance)の前提知識であり、第6回の kubectl logs / kubectl exec / kubectl describe への橋渡しになります。
docker logs — コンテナの標準出力・標準エラーを確認する
まず Nginx コンテナを再度起動してからログを確認します。
実行コマンド:
$ docker run -d --name nginx-observe -p 8080:80 nginx:1.27-alpine
実行コマンド:
$ docker logs nginx-observe
実行結果(Nginx の起動ログ抜粋):
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2026/05/09 08:36:16 [notice] 1#1: using the "epoll" event method
2026/05/09 08:36:16 [notice] 1#1: nginx/1.27.5
2026/05/09 08:36:16 [notice] 1#1: built by gcc 14.2.0 (Alpine 14.2.0)
2026/05/09 08:36:16 [notice] 1#1: OS: Linux 6.12.0-124.52.3.el10_1.x86_64
2026/05/09 08:36:16 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1024:524288
2026/05/09 08:36:16 [notice] 1#1: start worker processes
2026/05/09 08:36:16 [notice] 1#1: start worker process 30
2026/05/09 08:36:16 [notice] 1#1: start worker process 31
--follow(-f)オプションでリアルタイムにログを追うことができます。
実行コマンド:
$ docker logs -f nginx-observe
別ターミナルで curl を実行するとアクセスログがリアルタイムで流れることを確認できます。終了するには Ctrl+C を入力します。
K8s での対応:kubectl logs <pod名> が同等の操作です。第6回の Observability セクションで本格的に扱います。
docker exec — 起動中のコンテナ内でコマンドを実行する
実行コマンド(コンテナ内のシェルに入る):
$ docker exec -it nginx-observe /bin/sh
実行結果(コンテナ内のシェルプロンプトが表示される):
/ #
オプションの意味:
-i:標準入力をオープンにする(interactive)-t:疑似ターミナルを割り当てる(tty)
コンテナ内での確認例(コンテナ内で実行):
コンテナ内に入った後、Nginx の設定ファイルや DocumentRoot を確認できます。以下の順で実行します。
実行コマンド(Nginx 設定ファイルの中身を確認):
# cat /etc/nginx/nginx.conf
nginx 公式イメージ 1.27-alpine の標準設定(worker_processes / events / http ブロックなど)が表示されます。本回ではコンテナの中身を観察できることを確認するのが目的のため、内容の詳細は第3回(Dockerfile / nginx ベースイメージ)以降で扱います。
実行コマンド(DocumentRoot を確認):
# ls /usr/share/nginx/html/
実行結果:
50x.html index.html
確認が終わったらコンテナから抜けます。
実行コマンド:
# exit
コマンド1つだけ実行してコンテナ内に入らない方法:
実行コマンド:
$ docker exec nginx-observe nginx -v
実行結果:
nginx version: nginx/1.27.5
K8s での対応:kubectl exec -it <pod名> -- /bin/sh が同等の操作です。第6回で詳述します。
docker inspect — コンテナの詳細設定情報を JSON で確認する
実行コマンド:
$ docker inspect nginx-observe
実行結果(JSON 形式・一部抜粋):
[
{
"Id": "a3f8b2c1d4e5f6g7...",
"Created": "2026-05-09T08:36:16.000000000Z",
"State": {
"Status": "running",
"Running": true
},
"NetworkSettings": {
"Networks": {
"bridge": {
"IPAddress": "172.17.0.2"
}
}
},
"Mounts": []
}
]
特定のフィールドだけ取り出す場合は --format オプションが便利です。
【Docker 29.x 変更点】:Docker 29.x ではコンテナのネットワーク設定が NetworkSettings.Networks.<network 名> 配下にネスト化されました。旧バージョンで使われていた {{.NetworkSettings.IPAddress}} は map has no entry for key "IPAddress" エラーになります。
デフォルトの bridge ネットワーク使用時は .NetworkSettings.Networks.bridge.IPAddress でアクセスします。複数ネットワーク接続時は range テンプレート({{range $k, $v := .NetworkSettings.Networks}}{{$k}}={{$v.IPAddress}}{{end}})が便利です。
実行コマンド(コンテナの IP アドレスだけ取得):
$ docker inspect nginx-observe --format '{{.NetworkSettings.Networks.bridge.IPAddress}}'
実行結果:
172.17.0.2
K8s での対応:kubectl describe pod <pod名> や kubectl get pod -o json が同等の操作です。第6回で詳述します。
Volume と bind mount の違い
コンテナのファイルシステムは「コンテナのライフサイクルと同一」です。docker rm でコンテナを削除すると、コンテナ内に書き込んだデータもすべて消えます。データを永続化したり、ホストとファイルを共有したりするために Volume と bind mount の2つの手段があります。
Volume vs bind mount 比較表:
| 比較項目 | Volume | bind mount |
|---|---|---|
| 管理主体 | Docker が管理(/var/lib/docker/volumes/ 以下) | ホスト OS のパスを直接指定 |
| データの場所 | Docker 管理下(ホストパスを意識しない) | ホスト OS の任意のパス |
| 作成方法 | docker volume create または -v volume名:コンテナ内パス | -v /ホストパス:コンテナ内パス または --mount type=bind,... |
| ポータビリティ | 高い(ホスト OS のディレクトリ構造に依存しない) | 低い(ホスト OS のパスに依存) |
| 主な用途 | DB データ永続化・コンテナ間データ共有 | 設定ファイルの注入・開発時のソースコード共有 |
| 本番向き | 推奨 | 設定ファイル注入目的なら可 |

K8s との橋渡し:
- Docker Volume → Kubernetes PersistentVolume(PVC)/ emptyDir(第9回で詳述)
- bind mount → Kubernetes ConfigMap / Secret(設定ファイル注入)/ hostPath(第9回で詳述)
- 注意: K8s の
emptyDirは Pod 削除と同時にデータが消える一時ストレージです。Docker Volume はコンテナをdocker rmで削除しても残るため、両者は「永続性」の意味が大きく異なります。混同しやすいポイントなので、第9回 Volume / PVC の学習時に再度確認します。
Volume の基本操作(概念確認):
実行コマンド(Volume を作成する):
$ docker volume create nginx-data
実行結果:
nginx-data
実行コマンド(Volume の一覧確認):
$ docker volume ls
実行結果:
DRIVER VOLUME NAME
local nginx-data
実行コマンド(Volume の詳細確認):
$ docker volume inspect nginx-data
実行結果(JSON 形式):
[
{
"CreatedAt": "2026-05-09T19:50:38+09:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginx-data/_data",
"Name": "nginx-data",
"Options": null,
"Scope": "local"
}
]
Mountpoint フィールドでホスト OS 上の実際のディレクトリパスを確認できます。
やってみよう ② Volume + bind mount でデータ永続化
前提状態:H2-5 の nginx-observe コンテナが起動中。
シナリオ:Nginx のデフォルトページをカスタムし(bind mount)、Volume のマウントで Docker コンテナのログ設計を発見する。
ステップ1:nginx-observe コンテナを停止・削除(クリーンアップ)
実行コマンド:
$ docker stop nginx-observe && docker rm nginx-observe
実行結果:
nginx-observe
nginx-observe
ステップ2:カスタム HTML ファイルを作成(bind mount 用)
まず bind mount するためのディレクトリをホスト OS 上に作成します。
実行コマンド:
$ mkdir -p /home/developer/nginx-html
実行結果:(出力なし。成功時は何も表示されません)
続いて、ヒアドキュメントでカスタム HTML ファイルを書き込みます。
実行コマンド:
$ cat > /home/developer/nginx-html/index.html << 'EOF'
カスタム Nginx ページ
第2回 Docker 基本操作 - bind mount 動作確認
EOF
実行結果:(出力なし。成功時は何も表示されません)
ステップ3:Volume を作成
実行コマンド:
$ docker volume create nginx-logs
実行結果:
nginx-logs
ステップ4:bind mount + Volume を指定してコンテナを起動
実行コマンド:
$ docker run -d \
--name nginx-vol-test \
-p 8080:80 \
-v /home/developer/nginx-html:/usr/share/nginx/html:ro \
-v nginx-logs:/var/log/nginx \
nginx:1.27-alpine
実行結果(コンテナ ID が返る):
b4e9f3a2c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2
オプションの説明:
-v /home/developer/nginx-html:/usr/share/nginx/html:ro:ホストの HTML ディレクトリを Nginx のドキュメントルートに bind mount(:ro= 読み取り専用)-v nginx-logs:/var/log/nginx:nginx-logsVolume を Nginx のログディレクトリにマウント(Nginx の/var/log/nginx/ディレクトリには、Docker 公式イメージのデフォルトでログファイルではなく/dev/stdout//dev/stderrへの symbolic link が配置される。Volume にマウントすることで「コンテナがどのようなログ設計を持つか」を確認する演習として活用する)
ステップ5:カスタムページの表示確認
実行コマンド:
$ curl -s http://localhost:8080
実行結果(カスタム HTML が返る):
<!DOCTYPE html>
<html>
<head><title>カスタム Nginx ページ</title></head>
<body>
<h1>第2回 Docker 基本操作 - bind mount 動作確認</h1>
</body>
</html>
カスタム HTML が表示されれば bind mount が正常に機能しています。
ステップ6:「Nginx ログは Volume に保存されない」の発見演習
注:alpine イメージが未取得の場合、Docker Hub から自動でダウンロードされます(初回実行時のみ・圧縮転送サイズ 約 4 MB / 展開後ディスク使用量 約 12 MB)。
実行コマンド:
$ docker run --rm -v nginx-logs:/data alpine ls -la /data
実行結果(alpine イメージを初回取得する場合は pull 出力が先に表示される):
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
6a0ac1617861: Pulling fs layer
a63813f19ccb: Download complete
4e0cb4ac63e7: Download complete
Digest: sha256:5b10f432ef3da1b8d4c7eb6c487f2f5a8f096bc91145e68878dd4a5019afde11
Status: Downloaded newer image for alpine:latest
実行結果(ls -la の本体・symlink のみが表示される):
total 0
drwxr-xr-x 2 root root 41 May 9 08:39 .
drwxr-xr-x 1 root root 18 May 9 08:39 ..
lrwxrwxrwx 1 root root 11 Apr 16 2025 access.log -> /dev/stdout
lrwxrwxrwx 1 root root 11 Apr 16 2025 error.log -> /dev/stderr
ステップ7:Docker ログ設計の解説
Volume 内に access.log と error.log のファイルは存在しますが、いずれも実体ではなく /dev/stdout / /dev/stderr への symbolic link です。Nginx 公式イメージは Docker コンテナベストプラクティスに従い、ログを /dev/stdout / /dev/stderr に流す symbolic link として /var/log/nginx/ を実装しています。これにより docker logs <コンテナ名> でログを取得でき、コンテナがステートレスに保たれます。
nginx.conf の access_log ディレクティブはすでに /var/log/nginx/access.log を指していますが、その先が symlink になっているため、Volume にマウントしても symlink のみが保存されます。ログ実体を Volume に保存するには、nginx.conf の access_log 先をコンテナ内の実ファイルパス(例: /tmp/access.log)に変更するか、symlink を含まないカスタムイメージを作成する必要があります(本書スコープ外)。
実用上は Loki / Fluent Bit / syslog 集約などのログアグリゲータで集めるのが標準です(第2巻第13回で扱う Prometheus/Loki スタックに繋がる前提知識)。
ステップ8:コンテナを削除して Volume が残ることを確認
実行コマンド:
$ docker stop nginx-vol-test
$ docker rm nginx-vol-test
実行コマンド(Volume がまだ存在することを確認):
$ docker volume ls
実行結果(Volume が残っている):
DRIVER VOLUME NAME
local nginx-data
local nginx-logs
コンテナを削除しても Volume は残ります。これが Volume を使う意義です。
ステップ9:Volume と bind mount のクリーンアップ
実行コマンド:
$ docker volume rm nginx-data nginx-logs
実行結果:
nginx-data
nginx-logs
bind mount 用ディレクトリも削除します。
実行コマンド:
$ rm -rf /home/developer/nginx-html
実行コマンド(演習② 終了時点のイメージ一覧確認):
$ docker images
実行結果:
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
nginx:1.27-alpine 65645c7bb6a0 73MB 21.9MB
alpine:latest 5b10f432ef3d 12.7MB 3.95MB
hello-world:latest f9078146db2e 21.8kB 9.49kB U
WARNING: This output is designed for human readability. For machine-readable output, please use --format.
演習② で pull した alpine:latest が追加されていることが確認できます。
現場ヒヤリハット
事例1:docker rm -f で稼働中 DB コンテナを削除してデータが消えた
入社4ヶ月目の B さんは、開発環境の Docker コンテナが増えて混乱してきたため、不要なコンテナをまとめて削除しようとしました。docker ps -a を実行し、停止中のコンテナを中心に docker rm を実行しようとしましたが、誤って -f(強制削除)オプションを付けたままコンテナ名を間違えて実行しました。
削除したコンテナは MySQL のデータベースコンテナでした。Volume を使わずにコンテナ内のファイルシステム(/var/lib/mysql/)に直接データを書き込んでいたため、docker rm -f の実行と同時に開発中のデータが全件消失しました。
翌朝、チームメンバーが開発環境で動作確認しようとしたところ、DB が空になっていることが発覚。バックアップは1週間前のものが最後で、その間に蓄積した開発データは復旧不能でした。
教訓と対処法:
- コンテナのデータは必ず Volume か bind mount で永続化する:データを持つコンテナ(DB 等)は、コンテナを削除してもデータが消えないように Volume を必ず指定する
docker rm -fは運用中には原則使用しない:正しい手順はdocker stop→docker rmの2ステップ。-fは緊急時のみ- 削除前に
docker inspectでマウント情報を確認する:削除対象コンテナのMountsフィールドを確認し、データが保存されている場所を把握する
事例2:bind mount の順序を誤ってホスト OS の重要ファイルを上書きしそうになった
入社8ヶ月目の C さんは、コンテナ内の設定ファイルを外部から注入するために bind mount を設定しようとしました。-v オプションの順序は「ホストパス:コンテナ内パス」ですが、手元のメモを見間違えて「コンテナ内パス:ホストパス」の順序で記述してしまいました。さらに、マウント先として /etc に近い重要なディレクトリを指定してしまいました。
コマンドを実行する直前に、同席していた先輩エンジニアがコマンドの引数を見て「それは逆では」と気付き、実行前に停止できました。もし実行されていれば、ホスト OS の設定ディレクトリがコンテナ内から参照でき、最悪の場合は書き換えられる危険がありました。
危険な例(絶対に実行しないこと):
$ docker run --rm -v /etc:/etc nginx:1.27-alpine rm /etc/passwd
上記は、ホスト OS の /etc/passwd が削除されます。bind mount の -v オプションでは「ホストパス:コンテナ内パス」の順序・パスを必ず慎重に確認してください。
防止策:
- 設定ファイルの注入目的の bind mount は原則
:ro(読み取り専用)を付ける -vの前に--mount type=bind,source=...,target=...,readonly形式で書くと視認性が上がり、誤記が減る- コマンド実行前に
--dry-run相当の確認をする(コマンドを一度 echo で確認する等)
CKAD D3 前提知識ブリッジ — Docker コマンドと kubectl の対応
本回で学習した docker logs / docker exec / docker inspect は、Kubernetes 環境では対応するコマンドに置き換わります。Docker レベルの操作を習得しておくことで、第6回以降の kubectl 操作に移行する際の概念的なハードルを下げることが目的です。
Docker → Kubernetes コマンド対応表:
| 操作 | Docker コマンド | kubectl 対応コマンド | 対応回 |
|---|---|---|---|
| コンテナのログ確認 | docker logs <コンテナ名> | kubectl logs <Pod名> | 第6回 |
| リアルタイムログ追跡 | docker logs -f <コンテナ名> | kubectl logs -f <Pod名> | 第6回 |
| コンテナ内でコマンド実行 | docker exec -it <コンテナ名> /bin/sh | kubectl exec -it <Pod名> -- /bin/sh | 第6回 |
| コンテナの詳細情報確認 | docker inspect <コンテナ名> | kubectl describe pod <Pod名> | 第6回 |
| 起動中コンテナの一覧 | docker ps | kubectl get pods | 第5回 |
| 全コンテナの一覧(停止中含む) | docker ps -a | kubectl get pods --field-selector=status.phase!=Running(停止中相当を抽出) | 第5回 |
| 全 Namespace のコンテナ一覧 | —(Docker に Namespace 概念なし) | kubectl get pods -A(-A は all-namespaces の意・状態フィルタではない) | 第5回 |
CKAD D3(Application Observability and Maintenance)との対応:
CKAD の D3 ドメインでは「コンテナログの活用」と「Kubernetes でのデバッグ」が出題範囲に含まれます。第2回で Docker レベルの観察手段を習得しておくことで、第6回の kubectl 操作へ移行する際の概念的なハードルを下げられます。
第3回(Dockerfile + マルチステージビルド)では、本回で起動した Nginx コンテナのような「出来合いのイメージを使う」ではなく、自分でイメージを作るステップに進みます。fanclub-api の Backend(Java JDK 25 + Payara Micro 7.2026.4)のイメージを Dockerfile で定義し、docker build でビルドします。
今回のまとめ + 理解度チェック
第2回では以下を実施しました。
- コンテナのライフサイクル(Created → Running → Paused → Stopped → Removed)と状態遷移を確認した
- イメージとコンテナの関係(イメージ = テンプレート / コンテナ = 実行インスタンス)を整理した
- Docker 29.x の
docker images出力フォーマット変更(DISK USAGE / CONTENT SIZE / EXTRA)を確認した - Nginx コンテナを起動(
docker run -d -p 8080:80)してホストブラウザからアクセスした docker logs/docker exec/docker inspectでコンテナを観察する手段を習得した- Volume と bind mount の違い(管理主体・用途・ポータビリティ)を整理し、実際にコンテナに適用した
- Nginx 公式イメージのログ設計(
/var/log/nginx/は/dev/stdout//dev/stderrへの symbolic link)を実機で発見した(Docker コンテナベストプラクティス・ログアグリゲータ連携への前提知識) - Volume のデータ(および symlink)はコンテナ削除後も残ることを確認した
理解度チェック(○×形式・全 9 問)
| 問 | 問題文 | 解答 |
|---|---|---|
| 1 | docker run コマンドは内部的に docker create と docker start の2ステップを実行する | ○ |
| 2 | docker ps は起動中のコンテナと停止中のコンテナを両方表示する | × |
| 3 | docker stop を実行するとコンテナのファイルシステムも削除される | × |
| 4 | docker logs コマンドはコンテナの標準出力(stdout)と標準エラー(stderr)を表示する | ○ |
| 5 | Volume はホスト OS の任意のパスを直接指定してコンテナにマウントする手段である | × |
| 6 | bind mount に :ro オプションを付けると、コンテナ内からそのマウントパスへの書き込みを禁止できる | ○ |
| 7 | docker rm -f は起動中のコンテナを強制削除できる | ○ |
| 8 | Docker 29.x の docker images 出力では SIZE 列の代わりに DISK USAGE / CONTENT SIZE / EXTRA の3列が表示される | ○ |
| 9 | Nginx 公式 Docker イメージでは、/var/log/nginx/access.log は実ファイルとして存在している | × |
解説(重要問のみ):
- 問2:
docker psは起動中(Running)のコンテナのみ表示します。停止中も含めて表示するにはdocker ps -aを使います。 - 問3:
docker stopはコンテナを停止(Exited 状態)にするだけです。コンテナのファイルシステムはdocker rmを実行するまで残ります。 - 問5:これは bind mount の説明です。Volume は Docker が管理するストレージ領域(
/var/lib/docker/volumes/配下)に作成されます。ホスト OS の任意パスを指定するのは bind mount です。
次回予告:第3回「Dockerfile + マルチステージビルド + JDK 25 / Payara Micro イメージビルド」では、出来合いのイメージを使うのではなく、自分でコンテナイメージを作るステップに進みます。Dockerfile の記法(FROM / COPY / RUN / CMD / ENTRYPOINT / EXPOSE / ENV)、マルチステージビルド(Maven ビルドステージ → JDK 25 + Payara Micro 実行ステージ)、そして fanclub-api Backend(v0.1.0)の初登場を扱います。
シリーズ一覧
第1部:コンテナと Docker
- 第1回 コンテナ技術概念 + Docker 環境準備
- 第2回 Docker 基本操作 ← 今ここ
- 第3回 Dockerfile + マルチステージ + JDK 25 / Payara Micro イメージビルド
- 第4回 コンテナレジストリ + イメージタグ戦略 + Trivy スキャン
第2部:Kubernetes 基礎
第3部:アプリリソース
- 第7回 Pod + Multi-container パターン
- 第8回 Service とネットワーキング
- 第9回 ストレージ(PVC + StatefulSet)+ PostgreSQL DB 追加
- 第10回 ConfigMap + Secret + ServiceAccount 基礎
- 第11回 Job + CronJob + DaemonSet
第4部:ワークロード戦略
- 第12回 Deployment + 3 Probe + Rolling Update + Probe デバッグ実践
- 第13回 Deployment 戦略補完(Blue/Green + Canary + Recreate)
- 第14回 ResourceQuota + LimitRange + Multi-tenant Namespace
