Python | DevOps・運用:Docker volume

Python Python
スポンサーリンク

Docker volumeって何?一言でいうと「コンテナが消えても残る“外付けハードディスク”」

Docker volume は、コンテナの外側にある「永続ストレージ」です。
コンテナの中のファイルは、コンテナを消すと一緒に消えますが、volume に置いたデータはコンテナを消しても残ります。

Python アプリだと、特にこういうものを volume に置きたくなります。
データベースのデータ、ログファイル、アップロードされたファイルなど、「コンテナを作り直しても消えたら困るもの」です。

「コンテナは使い捨て、データは volume に残す」
この考え方が Docker volume の出発点です。


コンテナの中のデータはなぜ消えるのか

コンテナのファイルシステムは「一時的なレイヤー」

Docker コンテナは、イメージの上に「書き込み可能なレイヤー」が1枚乗っているイメージです。
コンテナの中でファイルを作ったり書き換えたりすると、その変更はこのレイヤーに乗ります。

コンテナを削除すると、このレイヤーごと消えます。
つまり、コンテナ内の /var/lib/postgresql/data に DB のデータを置いていたら、コンテナを消した瞬間に全部消えます。

開発中に docker rm -f したらデータが全部飛ぶ、というのはこの仕組みのせいです。
そこで、「データだけはコンテナの外に逃がそう」という発想が出てきます。それが volume です。


Docker volume の基本パターンを具体例で見る

例1:PostgreSQL のデータを volume に置く

一番分かりやすいのが DB です。
docker-compose で PostgreSQL を立てるとき、よくこう書きます。

services:
  db:
    image: postgres:16
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypass
      - POSTGRES_DB=mydb
    volumes:
      - db-data:/var/lib/postgresql/data

volumes:
  db-data:
YAML

ここで重要なのは2か所です。

volumes: - db-data:/var/lib/postgresql/data
コンテナ内の /var/lib/postgresql/data を、db-data という名前の volume にマウントしている。

一番下の volumes: db-data:
db-data という名前の volume を定義している。

これで、PostgreSQL が書き込むデータは、コンテナの外側(volume)に保存されます。
コンテナを消しても、db-data volume は残るので、コンテナを作り直してもデータはそのままです。

例2:FastAPI アプリのログを volume に出す

例えば、アプリが /var/log/app にログを書き出す設計だとします。
そのログをホスト側に残したい場合、こう書けます。

services:
  web:
    build: .
    volumes:
      - app-logs:/var/log/app

volumes:
  app-logs:
YAML

これで、コンテナ内の /var/log/app に書かれたログは、app-logs volume に保存されます。
コンテナを入れ替えても、ログは volume に残り続けます。

ただし、Docker では「ログは標準出力に出す」方が一般的なので、ログ用 volume は必須ではありません。
DB データのような「絶対消したくないもの」に volume を使うのが基本です。


volume と bind mount の違いをちゃんと理解する

volume は「Docker が管理するストレージ」

db-data:/var/lib/postgresql/data のように書く volume は、Docker が管理するストレージです。
ホスト側のどこにあるかは、docker volume inspect すれば分かりますが、普段は意識しません。

特徴としては、次のようなイメージです。
パスを気にしなくていい、複数のコンテナから共有しやすい、バックアップや移行もしやすい(volume 単位で扱える)。

bind mount は「ホストのディレクトリをそのまま見せる」

一方で、こういう書き方もあります。

services:
  web:
    volumes:
      - .:/app
YAML

これは「ホストのカレントディレクトリを、コンテナの /app にマウントする」という意味です。
これは volume ではなく bind mount です。

開発中にコードをマウントして --reload でホットリロードする、というのは bind mount の典型的な使い方です。
「ホストのファイルをそのままコンテナに見せたいとき」は bind mount、「コンテナ用のデータ置き場が欲しいとき」は volume、という使い分けが基本です。


DevOps 的に重要なポイント:volume は「状態」と「コンテナ」を分離するための道具

コンテナは使い捨て、状態は volume に残す

DevOps・運用の観点で一番大事なのは、「コンテナと状態を分ける」ことです。

コンテナは壊れてもいい、作り直せばいい。
でも、DB のデータやユーザーがアップロードしたファイルは消えたら困る。

この「壊れてもいいもの」と「壊れたら困るもの」を分ける境界線が、volume です。

例えば、本番運用でこういうことをします。

新しいバージョンのアプリコンテナを立ち上げる
古いコンテナを止めて消す
でも DB volume はそのまま使い回す

これができると、「アプリのバージョンアップ」と「データの保持」がきれいに分離できます。

CI/CD と組み合わせたときのイメージ

CD 自動デプロイで、docker compose pull && docker compose up -d のようにコンテナを入れ替えるとき、
volume を使っていれば、DB のデータはそのままです。

逆に、volume を使わずコンテナ内にデータを置いていると、
デプロイのたびにデータが初期化される、という地獄になります。

「コンテナは何度でも捨てられるが、volume は捨てない」
この前提で設計すると、運用が一気に楽になります。


volume を扱うときに気をつけたいポイント

「どのデータを volume にするか」を意識して決める

何でもかんでも volume にすればいいわけではありません。
volume に向いているのは、「アプリのライフサイクルを超えて残したいデータ」です。

DB のデータ、ユーザーアップロード、長期保存したいログなどが典型です。
逆に、「コンテナごと消えてもいい一時ファイル」は volume にしなくて構いません。

「このディレクトリの中身が消えたら、本番でどれくらい困るか?」
これを基準に、「volume にするかどうか」を決めると良いです。

volume の中身も「バックアップ対象」として考える

volume はコンテナよりは長生きですが、サーバーが壊れたら一緒に消えます。
本番運用では、volume の中身(特に DB データ)は、別途バックアップ戦略が必要です。

PostgreSQL なら定期的なダンプ、ストレージスナップショット、レプリケーションなど、
インフラ側の話も絡んできますが、「volume に置いたから安心」ではない、というのは覚えておいてほしいポイントです。


初心者向けの現実的なステップ

ステップ1:PostgreSQL を volume 付きで立ててみる

docker-compose で db-data:/var/lib/postgresql/data を付けて、
コンテナを消してもデータが残ることを実際に確認してみる。

コンテナを立てる → テーブルを作る → コンテナを消す → もう一度立てる → テーブルが残っている、という体験をすると、volume の価値が一気に腹落ちします。

ステップ2:bind mount と volume の違いを意識して使い分ける

開発中のコードは bind mount(ホストのファイルをそのまま見せる)。
DB データは volume(コンテナとは独立したストレージ)。

この2つを意識して書き分けるだけで、docker-compose の設計がかなりきれいになります。


まとめ(Docker volume は「コンテナを捨てても生き残るデータ置き場」)

初心者目線で整理すると、Docker volume はこういうものです。

コンテナの外側にある永続ストレージで、DB のデータや消えたら困るファイルを置く場所。
docker-compose では volumes: 名前:/パス でコンテナ内のディレクトリにマウントし、コンテナを入れ替えても volume の中身は残るので、「コンテナは使い捨て、データは残す」という DevOps 的な運用がやりやすくなる。

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