SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor ・更新日 2026-08-26

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

VPSのDockerは同じengineですが、RAM不足、公開portがUFWを通過、reboot後にcontainerが停止、disk枯渇が起きます。実際のerror stringと対策を確認できます。

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

VPS 上の Docker は、ノート PC 上の Docker と同じ engine と同じ image を使用するため、すでに知っているコマンドはすべてそのまま動作します。変わるのは、Docker を取り巻く余裕です。ノート PC には余剰メモリがあり、誰もスキャンしていない firewall があり、容量を確認する必要がないほど大きなディスクがあります。レンタルサーバーには固定のメモリ上限があり、起動から数分以内にスキャンされる公開 IP アドレスがあり、Docker が確認なしに容量を消費する root filesystem があります。

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

  • メモリには上限があり、kernel はメモリ不足を解消するために process を強制終了します。
  • 公開した port は UFW(Uncomplicated Firewall)をそのまま通過します。Docker が独自の firewall rule を書き込むためです。
  • 事前に指定しない限り、reboot 後に container は再起動しません。
  • image、container、volume、build cache は、ディスクが満杯になるまで増え続けます。

以下の各セクションでは、障害の内容、実際に表示される文字列、その問題を詳しく解決する guide を示します。まだ compose file を作成していない場合は、先に VPS での Docker Compose の基本 を読み、その後ここに戻ってください。このページでは、すでに stack を起動できることを前提とします。

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 daemon は、コンテナと同じ RAM を使用します。dockerd と containerd で、そのうち約 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 daemon、負荷がかかってもサーバーの応答性を維持するための余裕に充てられます。残りが 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 またはディスクスループットに移ります。コンテナの中には、負荷ではなく設定値によって必要なメモリ量が決まるものがあります。ローカルモデルサーバーは、コンテキストウィンドウに比例した KV キャッシュを確保するため、1 件のリクエストも到着していない段階で数 GB のメモリを予算に追加することがあります。そのため、計算上スタックが収まらない場合は、設定を無理に調整するのではなく、より大きいプランを選びます。VPS に実際にかかる費用では、追加の GB に月額いくらの価値があるかを説明しています。Ollama の num_ctx を増やす方法も参照してください。

計算を正確に保つには、2 つのルールがあります。まず、すべてのサービスにメモリ制限を設定します。これにより、1 つの暴走したプロセスがサーバー全体のメモリを使い切ることを防げます。次に、予算の上限まで使い切らず、余裕を残します。docker compose build と pg_dump は、負荷が最も高いタイミングでメモリを必要とするためです。Docker Compose のメモリ制限で、構文と注意点を確認できます。

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

kernel がコンテナを強制終了したためです。137 は 128 に 9 を加えた値で、シグナル 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 制限に達したことを示し、kernel のログには選択されたプロセスが記録されます。

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

これは、影響が 1 つのコンテナ内に収まるため、望ましい状態です。問題なのは、制限のないコンテナです。制限がない場合、その上限はマシン全体になります。そのため、1 つのサービスのメモリリークによって host のメモリが枯渇し、kernel はシステム全体からサイズを基準に強制終了する対象を選びます。ログ行から Memory cgroup プレフィックスがなくなり、Out of memory: Killed process 2417 (postgres) と表示されます。選ばれるプロセスは database であることが多く、メモリリークを起こしたコンテナは動作し続けます。すべてのサービスに制限を設定することが、個々の制限値を正確に決めることより重要なのはこのためです。

Swap はタイミングを変えるだけで、計算方法は変えません。多くの VPS イメージには Swap がありません。swapon --show で確認できます。Swap がない場合、このコマンドは何も出力しません。Swap file があると、kernel は使用頻度の低いページを退避させる場所を確保できるため、問題に気付くまでの時間を数分延ばせます。

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 行の合計値が 0 以外になっていることを確認します。Swap は RAM を増やしません。メモリ不足が常態化したマシンは、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 は引き続き機能します。正常な小規模スタックでは、reverse proxy だけが 80 と 443 でポートを公開します。ポートを公開しつつフィルタリングする必要がある場合の DOCKER-USER チェーンについては、Docker の公開ポートが UFW を迂回する理由 を参照してください。ホスト側のルールについては、UFW ファイアウォールの基本 を参照してください。

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

コンテナを再起動する設定がないためです。コンテナは、restart policy を指定しない場合、no で作成されます。そのため、再起動すると停止したままになり、daemon も対応しません。VPS では再起動は珍しくありません。unattended upgrades による kernel 更新、プロバイダーのメンテナンス、前述の OOM シーケンスなどが再起動の原因になります。

2 つの条件を満たす必要があります。まず、daemon がブート時に起動することです。

systemctl is-enabled docker

標準的な Ubuntu インストールでは、enabled と表示されます。次に、各サービスに policy を設定します。

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

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

docker inspect my-app | grep -A3 RestartPolicy

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

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 mounts と named volumes の違いを確認し、先にバックアップを取得してください。

コンテナログは、気付きにくい形で増加します。デフォルトの 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 df と df -h / を実行します。2 つのコマンドを 30 秒実行するだけで、障害になるかなり前から傾向を把握できます。
  • 確実に小さいと思うサービスも含め、すべてのサービスにメモリ制限を設定します。制限により、ホスト全体の障害をコンテナ 1 つの再起動に抑えられます。
  • 別の場所からホストを監視し、カーネルが対応する前にメモリやディスクの逼迫を把握します。Uptime Kuma はコンテナで実行でき、アイドル時のメモリ使用量は約 95 MB です。
  • コンテナではなくボリュームをバックアップします。コンテナは破棄できますが、ボリュームはそうではありません。VPS の restic バックアップ で、スケジュール設定とリストアテストに対応できます。
  • compose ファイルではイメージタグを固定し、決めた日に更新します。latest を使用すると、次の docker compose pull から取得するバージョンは、その朝にリリースされたものになります。

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

FAQ

Docker を VPS で実行するには、どのくらいの RAM が必要ですか?

Docker 自体のメモリ使用量は少なく、daemon と containerd を合わせても約 100 MB です。必要な容量の大部分はコンテナが使用します。まずホストのための容量を確保します。768 MB の OS、daemon、余裕を 2048 MB の環境に割り当てると、コンテナには 1280 MB を使用できます。512 MB のデータベース、128 MB のリバースプロキシ、小規模なアプリケーション 2 つであれば収まります。公開されている数値をそのまま信頼せず、docker stats --no-stream で実際の構成を測定してください。

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

はい。ただし、軽量なコンテナを 1 つまたは 2 つ実行する場合に限り、開始前に swap ファイルを追加してください。OS と Docker daemon が起動すると、1 GB の環境ではおおよそ半分が使用されます。小規模なアプリケーションとリバースプロキシを動かす余地はありますが、実負荷のデータベースには足りません。この容量の環境でイメージをビルドすると、失敗するか、別のサービスが強制終了する可能性があります。そのため、別の環境でビルドして完成したイメージを 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 docker が enabled を出力することも確認します。その後、意図的に再起動して docker compose ps を確認してください。一度もテストしていない restart policy は、実質的に restart policy ではありません。

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

小規模なサーバーの多くでは、月 1 回で十分です。または、docker system df が、放置すると困るほどの reclaimable space を報告したときに実行してください。サービスの稼働中でも docker image prune -a と docker builder prune は安全です。使用中のイメージと cache は対象外になるためです。参照されていない volume を正確に把握している場合を除き、docker system prune --volumes は避けてください。停止中の stack にあるデータまで削除される可能性があります。