SSD Nodes Learn 🎉 VPS $4.99/月〜
ガイド Matt Connor著者 Matt Connor ・更新日 2026-08-05

VPSでDockerを使うと何が変わる?4つの注意点

VPSのDockerは同じエンジンでも余裕がありません。RAM不足、公開ポートがUFWを通る問題、再起動後に停止するコンテナ、ディスク枯渇の対策を解説します。

VPS で Docker を実行すると何が変わるか

VPS 上の Docker は、ノート PC 上の Docker と同じエンジンと同じイメージを実行するため、すでに知っているコマンドはすべてそのまま使えます。変わるのは、Docker を取り巻く余裕です。ノート PC には余分なメモリがあり、誰もスキャンしていないファイアウォールがあり、容量が十分に大きいためディスクを確認することもありません。レンタルサーバーには固定されたメモリ上限があり、起動して数分以内にスキャンされるパブリック IP アドレスがあり、Docker が何の確認もなく使い切る root ファイルシステムがあります。

小規模なサーバーで問題の大半を引き起こす違いは、次の 4 つです。

  • メモリには限りがあり、不足するとカーネルはプロセスを強制終了して解消します。
  • 公開したポートは UFW (uncomplicated firewall) をそのまま通過します。Docker が独自のファイアウォールルールを書き込むためです。
  • 事前に指定しない限り、再起動後にコンテナは自動的に戻りません。
  • イメージ、コンテナ、ボリューム、ビルドキャッシュは、ディスクが満杯になるまで増え続けます。

以下の各セクションでは、障害の内容、実際に表示される文字列、および詳しい対処方法を説明するガイドを示します。まだ compose ファイルを作成していない場合は、先に VPS での Docker Compose の基礎 を読んでから戻ってきてください。このページでは、すでにスタックを起動できることを前提とします。

Docker コンテナはどれだけの RAM を使用しますか?

多くの人が予想するより少ない量です。コンテナは仮想マシンではなく、cgroup(control group)内のプロセスです。そのため、ゲストカーネルはなく、固定された割り当てもありません。必要なメモリは、内部のプロセスが実際に使用する量です。同じスタックを仮想マシンで構築した場合は収まらなくても、コンテナなら 2 GB に収まるのはこのためです。

以下の数値は、デフォルト設定の Ubuntu 24.04 で、標準イメージを起動してから数分後に docker stats で確認した、一般的なアイドル時の値です。これは計画の出発点であり、実際のワークロードのベンチマークではありません。以下の数値を含め、どの数値もそのまま信頼する前に、自分のホストで docker stats --no-stream を実行してください。

ChartTypical idle container memory, stock images, megabytes
The data behind this chart
[
  {
    "label": "nginx",
    "idle_mb": 8,
    "budget_mb": 64
  },
  {
    "label": "Redis 7",
    "idle_mb": 12,
    "budget_mb": 128
  },
  {
    "label": "Traefik v3",
    "idle_mb": 40,
    "budget_mb": 128
  },
  {
    "label": "PostgreSQL 16",
    "idle_mb": 45,
    "budget_mb": 512
  },
  {
    "label": "Uptime Kuma",
    "idle_mb": 95,
    "budget_mb": 256
  },
  {
    "label": "MariaDB 11",
    "idle_mb": 190,
    "budget_mb": 512
  },
  {
    "label": "Nextcloud (Apache)",
    "idle_mb": 210,
    "budget_mb": 768
  }
]

2 つの列は異なる目的で使用します。idle_mb は、何も処理していないときにコンテナが使用する量です。budget_mb は、計画時に確保する量です。実際の使用時はアイドル状態ではないためです。PostgreSQL はアイドル時には 45 MB 前後ですが、接続、ソート、キャッシュが使用されると 512 MB を必要とします。計画には予算の列を使用してください。デバッグにはアイドルの列を使用してください。

7 行の傾向にも注目してください。nginx はアイドル時に 8 MB、Nextcloud は 210 MB です。アプリケーションの前段に置くプロキシの使用量は、ほぼ無視できます。サーバーのサイズを決める主な要因は、データベースと PHP アプリケーションです。

docker stats について、1 点注意してください。このメモリ値には、コンテナ自身が読み込んだファイルによるページキャッシュが含まれます。そのため、起動後しばらくは増加し、その後に落ち着きます。メモリリークを疑う前に、1 時間監視してください。

VPS のサイズ選定: 2 GB、4 GB、8 GB で収まる構成

まず、ホスト自身が使用する分を差し引きます。カーネル、systemd、journald、sshd、Docker デーモンは、コンテナと同じ RAM を使用します。dockerdcontainerd だけで約 100 MB を占有します。ページキャッシュ用の空きメモリも必要です。イメージのビルドやデータベースダンプを実行したときの急増分も確保してください。

