はじめに

Dockerコンテナは軽量で起動が速い反面、コンテナを削除するとその中のデータも消えてしまいます。また、複数のコンテナを連携させるには、コンテナ間でネットワーク通信を行う必要があります。

本記事では、Dockerのデータ永続化(ボリューム・バインドマウント)とネットワーク設定(bridge/hostネットワーク、ポートマッピング)について、基礎から実践的な使い方まで解説します。この記事を読み終えると、以下のことができるようになります。

  • ボリュームとバインドマウントの違いを理解し、適切に使い分けられる
  • docker volumeコマンドでボリュームを作成・管理できる
  • bridgeネットワークを使ってコンテナ間通信を設定できる
  • ポートマッピングでコンテナのサービスを外部に公開できる

前提として、Dockerの基本コマンド(docker rundocker psなど)を理解していることを想定しています。まだ基本コマンドに不安がある場合は、Docker基本コマンド完全ガイドを参照してください。

Dockerにおけるデータ永続化の重要性

コンテナのデータは消える

Dockerコンテナには書き込み可能なレイヤー(Writable Layer)があり、コンテナ内でファイルを作成・編集できます。しかし、この書き込み可能レイヤーはコンテナと運命を共にします。

flowchart TD
    subgraph Container["コンテナ実行中"]
        subgraph WritableLayer["書き込み可能レイヤー"]
            AppData["アプリケーションが生成したデータ"]
            LogFiles["ログファイル"]
            DBData["データベースのデータ ← 消える"]
        end
        subgraph ReadOnlyLayer["読み取り専用レイヤー (イメージ)"]
            OS["OS, ライブラリ, アプリコード"]
        end
    end
    Container -->|"docker rm (コンテナ削除)"| Lost["書き込み可能レイヤーのデータは完全に消失"]

例えば、データベースコンテナを起動してデータを蓄積しても、docker rmでコンテナを削除すると、すべてのデータが失われます。

データ永続化が必要なユースケース

以下のような場面では、コンテナの外部にデータを保存する必要があります。

ユースケース 具体例
データベース MySQL、PostgreSQL、MongoDBのデータファイル
アップロードファイル ユーザーがアップロードした画像や文書
ログファイル アプリケーションログ、アクセスログ
設定ファイル アプリケーションの設定を外部から注入
開発時のソースコード ホストで編集したコードをコンテナに反映

Dockerでは、この問題を解決するためにボリュームバインドマウントという2つの仕組みを提供しています。

ボリュームとバインドマウントの違い

Dockerには主に3種類のデータ永続化方法があります。

方式 管理者 用途
ボリューム(Volume) Docker 本番環境でのデータ永続化
バインドマウント(Bind Mount) ユーザー 開発環境でのソースコード共有
tmpfsマウント メモリ 一時的な機密データの保存

本記事では、最もよく使われるボリュームとバインドマウントに焦点を当てます。

flowchart TB
    subgraph Volume["ボリューム - Dockerが管理する領域に保存"]
        direction LR
        HostVolume["ホスト\n/var/lib/docker/\nvolumes/myvolume/_data/\n(※Dockerが自動管理)"]
        ContainerVolume["コンテナ\n/data"]
        HostVolume <--> ContainerVolume
    end
    subgraph BindMount["バインドマウント - ホストの任意のディレクトリをマウント"]
        direction LR
        HostBind["ホスト\n/home/user/myproject/src/\n(※ユーザーが直接管理)"]
        ContainerBind["コンテナ\n/app"]
        HostBind <--> ContainerBind
    end

ボリュームの特徴

ボリュームはDockerによって完全に管理されるデータ保存領域です。

メリット

  • Docker CLIやAPIで簡単に管理できる
  • Linux/Windowsの両方で動作する
  • 複数のコンテナ間で安全に共有できる
  • ボリュームドライバーを使ってリモートストレージやクラウドに保存できる
  • バックアップや移行が容易

デメリット

  • ホストから直接ファイルにアクセスしにくい

バインドマウントの特徴

バインドマウントは、ホストマシンの任意のディレクトリをコンテナにマウントします。

メリット

  • ホストとコンテナでファイルをリアルタイムに共有できる
  • 開発時にソースコードの変更を即座にコンテナに反映できる
  • 設定ファイルをホストから注入しやすい

デメリット

  • ホストのディレクトリ構造に依存する(ポータビリティが低い)
  • ホストのファイルシステムへの書き込みアクセスを許可するため、セキュリティリスクがある

ボリュームの作成と利用方法

ボリュームの基本操作

ボリュームはdocker volumeコマンドで管理します。

