- Docker
Docker network/volume使い方|種類比較表と実行ログで理解
Docker volume は「コンテナを消しても残るデータの置き場所」、Docker network は「コンテナ同士・コンテナと外部をつなぐ通り道」です。 どちらもコンテナの外側に用意するもので、コンテナ本体(イメージから作られる使い捨ての実行環境)とは別に作成・削除できます。この2つを押さえると、「コンテナを作り直したらデータが消えた」「隣のコンテナに名前でつながらない」といったつまずきの大半が説明できるようになります。
この記事では、Docker Engine 29.4.3 と Docker Compose v5.1.3 で実際に実行したログをもとに、volume・bind mount・tmpfs の違い、ネットワークドライバ6種類の違い、既定の bridge とユーザー定義ネットワークで名前解決の結果がどう変わるか、compose.yaml での書き方、よくあるエラー文と直し方までを1ページにまとめました。コマンド早見表は冒頭にあるので、まずはそこから必要な行を探してください。
Docker network/volumeの早見表
まずはこの表で「やりたいこと → コマンド」を引けます。
| やりたいこと | コマンド | ひとこと |
|---|---|---|
| volume を作る | docker volume create mydata |
-v 指定時に無ければ自動作成もされる |
| volume 一覧 | docker volume ls |
--filter name=xx / --filter label=k=v で絞り込み |
| volume の詳細(保存先) | docker volume inspect mydata |
Mountpoint がホスト上の実体 |
| volume をコンテナにつなぐ | docker run -v mydata:/data IMAGE |
--mount type=volume,src=mydata,dst=/data でも同じ |
| 読み取り専用でつなぐ | -v mydata:/data:ro |
--mount ...,readonly |
| ホストのフォルダをつなぐ(bind mount) | docker run -v "$PWD/site":/work IMAGE |
相対パスは ./site のように ./ を付ける |
| メモリ上の一時領域 | docker run --tmpfs /cache:size=16m IMAGE |
コンテナ停止で消える |
| volume を消す | docker volume rm mydata |
使用中のコンテナがあると消せない |
| 未使用 volume を掃除 | docker volume prune |
既定は匿名 volume のみ。名前付きも含めるなら -a |
| ネットワークを作る | docker network create appnet |
既定ドライバは bridge |
| ネットワーク一覧 | docker network ls |
bridge / host / none は最初からある |
| ネットワークの詳細 | docker network inspect appnet |
サブネット・接続中コンテナが見える |
| ネットワークにつないで起動 | docker run --network appnet --name api IMAGE |
同じネットワークなら api で名前解決できる |
| 別名(エイリアス)を付ける | --network-alias api |
1つのコンテナに複数の名前を付けられる |
| 起動中のコンテナを追加接続 | docker network connect appnet web |
外すときは disconnect |
| ポート公開 | docker run -p 127.0.0.1:8080:80 IMAGE |
「ホスト側:コンテナ側」の順 |
| 公開ポートの確認 | docker port web |
docker ps の PORTS 列でも見える |
| ネットワークを消す | docker network rm appnet |
接続中のコンテナがあると消せない |
| 未使用ネットワークを掃除 | docker network prune |
既定の3つは消えない |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Docker network/volume使い方|種類比較表と実行ログで理解」
検証環境とバージョン
この記事のログはすべて次の環境で取得しました。 2026年10月1日時点の Docker Engine の最新版は、公式リリースノートで 29.8.2(2026-09-30) と確認できます。記事のコマンドは 29 系で共通に使えるものだけを扱っています。
| 項目 | バージョン・内容 |
|---|---|
| Docker Engine | 29.4.3(Linux) |
| Docker Compose | v5.1.3(docker compose プラグイン) |
| 使ったイメージ | 最小構成のローカルイメージ mini:1(sh・cat・ls・echo・sleep などのみ) |
| 通信テスト用ツール | Go 標準ライブラリだけで書いた静的バイナリ nettool(HTTPサーバー・HTTP GET・名前解決の3機能)を bind mount で読み込み |
最小イメージには ping も curl も入っていないため、通信の確認用に小さなツールを用意しました。ツールのコードは次のとおりです。CGO_ENABLED=0 go build で作れば、どの Linux イメージにもそのまま持ち込めます。
// nettool/main.go (Go 1.27 / 標準ライブラリのみ)
// 使い方: nettool serve :8080 | nettool lookup NAME | nettool get URL
package main
import (
"fmt"
"io"
"net"
"net/http"
"os"
"time"
)
func main() {
switch os.Args[1] {
case "serve":
h, _ := os.Hostname()
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello from %s\n", h)
})
fmt.Println("listening on", os.Args[2])
http.ListenAndServe(os.Args[2], nil)
case "lookup":
ips, err := net.LookupHost(os.Args[2])
if err != nil {
fmt.Println("lookup error:", err)
os.Exit(1)
}
fmt.Println(os.Args[2], "->", ips)
case "get":
c := http.Client{Timeout: 3 * time.Second}
res, err := c.Get(os.Args[2])
if err != nil {
fmt.Println("get error:", err)
os.Exit(1)
}
b, _ := io.ReadAll(res.Body)
fmt.Print(res.Status, " ", string(b))
}
}
cd nettool && CGO_ENABLED=0 go build -o nettool .
N=$PWD/nettool # 以降のコマンドで使う変数
手元で試すときは mini:1 を alpine や busybox などお使いのイメージに、/nettool lookup を nslookup、/nettool get を wget -qO- などに読み替えてください。
volume・bind mount・tmpfsの違いと選び方
データをコンテナの外に置く方法は3種類あり、「誰が場所を管理するか」で選びます。 Docker 公式ドキュメントでも、この3つを「ストレージのマウント方式」として並べて説明しています。
| 比較項目 | volume | bind mount | tmpfs |
|---|---|---|---|
| 保存先 | Docker が管理する領域(Linux では /var/lib/docker/volumes/名前/_data) |
ホストの任意のパス | ホストのメモリ |
| コンテナ削除後 | 残る | 残る(ホストのファイルそのもの) | 消える |
| コンテナ停止後 | 残る | 残る | 消える |
| 名前で管理 | できる(docker volume ls) |
できない(パスで管理) | できない |
| ホストから直接編集 | 可能だが通常はしない | しやすい | できない |
| 主な用途 | データベースのデータ、アップロードファイル、キャッシュの永続化 | ソースコードの共有(開発時)、設定ファイルの差し込み | 一時ファイル、秘密情報の一時置き場 |
| Compose での書き方 | - dbdata:/var/lib/data +トップレベル volumes: |
- ./src:/app/src |
tmpfs: - /cache |
| バックアップ | docker run -v 名前:/data ... tar などで取り出す |
ホストのファイルをそのまま扱う | 対象外 |
判断の目安は次のとおりです。
| こんなとき | 選ぶもの |
|---|---|
| データベースやアプリのデータを残したい | volume |
| 手元で編集したコードを即コンテナに反映したい | bind mount |
| 設定ファイル1つだけ差し込みたい | bind mount(:ro 付き) |
| 書き込みは多いが残す必要がない | tmpfs |
| 複数コンテナで同じデータを共有したい | volume(同じ名前を両方に指定) |
volumeを作って永続化を確かめる
volume に書いたデータは、コンテナを --rm で消しても次のコンテナから読めます。 実際に「書くコンテナ」と「読むコンテナ」を別々に起動して確認しました。
docker volume create t79-data
docker volume ls --filter name=t79
docker run --rm -v t79-data:/data mini:1 sh -c 'echo "order-001" > /data/orders.txt; ls -l /data'
docker run --rm -v t79-data:/data mini:1 cat /data/orders.txt
実行結果(Docker Engine 29.4.3):
t79-data
DRIVER VOLUME NAME
local t79-data
total 4
-rw-r--r-- 1 root root 10 Oct 1 12:59 orders.txt
order-001
1つ目のコンテナは書き込み後に削除されていますが、2つ目のコンテナで order-001 が読めました。データがコンテナではなく volume 側にあるためです。
docker volume inspectで保存場所を見る
Mountpoint がホスト上の実体のパスです。 ラベルやドライバもここで確認できます。
docker volume inspect t79-data
[
{
"CreatedAt": "2026-10-01T21:59:48+09:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/t79-data/_data",
"Name": "t79-data",
"Options": null,
"Scope": "local"
}
]
Docker Desktop(Mac・Windows)では Docker が内部の Linux 仮想マシンで動いているため、この Mountpoint はホストの Finder やエクスプローラーからは見えません。中身を確認したいときは、volume をつないだコンテナを1つ起動して ls するのが確実です。
読み取り専用でマウントする
設定ファイルや共有データを「読むだけ」にしたいときは :ro または readonly を付けます。 書き込もうとすると次のようになります。
docker run --rm --mount type=volume,src=t79-data,dst=/data,readonly mini:1 \
sh -c 'echo x > /data/a.txt'
sh: 1: cannot create /data/a.txt: Read-only file system
-vと--mountの違い
どちらも同じマウントを作れますが、存在しないパスを指定したときの動きが違います。 bind mount で、ホストに無いフォルダを指定して比べました。
# --mount:存在しないとエラーで止まる
docker run --rm --mount type=bind,src="$PWD/nosuchdir",dst=/work mini:1 ls /work
docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /tmp/.../t79/nosuchdir
# -v:ホスト側に空のフォルダを自動作成して続行する
docker run --rm -v "$PWD/nosuchdir2":/work mini:1 ls -la /work
ls -ld nosuchdir2
total 8
drwxr-xr-x 2 root root 4096 Oct 1 13:00 .
drwxr-xr-x 1 root root 4096 Oct 1 13:00 ..
drwxr-xr-x 2 root root 4096 Oct 1 22:00 nosuchdir2
-v はパスの打ち間違いでも空フォルダを作って起動するため、「設定ファイルが読み込まれていない」と気づくのが遅れることがあります。意図どおりのパスか確かめたいときは --mount を使うと、間違いがその場でエラーとして出ます。
| 比較 | -v / --volume |
--mount |
|---|---|---|
| 書き方 | src:dst:opts の短い形式 |
type=,src=,dst=,readonly のキー=値形式 |
| 存在しない bind 元 | 空フォルダを自動作成 | エラー |
| 読みやすさ | 短い | 長いが意味が明確 |
| 向いている場面 | 手元での試し打ち | スクリプト、手順書 |
bind mountでホストのファイルを共有する
bind mount はホストのフォルダをそのままコンテナに見せます。 コンテナ内で書いたファイルは、ホスト側にすぐ現れます。
mkdir -p site && echo "<h1>hello</h1>" > site/index.html
docker run --rm -v "$PWD/site":/work mini:1 \
sh -c 'cat /work/index.html; echo "from container" > /work/note.txt'
cat site/note.txt
docker run --rm -v ./site:/work mini:1 ls /work
<h1>hello</h1>
from container
index.html
note.txt
相対パスは ./site のように ./ から書きます。site:/work と書くと、site という名前の volume として扱われます。
tmpfsでメモリ上に一時領域を作る
tmpfs はディスクに書かず、コンテナが止まると中身が消える領域です。 サイズ上限も指定できます。
docker run --rm --tmpfs /cache:size=16m mini:1 \
sh -c 'echo tmp > /cache/a; ls -l /cache; cat /proc/mounts' | grep -E 'cache|^total|^-'
total 4
-rw-r--r-- 1 root root 4 Oct 1 13:00 a
tmpfs /cache tmpfs rw,nosuid,nodev,noexec,relatime,size=16384k 0 0
size=16384k(16MB)で、noexec などのオプションが付いた状態でマウントされているのがわかります。
匿名volumeとdocker rm -v
-v /data のように名前を付けずに指定すると、ランダムな名前の「匿名 volume」ができます。 コンテナを docker rm しても匿名 volume は残ります。
docker run -d --name t79-anon -v /data mini:1 sleep 1
docker inspect t79-anon --format '{{json .Mounts}}'
docker rm t79-anon
docker volume ls
[{"Type":"volume","Name":"30a1dcb02666c37ca6ccfe37e3acc668f3fce3e87ec70b826db087ec127f84a8","Source":"/var/lib/docker/volumes/30a1dcb0.../_data","Destination":"/data","Driver":"local","Mode":"","RW":true,"Propagation":""}]
t79-anon
DRIVER VOLUME NAME
local 30a1dcb02666c37ca6ccfe37e3acc668f3fce3e87ec70b826db087ec127f84a8
コンテナと一緒に匿名 volume も消すなら docker rm -v、docker run --rm なら自動で消えます。 長く使うデータには最初から名前を付けておくと、あとで探しやすくなります。
volumeの削除とpruneの動き
使用中の volume は削除できません。 エラー文にどのコンテナが使っているかが出ます。
docker run -d --name t79-holder -v t79-data:/data mini:1 sleep 300
docker volume rm t79-data
Error response from daemon: remove t79-data: volume is in use - [49be87ac85897548b7d95d8f50888aa5138bf04533826b15bcddd4f38bf4559e]
コンテナを docker rm -f t79-holder で消してから、もう一度 docker volume rm すれば削除できます。
docker volume prune は、Docker Engine 23 以降は既定で匿名 volume だけを対象にします。 名前付きの未使用 volume があっても、-a を付けない限り残ります。
docker volume create t79-tmpvol
docker volume prune -f
Total reclaimed space: 0B
名前付きの t79-data と t79-tmpvol は未使用でしたが、-a なしでは何も消えませんでした。名前付きも含めて掃除するときは docker volume prune -a です。 同じホストで他の人やほかのアプリが volume を使っている場合は、--filter label=... で対象を絞ってから実行すると安心です。
docker volume create --label env=dev t79-l
docker volume ls --filter label=env=dev
DRIVER VOLUME NAME
local t79-l
Docker networkの種類と比較表
ネットワークドライバは6種類あり、普段使うのは「ユーザー定義 bridge」です。 docker network ls を実行すると、最初から3つが用意されています。
docker network ls
NETWORK ID NAME DRIVER SCOPE
8e0b0a451046 bridge bridge local
4b5269cdf79e host host local
07568ace05bf none null local
| ドライバ | 作り方 | コンテナ名で名前解決 | ホストとの関係 | 主な用途 |
|---|---|---|---|---|
bridge(既定の bridge) |
最初からある。--network 省略時 |
できない | 仮想ブリッジ docker0 経由。公開には -p |
1コンテナだけの手軽な起動 |
| ユーザー定義 bridge | docker network create NAME |
できる(内蔵DNS 127.0.0.11) | 同上 | 複数コンテナの連携(基本はこれ) |
| host | --network host |
―(ホストと同じ) | ホストのネットワークをそのまま使う。-p は不要で無視される |
ポート数が多い、変換を挟みたくない処理 |
| none | --network none |
― | ループバック(lo)のみ。外と通信しない | ネットワーク不要なバッチ処理、隔離 |
| overlay | docker network create -d overlay NAME(Swarm 必須) |
できる | 複数ホストをまたぐ仮想ネットワーク | Swarm で複数台に分散したサービス |
| macvlan | docker network create -d macvlan --subnet ... -o parent=eth0 NAME |
できる(同ネットワーク内) | コンテナに MAC アドレスを割り当て、LAN 上の1台のように見せる | 既存の LAN 機器から直接 IP で見せたい場合 |
このほか、macvlan に近い ipvlan(MAC アドレスを共有する方式)もあります。この記事の環境では overlay と macvlan の通信までは確かめていません(overlay は作成時のエラー文のみ確認)。仕様は公式ドキュメントの「Network drivers」に沿って記載しています。
flowchart TD
A[コンテナをどのネットワークにつなぐ?] --> B{外部と通信する?}
B -- しない --> N[none]
B -- する --> C{複数ホストにまたがる?}
C -- はい(Swarm) --> O[overlay]
C -- いいえ --> D{LAN上で独立したIPが必要?}
D -- はい --> M[macvlan / ipvlan]
D -- いいえ --> E{ポート変換なしでホストと同じ口を使いたい?}
E -- はい --> H[host]
E -- いいえ --> U[ユーザー定義 bridge(おすすめ)]
既定bridgeとユーザー定義bridgeで名前解決を比べる
同じ bridge ドライバでも、既定の bridge ではコンテナ名で通信できず、自分で作ったネットワークではできます。 理由は /etc/resolv.conf に出ています。
既定のbridgeではコンテナ名が引けない
docker run -d --name t79-web1 -v $N:/nettool:ro mini:1 /nettool serve :8080
docker run --rm -v $N:/nettool:ro mini:1 /nettool lookup t79-web1
lookup error: lookup t79-web1 on 8.8.8.8:53: no such host
名前を外部の DNS(8.8.8.8)に問い合わせているため見つかりません。 IP アドレスを直接指定すれば通信はできます。
IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' t79-web1)
echo $IP
docker run --rm -v $N:/nettool:ro mini:1 /nettool get http://$IP:8080/
docker run --rm -v $N:/nettool:ro mini:1 cat /etc/resolv.conf
172.17.0.2
200 OK hello from e530639aac09
# Generated by Docker Engine.
# This file can be edited; Docker Engine will not make further changes once it
# has been modified.
nameserver 8.8.8.8
nameserver 8.8.4.4
options timeout:2 attempts:3
# Based on host file: '/etc/resolv.conf' (legacy)
# Overrides: []
IP アドレスはコンテナを作り直すたびに変わる可能性があるため、IP 直書きは長く使う設定には向きません。
ユーザー定義bridgeではコンテナ名とエイリアスで引ける
docker network create t79-net
docker run -d --name t79-api --network t79-net --network-alias api \
-v $N:/nettool:ro mini:1 /nettool serve :8080
docker run --rm --network t79-net -v $N:/nettool:ro mini:1 /nettool lookup t79-api
docker run --rm --network t79-net -v $N:/nettool:ro mini:1 /nettool lookup api
docker run --rm --network t79-net -v $N:/nettool:ro mini:1 /nettool get http://t79-api:8080/
docker run --rm --network t79-net -v $N:/nettool:ro mini:1 cat /etc/resolv.conf
t79-api -> [172.18.0.2]
api -> [172.18.0.2]
200 OK hello from 65f52e8ee497
# Generated by Docker Engine.
# This file can be edited; Docker Engine will not make further changes once it
# has been modified.
nameserver 127.0.0.11
options timeout:2 attempts:3 ndots:0
# Based on host file: '/etc/resolv.conf' (internal resolver)
# ExtServers: [host(8.8.8.8) host(8.8.4.4)]
# Overrides: []
# Option ndots from: internal
ユーザー定義ネットワークでは、Docker 内蔵の DNS サーバー 127.0.0.11 がコンテナ名とエイリアスを答えます。 それ以外の名前はホストの DNS(ExtServers)へ転送されます。
| 比較 | 既定の bridge | ユーザー定義 bridge |
|---|---|---|
| nameserver | ホストと同じ(今回は 8.8.8.8) | 127.0.0.11(内蔵DNS) |
| コンテナ名で解決 | できない(no such host) |
できる |
--network-alias |
使えない | 使える |
| サブネット(今回) | 172.17.0.0/16 | 172.18.0.0/16(自動割り当て) |
| 他のネットワークとの隔離 | 既定 bridge 上の全コンテナが同居 | ネットワークごとに分かれる |
別ネットワークのコンテナはnetwork connectでつなぐ
ネットワークが違うと名前は引けません。 既定 bridge にいる t79-web1 を、t79-net から探すと見つかりません。docker network connect で追加接続すると届くようになります。
docker run --rm --network t79-net -v $N:/nettool:ro mini:1 /nettool lookup t79-web1
docker network connect t79-net t79-web1
docker run --rm --network t79-net -v $N:/nettool:ro mini:1 /nettool get http://t79-web1:8080/
docker network disconnect t79-net t79-web1
lookup error: lookup t79-web1 on 127.0.0.11:53: no such host
200 OK hello from e530639aac09
1つのコンテナを複数のネットワークにつなげるので、「表側用」「裏側用」とネットワークを分けて、両方に属するコンテナだけが橋渡しをする構成が作れます(後半の Compose 例で確認します)。
ポート公開(-p)の書き方と確認
ホストからコンテナに届けるには -p ホスト側:コンテナ側 で公開します。 IP を付けると、どのアドレスで待ち受けるかを絞れます。
docker run -d --name t79-pub -p 127.0.0.1:7790:8080 -v $N:/nettool:ro mini:1 /nettool serve :8080
docker port t79-pub
curl -s http://127.0.0.1:7790/
docker ps --filter name=t79-pub --format '{{.Names}} {{.Ports}}'
8080/tcp -> 127.0.0.1:7790
hello from 0dfcddea9bd7
t79-pub 127.0.0.1:7790->8080/tcp
| 書き方 | 意味 |
|---|---|
-p 8080:80 |
ホストの全アドレスの 8080 → コンテナの 80 |
-p 127.0.0.1:8080:80 |
ホスト自身からだけ接続できる(開発時におすすめ) |
-p 8080:80/udp |
UDP を公開 |
-p 80 |
ホスト側は空いているポートを自動で割り当て(docker port で確認) |
-P |
Dockerfile の EXPOSE にあるポートをすべて自動割り当てで公開 |
EXPOSE は「このポートを使います」という目印で、それだけでは公開されません。 ホストから届けるには -p か -P が必要です。なお、同じネットワーク内のコンテナ同士は -p なしでコンテナ側のポート(例: 8080)に直接つながります。
アプリが127.0.0.1で待ち受けていると届かない
-p を付けても、コンテナ内のアプリが 127.0.0.1 だけで待ち受けていると外から届きません。 実際に比べました。
docker run -d --name t79-lo -p 127.0.0.1:7791:8080 -v $N:/nettool:ro mini:1 /nettool serve 127.0.0.1:8080
curl -sS http://127.0.0.1:7791/
curl: (52) Empty reply from server
ポート転送はコンテナの eth0 側に届くため、コンテナ内のループバックだけを見ているアプリには到達しません。アプリの待ち受けを 0.0.0.0(全アドレス)に変えると解決します。Node.js なら listen(8080, "0.0.0.0")、Python の開発サーバーなら --host 0.0.0.0 などです。
hostとnoneの動きを確かめる
host ネットワークのコンテナは、ホストの 127.0.0.1 をそのまま使えます。 none のコンテナはループバックしか持たないため、外へは出られません。
docker run --rm --network host -v $N:/nettool:ro mini:1 /nettool get http://127.0.0.1:7790/
docker run --rm --network none -v $N:/nettool:ro mini:1 \
sh -c 'cat /proc/net/dev; /nettool get http://172.17.0.1:7790/'
200 OK hello from 0dfcddea9bd7
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
get error: Get "http://172.17.0.1:7790/": dial tcp 172.17.0.1:7790: connect: network is unreachable
none のコンテナにはインターフェースが lo しかなく、network is unreachable になります。外部と通信させたくない処理を閉じ込めるのに便利です。
docker composeでnetworksとvolumesを書く
Compose では、トップレベルの networks: と volumes: で定義し、各サービスから名前で参照します。 次の例は「web(表)― api(橋渡し)― db(裏)」の3層で、db 側のネットワークを internal: true にしています。
# compose.yaml(Docker Compose v5.1.3 で動作確認)
services:
web:
image: mini:1
command: ["/nettool", "serve", ":8080"]
ports:
- "127.0.0.1:7792:8080"
volumes:
- ./nettool:/nettool:ro # bind mount(./ から始める)
networks:
- front
api:
image: mini:1
command: ["/nettool", "serve", ":8080"]
volumes:
- ./nettool:/nettool:ro
- api-data:/data # 名前付き volume
networks:
- front
- back
db:
image: mini:1
command: ["sleep", "3600"]
volumes:
- ./nettool:/nettool:ro
- db-data:/data
networks:
- back
networks:
front:
back:
internal: true # 外部への出口を持たないネットワーク
volumes:
api-data:
db-data:
docker compose -p t79 up -d
docker compose -p t79 ps --format 'table {{.Service}}\t{{.Status}}\t{{.Ports}}'
docker network ls --filter name=t79
docker volume ls --filter name=t79
Network t79_front Created
Network t79_back Created
Volume t79_db-data Created
Volume t79_api-data Created
...
SERVICE STATUS PORTS
api Up Less than a second
db Up Less than a second
web Up Less than a second 127.0.0.1:7792->8080/tcp
NETWORK ID NAME DRIVER SCOPE
6ca80f157492 t79_back bridge local
1c25a4d455d8 t79_front bridge local
DRIVER VOLUME NAME
local t79_api-data
local t79_db-data
Compose が作るネットワークと volume には「プロジェクト名_」が前に付きます(-p t79 なので t79_front)。networks: を書かなかった場合は プロジェクト名_default が1つ作られ、全サービスがそこにつながります。
サービス名で通信でき、ネットワークで隔離される
curl -s http://127.0.0.1:7792/
docker compose -p t79 exec web /nettool get http://api:8080/
docker compose -p t79 exec web /nettool lookup db
docker compose -p t79 exec db /nettool lookup api
docker compose -p t79 exec db /nettool lookup web
hello from c611be44d0e4
200 OK hello from 05ac8e75cc08
lookup error: lookup db on 127.0.0.11:53: no such host
api -> [172.19.0.2]
lookup error: lookup web on 127.0.0.11:53: server misbehaving
| 送信元 → 宛先 | 結果 | 理由 |
|---|---|---|
| web → api | 届く | 両方が front に所属 |
| web → db | 名前が引けない | db は back のみ |
| db → api | 引ける | 両方が back に所属 |
| db → web | 引けない(server misbehaving) |
back は internal のため外部 DNS への転送もない |
サービス名がそのままホスト名になり、ネットワークを分けるだけで通信範囲を絞れます。
down と down -v の違い
docker compose down は volume を残し、down -v は volume まで削除します。
docker compose -p t79 exec db sh -c 'echo stock=42 > /data/stock.txt'
docker compose -p t79 down
docker volume ls --filter name=t79
docker compose -p t79 up -d
docker compose -p t79 exec db cat /data/stock.txt
docker compose -p t79 down -v
docker volume ls --filter name=t79
...
Network t79_back Removed
Network t79_front Removed
DRIVER VOLUME NAME
local t79_api-data
local t79_db-data
stock=42
...
Volume t79_api-data Removed
Volume t79_db-data Removed
DRIVER VOLUME NAME
down でコンテナとネットワークが消えても、volume に書いた stock=42 は再度の up で読めました。データを初期化したいときだけ down -v を使います。
既存のネットワーク・volumeを使う(external)
Compose の外で作ったネットワークや volume を使うときは external: true を指定します。 存在しない場合は起動前にエラーになります。
services:
app:
image: mini:1
command: ["sleep", "60"]
networks: [shared]
volumes: [shared-data:/data]
networks:
shared:
external: true
name: t79-shared
volumes:
shared-data:
external: true
name: t79-shared-data
network t79-shared declared as external, but could not be found
external volume "t79-shared-data" not found
docker network create t79-shared と docker volume create t79-shared-data を先に実行すると起動できました。複数の compose.yaml で同じネットワークを共有したいときの定番の書き方です。 Compose 全体の書き方は「Docker Composeの使い方」の記事で詳しく扱っています。
Composeのnetworks/volumesでよく使う設定
| 設定 | 書く場所 | 意味 |
|---|---|---|
driver: bridge |
networks.NAME |
ドライバ指定(省略時 bridge) |
internal: true |
networks.NAME |
外部への出口を持たない |
ipam.config: - subnet: 10.10.0.0/24 |
networks.NAME |
サブネットを固定 |
aliases: [db-main] |
services.X.networks.NAME |
そのネットワーク内での別名 |
external: true + name: |
networks.NAME / volumes.NAME |
既存のものを使う |
name: fixed-name |
volumes.NAME |
プロジェクト名を付けない固定名にする |
labels: |
volumes.NAME / networks.NAME |
掃除や絞り込み用の目印 |
read_only: true 相当 |
- data:/data:ro |
読み取り専用マウント |
tmpfs: [/cache] |
services.X |
tmpfs をマウント |
よくあるエラーと直し方
エラー文はそのまま検索に使えるよう、今回の環境で出た文言を載せています。
| エラー文(実際の出力) | 原因 | 直し方 |
|---|---|---|
remove t79-data: volume is in use - [49be87ac...] |
volume を使うコンテナが残っている(停止中も含む) | 表示された ID のコンテナを docker rm してから削除 |
invalid mount config for type "bind": bind source path does not exist: ... |
--mount type=bind の src が存在しない |
パスを確認する、先に mkdir -p する |
Read-only file system |
:ro / readonly でマウントしている |
書き込みが必要なら ro を外す、書く場所を別に用意する |
lookup NAME on 8.8.8.8:53: no such host |
既定 bridge でコンテナ名を引いている | docker network create で作ったネットワークに両方をつなぐ |
lookup NAME on 127.0.0.11:53: no such host |
相手が別のネットワークにいる、名前の打ち間違い | docker network connect で同じネットワークに入れる、docker network inspect で所属を確認 |
Bind for 127.0.0.1:7790 failed: port is already allocated |
同じホストポートを別コンテナが使用中 | ホスト側ポートを変える、使用中コンテナを止める(docker ps で確認) |
curl: (52) Empty reply from server |
コンテナ内のアプリが 127.0.0.1 だけで待受 | アプリの待受を 0.0.0.0 にする |
connect: network is unreachable |
--network none など、経路がない |
通信が必要なら bridge 系のネットワークにつなぐ |
network nosuchnet not found |
--network に存在しない名前 |
docker network ls で名前を確認、先に作成 |
network with name t79-x already exists |
同名のネットワークがある | 既存を使う、または別名で作る |
invalid pool request: Pool overlaps with other one on this address space |
--subnet が既存ネットワークと重なっている |
重ならないサブネットを指定(docker network inspect で既存を確認) |
network t79-net has active endpoints |
接続中のコンテナがある | docker network disconnect かコンテナ削除の後に rm |
This node is not a swarm manager. ... |
overlay を Swarm 外で作ろうとした | docker swarm init 後に作成、単一ホストなら bridge を使う |
network X declared as external, but could not be found |
Compose の external ネットワークが未作成 | docker network create X を先に実行 |
external volume "X" not found |
Compose の external volume が未作成 | docker volume create X を先に実行 |
つながらないときの確認順
通信トラブルは「名前 → 所属ネットワーク → 待受アドレス → 公開ポート」の順に見ると早く絞り込めます。
| 順番 | 確認すること | コマンド |
|---|---|---|
| 1 | 相手コンテナが動いているか | docker ps |
| 2 | 同じネットワークにいるか | docker network inspect NET --format '{{range .Containers}}{{.Name}} {{end}}' |
| 3 | 名前が引けるか | コンテナ内で nslookup NAME など |
| 4 | アプリが 0.0.0.0 で待ち受けているか | コンテナ内で ss -tlnp(入っていれば) |
| 5 | ホストから来る場合、ポートが公開されているか | docker port NAME |
よくある質問
Q. volume と bind mount、データベースのデータはどちらに置けばよいですか?
A. 名前付き volume がおすすめです。 Docker が場所と権限をまとめて管理するため、ホストの OS やフォルダ構成に左右されにくく、docker volume ls で一覧できます。ホストから直接ファイルを編集したい用途(ソースコードや設定ファイル)は bind mount が向いています。
Q. docker volume prune を実行したのに名前付き volume が消えません。
A. Docker Engine 23 以降の prune は、既定で匿名 volume だけを消します。 名前付きの未使用 volume も消す場合は docker volume prune -a を使います。今回の検証でも、-a なしでは Total reclaimed space: 0B で何も削除されませんでした。
Q. Compose ではサービス名でつながるのに、docker run だとつながりません。
A. Compose は自動で「プロジェクト名_default」というユーザー定義ネットワークを作るためです。 docker run で --network を省略すると既定の bridge につながり、コンテナ名では解決できません。docker network create で作ったネットワークを --network で指定すると、同じように名前でつながります。
Q. -p で公開したポートに他のPCからアクセスできません。
A. -p 127.0.0.1:8080:80 のように 127.0.0.1 を付けていると、ホスト自身からしか接続できません。 他の端末から使う場合は -p 8080:80 にし、ホスト側のファイアウォール設定もあわせて確認してください。
まとめ
- volume は Docker が管理する永続データ置き場で、コンテナを消しても残る。データベースなどのデータはここに置く
- bind mount はホストのフォルダをそのまま見せる方式。
-vは存在しないパスを自動作成し、--mountはエラーにする - tmpfs はメモリ上の一時領域で、コンテナ停止で消える
- 既定の bridge ではコンテナ名で解決できず、ユーザー定義 bridge なら内蔵 DNS(127.0.0.11)で解決できる
-pは「ホスト側:コンテナ側」。アプリは 0.0.0.0 で待ち受けると外から届く- Compose はトップレベルの networks/volumes で定義し、
internal: trueやexternal: trueで用途に合わせて使い分ける docker compose downは volume を残し、down -vで削除、docker volume pruneは-aで名前付きも対象になる
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Docker network/volume使い方|種類比較表と実行ログで理解」
株式会社RJCでは、Docker のネットワークとストレージの仕組みを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。