コンテナはデフォルトで外から隔離されており、ファイルも揮発性です。「ブラウザからアクセスしたい」「データを消したくない」という2つのニーズに答えるのが -p(ポートマッピング)と -v(ボリュームマウント)です。第2章の締めくくりとして、この2つを完全に理解しましょう。
目次
- なぜポートマッピングが必要か
- -p の構文と動作
- ポートマッピングの応用
- EXPOSE と -p の違い
- なぜボリュームが必要か
- 3種類のマウント方式
- Named Volume の使い方
- バインドマウントの使い方
- tmpfs マウント
- シミュレータ:データ永続化の違いを体験
- docker volume コマンド
- –mount フラグ(より明示的な記法)
- Named Volume vs バインドマウントの使い分け
- まとめ
1. なぜポートマッピングが必要か
Dockerコンテナは独立したネットワーク名前空間を持ちます(第1章 1-5 参照)。コンテナ内でWebサーバーがポート 80 を LISTEN していても、ホストから localhost:80 にアクセスしても届きません。
デフォルト(ポートマッピングなし):
ブラウザ → localhost:8080 → ❌ 届かない
↓ 隔離
コンテナ → nginx → ポート80
ポートマッピングあり(-p 8080:80):
ブラウザ → localhost:8080 → ✅ Docker が転送 → コンテナ → nginx → ポート80
-p HOST_PORT:CONTAINER_PORT を指定することで、Dockerがホストのポートをコンテナのポートに転送するルールを設定します。Linux では iptables / nftables のルールとして実装されています。
2. -p の構文と動作
-p [ホストIP:]ホストポート:コンテナポート[/プロトコル]
# 基本: ホスト 8080 → コンテナ 80 へ転送
docker run -d -p 8080:80 nginx
# 確認: ブラウザで http://localhost:8080 にアクセス
# ポートマッピングを確認するコマンド
docker port web
# 80/tcp -> 0.0.0.0:8080
# 80/tcp -> :::8080
# 複数ポートを同時にマッピング
docker run -d \
-p 80:80 \
-p 443:443 \
nginx
# MySQL: 3306:3306
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=secret mysql:8.0
docker run -d -p 8080:80 nginx 実行後、ブラウザで http://localhost:8080 を開くと、nginx 公式イメージがデフォルトで用意している Welcome ページが表示されます。こんな画面です:
実際にブラウザからアクセスしてこの画面が出れば、-p 8080:80 の橋渡しが機能している証拠です。(nginx を使ったハンズオンは 2-8 で詳しく扱います)
| 指定例 | 意味 |
|---|---|
-p 8080:80 |
ホストの 8080 → コンテナの 80(全インターフェース) |
-p 80:80 |
ポート番号を同一にする(簡潔) |
-p 127.0.0.1:8080:80 |
ループバックのみ(外部からアクセス不可) |
-p 8080:80/tcp |
TCP を明示(省略時のデフォルト) |
-p 53:53/udp |
UDP で転送(DNS など) |
-p 80(ホスト側省略) |
ホストの空きポートを自動割り当て |
3. ポートマッピングの応用
同じイメージから複数コンテナを別ポートで起動
# 3つの nginx を別ポートで起動(ロードバランシングの基礎)
docker run -d --name web1 -p 8081:80 nginx
docker run -d --name web2 -p 8082:80 nginx
docker run -d --name web3 -p 8083:80 nginx
# 確認
docker ps --format "table {{.Names}}\t{{.Ports}}"
# NAMES PORTS
# web1 0.0.0.0:8081->80/tcp
# web2 0.0.0.0:8082->80/tcp
# web3 0.0.0.0:8083->80/tcp
ホストポートを自動割り当てにして後から確認
# ホスト側は空きポートを自動で使う
docker run -d -p 80 --name web nginx
# 割り当てられたポートを確認
docker port web 80
# 0.0.0.0:32768
# または
docker inspect --format='{{(index (index .NetworkSettings.Ports "80/tcp") 0).HostPort}}' web
# 32768
一度起動したコンテナのポートマッピングを後から変更することはできません。変更するには
docker stop → docker rm → 新しいオプションで docker run が必要です(または docker update は –publish には対応していません)。
4. EXPOSE と -p の違い
DockerfileにはEXPOSEという命令があります。-pと混同されやすいですが、役割が異なります。
| 項目 | EXPOSE(Dockerfile) | -p(docker run) |
|---|---|---|
| 目的 | コンテナが使うポートをドキュメント化する | ホスト ↔ コンテナ間の実際の転送ルールを設定する |
| 外部からのアクセス | ❌ 公開されない(ドキュメントのみ) | ✅ 公開される |
| コンテナ間通信 | Docker ネットワーク内ではアクセス可能(第5章) | ホスト側からのアクセス用 |
| 必須か? | 任意(ドキュメント目的) | 外部公開に必須 |
# Dockerfile の EXPOSE 80 だけではホストからアクセスできない
docker run -d nginx # EXPOSE 80 があっても localhost:80 には届かない
# -p で明示的に公開が必要
docker run -d -p 8080:80 nginx # これで localhost:8080 でアクセス可能
-P(大文字)を使うと、Dockerfile の EXPOSE で宣言した全ポートをホストのランダムポートに自動マッピングします。docker run -P nginx → docker port nginx で確認できます。開発時の素早い確認に便利ですが、本番では -p で明示するほうが安全です。
5. なぜボリュームが必要か
コンテナのファイルシステムは揮発的(エフェメラル)です。コンテナが削除されると、コンテナの書き込みレイヤーに保存されたすべてのデータが消えます(第2章 2-1 参照)。
# 問題: コンテナ内で作ったファイルは削除で消える
docker run -it --name test ubuntu bash
root@xxx:/# echo "重要なデータ" > /data/important.txt
root@xxx:/# exit
docker rm test # ← このとき important.txt は完全に消える
# -v でボリュームをマウントすれば永続化できる
docker run -it --name test -v mydata:/data ubuntu bash
root@xxx:/# echo "重要なデータ" > /data/important.txt
root@xxx:/# exit
docker rm test # コンテナは消えるが...
docker run -it --name test2 -v mydata:/data ubuntu bash
root@yyy:/# cat /data/important.txt
# 重要なデータ ← ちゃんと残っている!
データベースのデータファイル・ユーザーアップロードファイル・設定ファイルなど、コンテナの外で管理すべきものすべてにボリュームが必要です。
6. 3種類のマウント方式
Dockerには3種類のマウント方式があり、用途に応じて使い分けます。
| 方式 | 構文 | 保存場所 | 主な用途 |
|---|---|---|---|
| Named Volume | -v 名前:/パス |
Docker管理領域(/var/lib/docker/volumes/) | DBデータ・アプリデータの永続化 |
| バインドマウント | -v /ホスト/パス:/パス |
ホストの任意のディレクトリ | 開発時のソースコード共有・設定ファイル |
| tmpfs マウント | --tmpfs /パス |
ホストのメモリ上 | 機密情報・一時ファイル(再起動で消える) |
7. Named Volume の使い方
-v ボリューム名:コンテナ内のパス[:オプション]
# MySQL のデータを Named Volume で永続化
docker run -d \
--name db \
-v mysql_data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8.0
# PostgreSQL
docker run -d \
--name pgdb \
-v pg_data:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret \
postgres:16
# 読み取り専用マウント(コンテナ内からは変更不可)
docker run -d -v myconfig:/etc/myapp:ro myapp
# 複数のボリュームを同時にマウント
docker run -d \
-v app_data:/data \
-v app_logs:/var/log/myapp \
myapp
docker run -v mysql_data:/var/lib/mysql を実行するとき、mysql_data ボリュームがまだ存在しなければ Docker が自動的に作成します。事前に docker volume create mysql_data する必要はありません。
8. バインドマウントの使い方
-v /ホスト/絶対パス:コンテナ内のパス[:オプション]
# 開発時: カレントディレクトリをコンテナにマウント(ホットリロード開発)
docker run -d \
--name dev \
-v "$(pwd)":/app \
-w /app \
-p 3000:3000 \
node:20 npm run dev
# 設定ファイルをホストから読み込む
docker run -d \
--name proxy \
-v ./nginx.conf:/etc/nginx/nginx.conf:ro \
-p 80:80 \
nginx
# Windowsの場合のパス指定
# PowerShell: -v ${PWD}:/app
# CMD: -v %cd%:/app
# ホストの /var/log をコンテナから読む(監視用途)
docker run -d -v /var/log:/host/log:ro logparser
バインドマウントはホストのファイルシステムに直接アクセスします。
-v /:/hostroot のようなマウントはコンテナからホスト全体を操作できてしまいます。マウントするパスは必要最小限に限定し、可能なら :ro(読み取り専用)を付けましょう。
Windows・macOS でのバインドマウントの注意
Windows(WSL2)と macOS では、バインドマウントは実質的にDocker VMを経由します。大量のファイルI/Oが発生するとパフォーマンスが低下することがあります。Node.jsの node_modules などはバインドマウント対象に含めず Named Volume にするのがベストプラクティスです:
# node_modules だけ Named Volume に(ホスト側より高速)
docker run -d \
-v "$(pwd)":/app \
-v /app/node_modules \ ← ここが Named Volume(匿名ボリューム)
-p 3000:3000 \
node:20 npm run dev
9. tmpfs マウント
tmpfs はホストのメモリ上にマウントされるため、コンテナ停止・ホスト再起動で内容が消えます。ディスクに書かないため機密情報や高速I/Oが必要な一時ファイルに適しています。
# tmpfs マウント(ディスクに書かれない)
docker run -d --tmpfs /tmp myapp
# サイズとアクセス権限を指定(--mount 形式)
docker run -d \
--mount type=tmpfs,target=/tmp,tmpfs-size=64m,tmpfs-mode=1777 \
myapp
セッションデータ・認証トークン・一時キャッシュなど、ディスクに残したくない機密性の高い一時データに使います。また、ログファイルを大量生成するワークロードで書き込みI/OをSSDに与えたくない場合にも有効です。
10. シミュレータ:データ永続化の違いを体験
「マウントなし」「Named Volume」「バインドマウント」の3モードを切り替えて、コンテナ削除後のデータの運命を比較してみましょう。
① マウントなし: ファイル作成 → 削除 → 再起動でデータが消えることを確認
② Named Volume: ファイル作成 → 削除 → 再起動でデータが残ることを確認
③ バインドマウント: ファイル作成 → 削除 → 再起動でホスト側のデータが引き継がれることを確認
11. docker volume コマンド
# ボリューム一覧
docker volume ls
# DRIVER VOLUME NAME
# local mysql_data
# local pg_data
# local myapp_logs
# ボリュームの詳細情報(保存場所・使用コンテナ等)
docker volume inspect mysql_data
# [
# {
# "Name": "mysql_data",
# "Driver": "local",
# "Mountpoint": "/var/lib/docker/volumes/mysql_data/_data",
# ...
# }
# ]
# 手動でボリュームを作成
docker volume create myvolume
# ボリュームを削除(使用中のコンテナがない場合のみ)
docker volume rm mysql_data
# 使われていないボリュームを一括削除
docker volume prune
# 全ボリュームを強制削除(注意!)
docker volume prune -a
docker volume prune はどのコンテナにも使われていないボリュームを削除します。停止中のコンテナが参照しているボリュームは対象外ですが、コンテナを全削除した後に実行するとデータが消える危険があります。本番環境での実行前は必ず docker volume ls で内容を確認してください。
12. –mount フラグ(より明示的な記法)
Docker 17.06 以降、-v に加えて --mount フラグが使えます。--mount はキー=値形式で読みやすく、誤記を防ぎやすいため公式でも推奨されています。
# -v 形式(短い・従来)
docker run -d -v mysql_data:/var/lib/mysql mysql:8.0
# --mount 形式(明示的・推奨)
docker run -d \
--mount type=volume,source=mysql_data,target=/var/lib/mysql \
mysql:8.0
# バインドマウント(--mount)
docker run -d \
--mount type=bind,source="$(pwd)"/src,target=/app/src,readonly \
myapp
# tmpfs(--mount)
docker run -d \
--mount type=tmpfs,target=/tmp,tmpfs-size=64m \
myapp
| –mount のキー | 説明 |
|---|---|
type |
volume / bind / tmpfs |
source(src) |
ボリューム名 または ホストパス(type=volume で省略すると匿名ボリューム) |
target(dst・destination) |
コンテナ内のマウント先パス(必須) |
readonly(ro) |
読み取り専用にする |
volume-opt |
ドライバ固有のオプション(NFS など) |
13. Named Volume vs バインドマウントの使い分け
| 比較項目 | Named Volume | バインドマウント |
|---|---|---|
| 管理 | Dockerが管理(docker volume コマンド) |
ホストのファイルシステムをそのまま使う |
| 初期データ | イメージの内容でボリュームを初期化する | ホスト側のディレクトリがそのまま見える(イメージ内容を隠す) |
| パフォーマンス | Linux では最適(Docker直管理) | macOS/Windowsでは遅い場合がある |
| ポータビリティ | 高い(ホストパスに依存しない) | 低い(ホストのパス構造に依存する) |
| バックアップ | 専用コンテナ経由で可能 | 通常のファイルシステムツールで可能 |
| 推奨用途 | DB データ・本番アプリデータ | 開発時ソースコード・ホスト側設定ファイル |
Named Volume: 「Dockerが管理すれば十分」な場合。DBのデータファイルなど。
バインドマウント: 「ホストのエディタでファイルを編集したい」場合。開発時のソースコードなど。
第4章ではボリュームの詳細(バックアップ・リストア・ドライバ)を扱います。
14. まとめ
ポートマッピング
| 用途 | コマンド例 |
|---|---|
| 標準的な公開 | docker run -p 8080:80 nginx |
| 複数ポート | docker run -p 80:80 -p 443:443 nginx |
| ローカルのみ(セキュア) | docker run -p 127.0.0.1:3306:3306 mysql |
| 自動割り当て | docker run -p 80 nginx → docker port で確認 |
| EXPOSE の全ポートを自動公開 | docker run -P nginx |
ボリュームマウント
| 用途 | コマンド例 |
|---|---|
| DB データの永続化 | docker run -v mysql_data:/var/lib/mysql mysql |
| 開発時コード共有 | docker run -v "$(pwd)":/app node:20 npm run dev |
| 設定ファイル読み込み | docker run -v ./nginx.conf:/etc/nginx/nginx.conf:ro nginx |
| 機密一時ファイル | docker run --tmpfs /tmp myapp |
第2章「イメージとコンテナの基本操作」はこれで完了です!
次の「第3章:Dockerfileによるイメージ構築」では、自分でイメージを作る方法を学びます。FROM / RUN / COPY / CMD などの命令から始まり、レイヤーキャッシュの最適化・マルチステージビルドまで扱います。
また、「第4章:データの永続化」で Named Volume の詳細(バックアップ・リストア・NFS ドライバ)を深掘りします。
参考リンク
- docker run –publish(公式) — ポートマッピングの全オプション
- Volumes(公式) — Named Volume の詳細・ドライバ・バックアップ方法
- Bind mounts(公式) — バインドマウントの詳細・セキュリティ考慮
- tmpfs mounts(公式) — メモリマウントの使い方とオプション
- Storage overview(公式) — 3種類のマウント方式の比較ガイド



コメント