ボリュームの作成

1
2
3
4
5
# ボリュームを作成
docker volume create my-data

# 作成されたボリュームを確認
docker volume ls

実行結果の例:

DRIVER    VOLUME NAME
local     my-data

ボリュームの詳細確認

1
docker volume inspect my-data

実行結果の例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[
    {
        "CreatedAt": "2026-01-01T12:00:00Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-data/_data",
        "Name": "my-data",
        "Options": {},
        "Scope": "local"
    }
]

Mountpointが実際にデータが保存されるホスト上のパスです。ただし、Docker Desktopを使用している場合、このパスはLinux VM内のパスであり、ホストから直接アクセスすることは想定されていません。

コンテナにボリュームをマウントする

ボリュームをコンテナにマウントするには、--mountフラグまたは-vフラグを使用します。--mountフラグの方が明示的で推奨されています。

–mountフラグを使用する場合(推奨)

1
2
3
4
docker run -d \
  --name my-nginx \
  --mount source=my-data,target=/usr/share/nginx/html \
  nginx:latest

-vフラグを使用する場合

1
2
3
4
docker run -d \
  --name my-nginx \
  -v my-data:/usr/share/nginx/html \
  nginx:latest

どちらのコマンドも、my-dataボリュームをコンテナ内の/usr/share/nginx/htmlにマウントします。

実践例: MySQLのデータを永続化する

データベースはデータ永続化の典型的なユースケースです。以下の例では、MySQLコンテナのデータをボリュームに保存します。

1
2
3
4
5
6
7
8
9
# データ用ボリュームを作成
docker volume create mysql-data

# MySQLコンテナを起動(ボリュームをマウント)
docker run -d \
  --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=secret123 \
  --mount source=mysql-data,target=/var/lib/mysql \
  mysql:8.0

この設定により、コンテナを削除してもデータはmysql-dataボリュームに保持されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# コンテナを停止・削除
docker stop my-mysql
docker rm my-mysql

# 同じボリュームで新しいコンテナを起動(データは保持される)
docker run -d \
  --name my-mysql-new \
  -e MYSQL_ROOT_PASSWORD=secret123 \
  --mount source=mysql-data,target=/var/lib/mysql \
  mysql:8.0

ボリュームの削除

使用しなくなったボリュームは、明示的に削除する必要があります。

1
2
3
4
5
# 特定のボリュームを削除
docker volume rm my-data

# 使用されていないボリュームをすべて削除
docker volume prune

注意: ボリュームを削除すると、中のデータは完全に失われます。本番環境では、削除前に必ずバックアップを取得してください。

バインドマウントの使い方

バインドマウントの基本

バインドマウントは、ホストの任意のディレクトリをコンテナにマウントします。開発環境でソースコードを共有する際によく使用されます。

–mountフラグを使用する場合(推奨)

1
2
3
4
docker run -d \
  --name dev-nginx \
  --mount type=bind,source="$(pwd)"/html,target=/usr/share/nginx/html \
  nginx:latest

-vフラグを使用する場合

1
2
3
4
docker run -d \
  --name dev-nginx \
  -v "$(pwd)"/html:/usr/share/nginx/html \
  nginx:latest

Windowsの場合は、パスの指定方法が異なります。