ChartRAM budget by plan size, megabytes
The data behind this chart
[
  {
    "plan": "2 GB VPS",
    "total_mb": 2048,
    "host_reserve_mb": 768,
    "container_mb": 1280
  },
  {
    "plan": "4 GB VPS",
    "total_mb": 4096,
    "host_reserve_mb": 1024,
    "container_mb": 3072
  },
  {
    "plan": "8 GB VPS",
    "total_mb": 8192,
    "host_reserve_mb": 1536,
    "container_mb": 6656
  }
]

host_reserve_mb は、オペレーティングシステム、Docker デーモン、負荷時にもサーバーの応答性を維持するための余裕を含みます。残りが container_mb で、実際に使用できるのはこの値だけです。最小プランでは 768 MB、最大プランでは 1536 MB となるように、予備領域はプランに応じて増えます。大きいサーバーでは、より多くのコンテナを実行し、より多くのログを書き込み、より多くのページキャッシュを必要とするためです。

2 GB プランでは、コンテナ用に 1280 MB が残ります。そのうち 512 MB を PostgreSQL に、128 MB を Traefik に割り当てると、すでに半分がなくなります。残りで、各約 256 MB の小規模なアプリケーションを 2 つ実行できます。これは実用的なサーバー構成です。ただし、Nextcloud と検索クラスタまで追加できる余裕はありません。

4 GB プランでは 3072 MB が残ります。これなら、データベース、リバースプロキシ、3 つのアプリケーション、監視用コンテナを同時に収められます。重要な用途で使う場合に選ぶ価値がある最小サイズです。余ったメモリが、問題のあるデプロイによる一時的な増加を吸収するためです。

8 GB プランでは、8192 MB のうち 6656 MB が残ります。この規模では、通常はメモリではなく CPU またはディスクスループットが制限要因になります。計算上スタックが収まらない場合は、設定を無理に調整するのではなく、大きいプランを購入してください。VPS に実際にかかる費用では、追加のギガバイトに月額いくらの価値があるかを説明しています。

計算を正しく保つには、2 つのルールがあります。まず、すべてのサービスにメモリ制限を設定し、暴走したプロセスがサーバー全体を枯渇させないようにします。次に、予算の上限まで使い切らないでください。docker compose buildpg_dump は、最も厳しいタイミングでメモリを必要とするためです。Docker Compose のメモリ制限では、構文と注意点を説明しています。

コンテナが終了コード 137 で終了するのはなぜですか?

kernel に強制終了されたためです。137 は 128 に 9 を加えた値で、signal 9 は SIGKILL です。コンテナが許可されたメモリ量を超えて要求したため、out of memory (OOM) killer がコンテナを終了しました。

CONTAINER ID   IMAGE         STATUS
9f2c1a4d7b3e   postgres:16   Exited (137) 4 minutes ago

推測せずに原因を確認します。

docker inspect my-db | grep -i oomkilled
sudo journalctl -k | grep -i "out of memory"

"OOMKilled": true は、コンテナが自身の cgroup limit に達したことを示します。また、kernel log には選択された process が記録されます。

Memory cgroup out of memory: Killed process 2417 (postgres) total-vm:1284416kB

これは、被害が 1 つのコンテナ内に収まるため、望ましい状態です。問題なのは、limit がまったく設定されていないコンテナです。limit がない場合、その上限はマシン全体になります。そのため、1 つの service で発生した memory leak が host のリソースを枯渇させ、kernel はシステム全体からサイズを基準に終了対象を選びます。log 行から Memory cgroup prefix がなくなり、Out of memory: Killed process 2417 (postgres) になります。選ばれる process は database であることが多い一方、memory leak を起こしたコンテナは動作し続けます。したがって、個々の limit の正確な値よりも、すべての service に limit を設定することが重要です。

Swap はタイミングを変えるだけで、計算方法は変えません。ほとんどの VPS image には swap がありません。swapon --show で確認できます。swap がない場合、この command は何も出力しません。swap file があると、kernel は使用頻度の低い page を置く場所を確保できます。そのため、問題に気付くまでの時間を数分延ばせます。

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -h

free -h で、Swap row の total が 0 以外になっていることを確認できます。Swap は RAM を増やしません。常に memory pressure がかかっているマシンは、SSH で接続して修正できないほど遅くなることがあります。そのため、swap は警告用のバッファーとして扱い、サイズ設計を見直してください。

UFW が公開された Docker ポートをブロックしないのはなぜですか?

UFW が監視するチェーンに、トラフィックが到達しないためです。-p 5432:5432 または compose の ports: エントリでポートを公開すると、デーモンは nat テーブルに DNAT(宛先ネットワークアドレス変換)ルールを書き込み、独自の DOCKER チェーンに accept ルールを書き込みます。コンテナ宛てのパケットはホストに配信されず、コンテナへ転送されます。そのため FORWARD パスで処理され、UFW が書き込む INPUT ルールを通過しません。

