2.6 Dockerのポートマッピング(-p)とボリュームマウント(-v)完全解説

【第2章】イメージとコンテナの基本操作

コンテナはデフォルトで外から隔離されており、ファイルも揮発性です。「ブラウザからアクセスしたい」「データを消したくない」という2つのニーズに答えるのが -p(ポートマッピング)と -v(ボリュームマウント)です。第2章の締めくくりとして、この2つを完全に理解しましょう。


目次

  1. なぜポートマッピングが必要か
  2. -p の構文と動作
  3. ポートマッピングの応用
  4. EXPOSE と -p の違い
  5. なぜボリュームが必要か
  6. 3種類のマウント方式
  7. Named Volume の使い方
  8. バインドマウントの使い方
  9. tmpfs マウント
  10. シミュレータ:データ永続化の違いを体験
  11. docker volume コマンド
  12. –mount フラグ(より明示的な記法)
  13. Named Volume vs バインドマウントの使い分け
  14. まとめ

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 ページが表示されます。こんな画面です:



🔒 http://localhost:8080

Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.

実際にブラウザからアクセスしてこの画面が出れば、-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 stopdocker 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(大文字)で EXPOSE 全ポートを一括公開
-P(大文字)を使うと、Dockerfile の EXPOSE で宣言した全ポートをホストのランダムポートに自動マッピングします。docker run -P nginxdocker 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種類のマウント方式があり、用途に応じて使い分けます。

コンテナ
/app   (イメージレイヤー)
/data  ← Named Volume
/src   ← バインドマウント
/tmp   ← tmpfs

Docker管理領域(/var/lib/docker/volumes)
ホストの任意のパス(/home/user/code など)
ホストのメモリ上(再起動で消える)

方式 構文 保存場所 主な用途
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
💡 Named Volume は Docker が自動作成する
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
💡 tmpfs の用途
セッションデータ・認証トークン・一時キャッシュなど、ディスクに残したくない機密性の高い一時データに使います。また、ログファイルを大量生成するワークロードで書き込みI/OをSSDに与えたくない場合にも有効です。

10. シミュレータ:データ永続化の違いを体験

「マウントなし」「Named Volume」「バインドマウント」の3モードを切り替えて、コンテナ削除後のデータの運命を比較してみましょう。

💡 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 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
sourcesrc ボリューム名 または ホストパス(type=volume で省略すると匿名ボリューム)
targetdstdestination コンテナ内のマウント先パス(必須)
readonlyro 読み取り専用にする
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 nginxdocker 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章完了!次のステップ
第2章「イメージとコンテナの基本操作」はこれで完了です!
次の「第3章:Dockerfileによるイメージ構築」では、自分でイメージを作る方法を学びます。FROM / RUN / COPY / CMD などの命令から始まり、レイヤーキャッシュの最適化・マルチステージビルドまで扱います。
また、「第4章:データの永続化」で Named Volume の詳細(バックアップ・リストア・NFS ドライバ)を深掘りします。

参考リンク

Dockerの基礎を動画で体系的に学びませんか?

実務で使う基礎だけを3時間に凝縮。環境構築から丁寧に解説しています。

Udemy Docker入門講座 クーポン割引で講座を見る →

コメント

タイトルとURLをコピーしました