1
2
3
4
docker run -d `
  --name dev-nginx `
  -v ${PWD}/html:/usr/share/nginx/html `
  nginx:latest

–mountと-vの違い

--mount-vには重要な違いがあります。

項目 –mount -v
存在しないパスの扱い エラーになる 自動的にディレクトリを作成する
構文 明示的(key=value形式) 簡潔だが暗黙的
推奨度 推奨 互換性のために残されている
1
2
3
4
5
6
7
# 存在しないパスを-vで指定すると、ディレクトリが自動作成される
docker run -v /nonexistent/path:/app alpine ls /app
# → /nonexistent/path ディレクトリが作成される

# 存在しないパスを--mountで指定すると、エラーになる
docker run --mount type=bind,source=/nonexistent/path,target=/app alpine ls /app
# → エラー: bind source path does not exist

明示的にエラーを検出したい場合は--mountを使用することをお勧めします。

実践例: 開発環境でのソースコード共有

Node.jsアプリケーションの開発で、ホストのソースコードをコンテナに共有する例です。

1
2
3
4
5
6
7
# プロジェクトディレクトリで実行
docker run -d \
  --name node-dev \
  --mount type=bind,source="$(pwd)",target=/app \
  -w /app \
  node:20 \
  npm run dev

この設定により、ホストでソースコードを編集すると、即座にコンテナ内に反映されます。ホットリロードを備えたフレームワーク(Vite、Next.jsなど)と組み合わせると、効率的な開発環境を構築できます。

読み取り専用でマウントする

セキュリティを高めるため、コンテナからの書き込みが不要な場合は読み取り専用でマウントできます。

1
2
3
4
5
# 設定ファイルを読み取り専用でマウント
docker run -d \
  --name my-app \
  --mount type=bind,source="$(pwd)"/config,target=/app/config,readonly \
  my-app:latest

Dockerネットワークの基礎

なぜネットワークが必要か

現代のアプリケーションは、複数のサービスで構成されることが一般的です。例えば、Webアプリケーション、データベース、キャッシュサーバーなどを連携させる必要があります。Dockerネットワークは、これらのコンテナ間で安全に通信するための仕組みを提供します。

flowchart TB
    subgraph DockerNetwork["Docker Network"]
        WebApp["Web App\n(nginx)\nPort 80"]
        Database["Database\n(postgres)\nPort 5432"]
        Redis["Redis\n(cache)\nPort 6379"]
        WebApp --> Database
        Redis --> Database
    end
    External["外部アクセス\nhttp://localhost:8080"] -->|"ポートマッピング (8080:80)"| WebApp

ネットワークドライバーの種類

Dockerは複数のネットワークドライバーを提供しています。

ドライバー 説明 用途
bridge デフォルトのネットワーク。コンテナ間で通信可能 単一ホストでの一般的な使用
host ホストのネットワークを直接使用 高パフォーマンスが必要な場合
none ネットワーク接続なし 完全に隔離されたコンテナ
overlay 複数のDockerホスト間で通信 Docker Swarm環境

本記事では、最もよく使われるbridgehostについて解説します。

デフォルトbridgeネットワークの特徴

Dockerをインストールすると、bridgeという名前のデフォルトネットワークが自動的に作成されます。--networkオプションを指定せずにコンテナを起動すると、このデフォルトbridgeネットワークに接続されます。

1
2
# デフォルトネットワークを確認
docker network ls

実行結果の例:

NETWORK ID     NAME      DRIVER    SCOPE
a1b2c3d4e5f6   bridge    bridge    local
g7h8i9j0k1l2   host      host      local
m3n4o5p6q7r8   none      null      local

デフォルトbridgeネットワークの制限

デフォルトbridgeネットワークには重要な制限があります。

  • コンテナ間でIPアドレスでの通信は可能
  • コンテナ名での名前解決ができない
1
2
3
4
5
6
7
# 2つのコンテナをデフォルトbridgeで起動
docker run -d --name container1 alpine sleep 3600
docker run -d --name container2 alpine sleep 3600

# container1からcontainer2にpingを試みる
docker exec container1 ping -c 2 container2
# → ping: bad address 'container2'(名前解決できない)

この制限を解消するには、ユーザー定義bridgeネットワークを使用します。

ユーザー定義bridgeネットワークの作成と活用

ユーザー定義bridgeネットワークは、デフォルトbridgeネットワークより優れた機能を提供します。

ユーザー定義bridgeネットワークの利点

  • コンテナ名で自動的に名前解決ができる
  • より良い分離性(異なるネットワークのコンテナは通信できない)
  • コンテナを停止せずにネットワークに接続・切断できる
  • ネットワークごとに個別の設定が可能

ネットワークの作成と使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# ユーザー定義bridgeネットワークを作成
docker network create my-network

# ネットワークを指定してコンテナを起動
docker run -d --name web --network my-network nginx:latest
docker run -d --name db --network my-network postgres:16

# webコンテナからdbコンテナに接続できることを確認
docker exec web ping -c 2 db
# → PING db (172.18.0.3): 56 data bytes
# → 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.085 ms

ユーザー定義ネットワークでは、コンテナ名(この例ではdb)で自動的に名前解決が行われます。

実践例: WebアプリケーションとデータベースのNetwork構成

実際のアプリケーション構成を模した例を見てみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# アプリケーション用ネットワークを作成
docker network create app-network

# PostgreSQLコンテナを起動
docker run -d \
  --name postgres \
  --network app-network \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=myapp \
  postgres:16

# Webアプリケーションコンテナを起動
# 環境変数でDBホスト名にコンテナ名を指定
docker run -d \
  --name webapp \
  --network app-network \
  -e DATABASE_HOST=postgres \
  -e DATABASE_PORT=5432 \
  -e DATABASE_NAME=myapp \
  -e DATABASE_USER=postgres \
  -e DATABASE_PASSWORD=secret \
  -p 8080:3000 \
  my-webapp:latest

この構成では、webappコンテナはpostgresというホスト名でデータベースに接続できます。

hostネットワークドライバー

hostネットワークドライバーを使用すると、コンテナはホストのネットワークスタックを直接使用します。ネットワーク分離がなくなり、コンテナのポートがそのままホストのポートになります。

1
2
# hostネットワークでnginxを起動
docker run -d --name nginx-host --network host nginx:latest

hostネットワークの特徴

  • ネットワークのオーバーヘッドが最小限
  • ポートマッピングが不要(コンテナのポート80がそのままホストのポート80になる)
  • コンテナのネットワーク分離がなくなる

注意: hostネットワークはLinuxでのみ完全に動作します。Docker Desktop(Windows/macOS)では、LinuxVM内のネットワークがhostになるため、期待通りに動作しない場合があります。

ポートマッピングの仕組み

ポートマッピングとは

デフォルトでは、bridgeネットワーク上のコンテナのポートはDockerホストの外部からアクセスできません。外部からアクセスを許可するには、**ポートマッピング(ポート公開)**を設定する必要があります。

flowchart LR
    subgraph DockerHost["Docker Host"]
        subgraph Network["Docker Network (bridge)"]
            Container["コンテナ\nnginx (Port 80)"]
        end
    end
    Client["外部クライアント"] -->|"Port 8080"| DockerHost
    DockerHost -->|"8080:80\nホスト側:コンテナ側"| Container

ポートマッピングの指定方法

-pまたは--publishフラグを使用してポートをマッピングします。

基本的なポートマッピング

1
2
# ホストのポート8080をコンテナのポート80にマッピング
docker run -d -p 8080:80 nginx:latest

この設定により、http://localhost:8080でnginxにアクセスできます。

複数ポートのマッピング

1
2
3
4
5
# 複数のポートをマッピング
docker run -d \
  -p 8080:80 \
  -p 8443:443 \
  nginx:latest

特定のIPアドレスにバインド

1
2
# localhostのみでアクセス可能(外部からはアクセス不可)
docker run -d -p 127.0.0.1:8080:80 nginx:latest

UDPポートのマッピング

1
2
3
4
5
# UDPポートをマッピング
docker run -d -p 53:53/udp dns-server:latest

# TCPとUDP両方をマッピング
docker run -d -p 53:53/tcp -p 53:53/udp dns-server:latest

ポートマッピングの書式一覧

書式 説明
-p 8080:80 ホストの8080番ポートをコンテナの80番ポートにマッピング(TCP)
-p 192.168.1.100:8080:80 特定のホストIPアドレスにバインド
-p 8080:80/udp UDPポートをマッピング
-p 8080:80/tcp -p 8080:80/udp 同じポートでTCPとUDPの両方をマッピング

実践例: Webサーバーの公開

nginxコンテナを起動し、外部からアクセス可能にする例です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# カスタムHTMLを用意
mkdir -p ./html
echo "<h1>Hello Docker!</h1>" > ./html/index.html

# ポートマッピングとバインドマウントを組み合わせて起動
docker run -d \
  --name my-web \
  -p 8080:80 \
  --mount type=bind,source="$(pwd)"/html,target=/usr/share/nginx/html,readonly \
  nginx:latest

ブラウザでhttp://localhost:8080にアクセスすると、「Hello Docker!」と表示されます。

Docker Composeでの設定

ボリュームとネットワークは、Docker Composeでも簡潔に定義できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    networks:
      - app-network
    depends_on:
      - db

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - app-network

volumes:
  db-data:

networks:
  app-network:
    driver: bridge

この設定では、以下が自動的に行われます。

  • db-dataという名前のボリュームが作成され、PostgreSQLのデータが永続化される
  • app-networkというbridgeネットワークが作成される
  • webコンテナからdbというホスト名でPostgreSQLに接続できる
  • ホストのポート8080がWebサーバーに公開される

まとめ

本記事では、Dockerのデータ永続化とネットワーク設定について解説しました。

データ永続化のポイント

方式 推奨用途
ボリューム 本番環境でのデータベース、ファイルストレージ
バインドマウント 開発環境でのソースコード共有

ネットワーク設定のポイント

要素 推奨設定
コンテナ間通信 ユーザー定義bridgeネットワーク(名前解決が自動)
外部公開 ポートマッピング(-p ホスト:コンテナ
本番環境 ユーザー定義ネットワークで分離

これらの知識を活用することで、データを安全に永続化し、複数のコンテナを連携させたアプリケーション環境を構築できるようになります。

次のステップとして、Docker Compose入門で複数コンテナの管理を学ぶことをお勧めします。

参考リンク