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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?