サーバー上で、この動作を確認できます。

sudo ufw status | grep 5432
sudo iptables -t nat -L DOCKER -n | grep 5432

UFW が 5432 DENY IN Anywhere を出力していても、nat テーブルには同じポート用の DNAT tcp ... to:172.18.0.2:5432 ルールが存在する場合があります。別のマシンからは、nc -vz your.server.ip 5432 で接続できます。データベースはインターネットに公開されていますが、ファイアウォールは公開されていないと示しています。

対処方法は、公開するポートを減らすことです。同じ compose プロジェクト内のコンテナはネットワークを共有し、サービス名で相互に接続できます。そのため、同じプロジェクト内のアプリケーションだけにサービスを提供するデータベースには、ports: エントリは必要ありません。ローカルからのアクセスが必要な場合は、公開先を loopback にバインドします。

services:
  db:
    image: postgres:16
    ports:
      - "127.0.0.1:5432:5432"

docker compose up -d の後は、外部からの nc -vz your.server.ip 5432 が失敗し、ホスト上の psql -h 127.0.0.1 -p 5432 は引き続き動作します。正常な小規模スタックでは、リバースプロキシだけが 80 と 443 でポートを公開します。ポートを公開したままフィルタリングする必要がある場合は、Docker の公開ポートが UFW を迂回する理由で DOCKER-USER チェーンを確認してください。ホスト側の基本的なルールについては、UFW ファイアウォールの基本を参照してください。

再起動後にコンテナが消えるのはなぜですか?

コンテナを再起動する設定がないためです。コンテナは、再起動ポリシーを指定しない限り no で作成されます。そのため、再起動後も停止したままになり、デーモンも再起動させません。VPS では再起動は珍しくありません。unattended upgrades によるカーネル更新、プロバイダーのメンテナンス、前述の OOM シーケンスなどが再起動の原因になります。

次の 2 つを満たす必要があります。まず、デーモンがブート時に起動することです。

systemctl is-enabled docker

標準的な Ubuntu インストールでは、これにより enabled が表示されます。次に、各サービスに再起動ポリシーを設定します。

services:
  app:
    image: ghcr.io/example/app:1.4
    restart: unless-stopped

unless-stopped は再起動後にコンテナを起動し直し、意図的に停止したコンテナはそのままにします。always は、デーモンが再起動するたびに、意図的に停止したコンテナも再起動します。デバッグ中にこの動作をすると、予期しない結果になります。ファイルを編集するだけでは不十分です。再起動ポリシーはコンテナの作成時に設定されるためです。docker compose up -d を実行してコンテナを再作成し、その後、実際の値を確認します。

docker inspect my-app | grep -A3 RestartPolicy

その後、意図的にサーバーを再起動し、プロジェクトディレクトリで docker compose ps を実行します。計画的な再起動後も動作するスタックであれば、予期しない再起動後も動作します。起動順序の保証や、ブート時に 1 回だけ実行するジョブが必要な場合は、systemd unit のほうが適しています。ブート時に Docker Compose を起動するに unit ファイルがあります。再起動したコンテナが実際にサービスを提供しているか確認するには、Compose のヘルスチェックを追加します。

VPS のディスクが満杯になるのはなぜですか?

Docker は、削除を指示するまでデータを保持し続けるためです。これまでに pull したすべてのイメージタグ、停止したすべてのコンテナ、再作成時に残った匿名ボリューム、ビルドキャッシュのすべてのレイヤーがディスクに残ります。プランのサイズとして一般的な 40 GB または 80 GB の root ファイルシステムでは、数年ではなく数か月で障害につながります。

ディスクが満杯になっても、クラッシュのようには見えません。同じ 1 時間のうちに、コンテナ、apt、journald、docker pull から no space left on device が発生します。PostgreSQL は書き込みを受け付けなくなります。サーバー自体は稼働しているため、再起動ループよりも気付きにくい状態です。

削除する前に確認します。

docker system df
df -h /

docker system df は合計をイメージ、コンテナ、ローカルボリューム、ビルドキャッシュに分け、それぞれの横に RECLAIMABLE 列を表示します。独自にイメージをビルドするサーバーでは、通常、ビルドキャッシュが最大の項目です。

docker image prune -a
docker builder prune
docker system df

docker image prune -a は、どのコンテナからも使用されていないイメージをすべて削除します。docker builder prune はビルドキャッシュを削除します。使用中のデータはスキップされるため、どちらもサービスの稼働中に実行して安全です。一方、docker system prune --volumes は安全ではありません。これは、現在どのコンテナからも参照されていないボリュームをすべて削除します。週末の間だけ停止したスタックはまさにこの状態になり、そのデータベースボリュームも削除されます。そのフラグを入力する前に、bind mount と named volume の違いを確認し、先にバックアップを取得してください。

コンテナログは、気付きにくいまま増加します。デフォルトの json-file ドライバーにはサイズ制限がないため、ログを頻繁に出力するコンテナが /var/lib/docker/containers にギガバイト単位のデータを書き込みます。/etc/docker/daemon.json のすべてのコンテナに上限を設定します。

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

sudo systemctl restart docker で適用します。この操作でコンテナが再起動するため、実行するタイミングを選んでください。上限が適用されるのは変更後に作成したコンテナです。そのため、稼働中のコンテナを docker compose up -d --force-recreate で再作成し、次のように確認します。

docker inspect my-app | grep -A5 LogConfig
sudo du -sh /var/lib/docker/containers

inspect の出力に max-size が設定されていることを確認します。空の場合、そのコンテナは変更前に作成されており、現在も制限なしで書き込みを続けています。

小規模な Docker ホストを健全に保つ習慣

ダッシュボードや、習得が必要なツールはありません。

  • 月初に docker system dfdf -h / を実行します。2 つのコマンドで 30 秒あれば、障害になるずっと前から傾向を確認できます。
  • 小さいと確信しているサービスも含め、すべてのサービスにメモリ制限を設定します。制限により、ホスト全体の障害を、1 つのコンテナの再起動で済む障害に抑えられます。
  • 別の場所からホストを監視し、カーネルが対処する前にメモリやディスクの逼迫を把握できるようにします。Uptime Kuma はコンテナで実行でき、アイドル時のメモリ使用量は約 95 MB です。
  • バックアップする対象はコンテナではなくボリュームにします。コンテナは使い捨てですが、ボリュームは失えません。VPS での restic バックアップ では、スケジュール設定とリストアテストを扱います。
  • compose ファイルではイメージタグを固定し、更新する日を決めます。latest を使用すると、次の docker compose pull で取得するバージョンは、その朝にリリースされたものになります。

Docker を実行する小規模な VPS は、4 つの数値を適正範囲に保てば、何年も健全に運用できます。メモリの予算、公開ポートの一覧、各サービスの再起動ポリシー、空きディスク容量です。それ以外は、自宅ですでに実行している Docker と同じです。

FAQ

VPS で Docker を実行するには、どの程度の RAM が必要ですか?

Docker 自体の消費量は少ないです。daemon と containerd を合わせても約 100 MB で、残りの必要量はコンテナによって決まります。まずホスト用の容量を確保します。768 MB の 2048 MB 環境であれば、オペレーティングシステム、daemon、余裕分に割り当て、1280 MB がコンテナ用に残ります。512 MB のデータベース、128 MB のリバースプロキシ、小規模なアプリケーション 2 つであれば、この範囲に収まります。公開されている数値をそのまま信頼せず、docker stats --no-stream で実際のスタックを計測してください。

1 GB の VPS で Docker を実行できますか?

はい。軽量なコンテナを 1 つまたは 2 つ実行する用途であれば可能です。開始前に swap ファイルを追加してください。1 GB の環境では、オペレーティングシステムと Docker daemon の起動後に、おおむね半分が消費されます。小規模なアプリケーションとリバースプロキシを実行する余地はありますが、実際の負荷がかかるデータベースには不足します。この容量の環境でイメージをビルドすると、処理が失敗するか、別のプロセスが強制終了されます。そのため、別の環境でビルドして完成したイメージを pull してください。

UFW は Docker コンテナを保護しますか?

公開したポートには適用されません。Docker は独自の DNAT ルールと forward ルールを書き込むため、公開されたコンテナポート宛てのパケットはホストに渡されず、コンテナへ転送されます。そのため、UFW が管理する INPUT ルールには到達しません。ufw deny 5432 が有効でも、そのポートはインターネットから応答できます。127.0.0.1:5432:5432 で loopback に公開し、内部サービスは公開しないか、DOCKER-USER chain でフィルタリングしてください。

VPS の再起動後、コンテナは再起動しますか?

restart policy を指定して作成した場合に限り、再起動します。各サービスに restart: unless-stopped を設定し、docker compose up -d を実行してコンテナをその設定で再作成します。systemctl is-enabled dockerenabled を出力することを確認してください。その後、意図的に再起動して docker compose ps を確認します。一度もテストしていない restart policy は、実質的に restart policy ではありません。

Docker イメージはどの程度の頻度で prune すべきですか?

多くの小規模サーバーでは月 1 回で十分です。または、docker system df が回収可能な容量を報告し、それが必要になった時点で実行してください。サービスの実行中でも docker image prune -adocker builder prune は安全です。使用中のイメージとキャッシュはスキップされるためです。参照されていない volume を正確に把握していない限り、docker system prune --volumes は避けてください。停止中のスタックに対応するデータも削除されるためです。