動作確認済み環境
本記事のコマンドは ubuntu:24.04(Docker公式イメージ / Ubuntu 24.04.4 LTS Noble Numbat)+ Docker 20.10.12(Server / Storage Driver: overlay2 / Cgroup Version: 2)で実際に実行・確認しています。計測日は2026年6月15日です。バージョンが異なるとオプション名や出力が変わる場合があります。
「Dockerは動いているんだけど、本番で使うのは正直ちょっと怖い」と感じていませんか?実は Docker には、設定一つでセキュリティを劇的に改善できるオプションが最初から揃っています。しかも、ほとんどがコマンドにフラグを1つ足すだけで効きます。
この記事では、2026年時点で Ubuntu 24.04 + Docker に使えるベストプラクティスを、実際にコマンドを動かして取得した出力とともに解説します。「なんとなく動く」状態から「本番でも安心して使える」状態にステップアップしたい方向けです。
この記事のポイント
--user 1000:1000+--cap-drop=ALLでコンテナの権限を最小化できる(CapPrm が00000000a80425fb→0000000000000000になることを実測確認)- ベースイメージを alpine に変えるだけで
ubuntu:24.04(101MB)の約1/13(7.73MB)に軽量化できる(実測) --memory=512m --cpus=1でリソース上限を設定し、ホストを守れる(cgroup v2 で動作確認済み)--tmpfs /tmp:rw,noexec,nosuidで一時領域へのスクリプト実行・SUID を禁止できる- 全ポイントをまとめたチェックリストを記事末に掲載しています
目次
- 動作確認済み環境
- セキュリティ強化 — 非rootユーザー・ケーパビリティ・read-only
- イメージ最適化 — マルチステージビルドと alpine
- リソース制限 — メモリ・CPU・tmpfs
- Docker Compose ベストプラクティス
- 定期メンテナンス — docker system prune と更新
- まとめチェックリスト
動作確認済み環境
まず、本記事で使った環境を docker version と docker info で確認しておきます。Docker は「コンテナ」という隔離された箱の中でアプリを動かす仕組みで、docker info はその土台になっているストレージ方式やリソース管理の仕組み(cgroup)を教えてくれます。

重要な確認ポイントを整理します。
| 項目 | 今回の実測値 | 確認コマンド |
|---|---|---|
| Docker バージョン | 20.10.12(Server) | docker version |
| ストレージドライバー | overlay2(推奨) | docker info --format '{{.Driver}}' |
| cgroup バージョン | v2(cgroupsv2) | docker info --format '{{.CgroupVersion}}' |
| Ubuntu バージョン | 24.04.4 LTS (noble) | lsb_release -a(コンテナ内) |
| Ubuntu 24.04 の docker.io | 29.1.3-0ubuntu3~24.04.2 | apt-cache show docker.io |
実際にコンテナ内で cat /etc/os-release を叩くと VERSION="24.04.4 LTS (Noble Numbat)" が返ってきました。また apt-cache show docker.io では、Ubuntu 24.04 のリポジトリで配布されている docker.io が 29.1.3-0ubuntu3~24.04.2、containerd が 2.2.1-0ubuntu1~24.04.2 であることを確認できました(2026年6月15日時点)。
cgroup v2 が有効かどうかを確認する方法
docker info | grep -i cgroupでCgroup Version: 2と出れば cgroup v2 です- cgroup(コントロールグループ)は、プロセスが使えるCPU・メモリ・I/Oを制限するLinuxカーネルの機能です
- Ubuntu 22.04 以降はデフォルトで cgroup v2 が有効になっています
- cgroup v2 ではメモリ・CPU・I/O のリソース制限がより精密に機能します
セキュリティ強化 — 非rootユーザー・ケーパビリティ・read-only
Docker のセキュリティで最も効果的な対策は、「コンテナ内で root として動かさない」ことです。デフォルトでは、コンテナ内のプロセスは root(uid=0)として実行されます。これは、万が一コンテナの外(ホスト)に攻撃者が抜け出す「コンテナエスケープ」が起きたときに、被害を大きくする原因になります。
Docker 公式ドキュメントも、セキュリティを「カーネルの名前空間」「Dockerデーモンの攻撃面」「コンテナ設定(ケーパビリティ等)」「カーネルのハードニング機能」の4つの観点で整理しています。本記事はこのうち、個人でもすぐ手を打てる部分を実際のコマンドで押さえていきます。

①非rootユーザーでコンテナを実行する(–user フラグ)
最も手軽な対策は --user フラグです。
ubuntu
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu)
--user 1000:1000(uid:gid の指定)を付けるだけで、コンテナ内プロセスが root ではなく uid=1000(ubuntu) で動くことが実際に確認できました。Dockerfile に USER 命令を書いておくと、毎回 --user を指定しなくて済みます。
RUN groupadd –gid 1001 appuser && \
useradd –uid 1001 –gid appuser –no-create-home appuser
USER appuser
②Linux ケーパビリティを最小化する(–cap-drop=ALL)
Docker はデフォルトでコンテナに 約40種類の Linux ケーパビリティを付与します。ケーパビリティとは、root権限を細かく分割した「個別の特権」のことです。NET_RAW(rawソケット)や CHOWN(ファイル所有者の変更)など、アプリが必要としないものも多く含まれています。

実測では、デフォルトの CapPrm: 00000000a80425fb(多くのケーパビリティが有効)が、--cap-drop=ALL を付けると CapPrm: 0000000000000000(全ゼロ=ケーパビリティなし)になることを確認できました。CapPrm はそのプロセスが持つ許可済みケーパビリティをビット列で表したもので、ゼロは「特権を一切持たない」状態です。
$ docker run –rm ubuntu:24.04 bash -c ‘cat /proc/self/status | grep CapPrm’
CapPrm: 00000000a80425fb
# 全ケーパビリティを剥奪し、必要なものだけ追加する
$ docker run –rm \
–cap-drop=ALL \
–cap-add=NET_BIND_SERVICE \
ubuntu:24.04 bash -c ‘cat /proc/self/status | grep CapPrm’
CapPrm: 0000000000000400
# NET_BIND_SERVICE(ポート1024以下のバインド)だけ許可した状態
このように、--cap-drop=ALL でいったん全部剥がし、必要なものだけ --cap-add で足すのが本番コンテナの基本形です。Webサーバーで80番ポートを使いたいなら NET_BIND_SERVICE だけ追加すれば十分、というケースが多いです。
③ルートファイルシステムを読み取り専用にする(–read-only)
--read-only フラグを付けると、コンテナのルートファイルシステムへの書き込みが禁止されます。攻撃者がコンテナに侵入しても、マルウェアの設置や設定ファイルの改ざんができなくなります。
–tmpfs /tmp:rw,noexec,nosuid,size=64m \
ubuntu:24.04 bash -c ‘echo test > /tmp/ok && echo “tmpfs書き込みOK”‘
tmpfs書き込みOK
$ docker run –rm –read-only \
ubuntu:24.04 bash -c ‘echo test > /etc/hosts_test 2>&1’
bash: /etc/hosts_test: Read-only file system
# ルートFSは読み取り専用。/tmp のみ tmpfs で書き込み可能にしている
イメージ最適化 — マルチステージビルドと alpine
コンテナイメージは小さいほど良いです。理由は単純で、ダウンロード(プル)時間の短縮・攻撃面積の縮小・ストレージコストの削減の3点です。
①ベースイメージのサイズを比較する

実際に docker images で確認した結果です。ubuntu:24.04 が 101MB、ubuntu:22.04 が 69.6MB、alpine:3.19 が 7.73MBと、ubuntu:24.04 と alpine では約13倍の差があります。本番環境では Alpine(musl libc ベースの超軽量Linux)を検討するだけで、イメージの転送・プルの時間が大幅に短縮されます。
ubuntu:24.04 101MB
ubuntu:22.04 69.6MB
alpine:3.19 7.73MB
# alpine は ubuntu:24.04 の約1/13サイズ
②マルチステージビルドで本番イメージを軽量化する
Go や Rust のようにコンパイルが必要な言語では、ビルド環境と実行環境を分けるマルチステージビルドが特に効果的です。ビルドに必要なコンパイラやツール類を最終イメージに含めずに済みます。
FROM golang:1.24 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .
# ステージ2: 実行環境(alpine = 7.73MB)
FROM alpine:3.19
RUN addgroup -g 1001 appuser && adduser -u 1001 -G appuser -D appuser
COPY –from=builder /app/myapp /myapp
USER appuser
ENTRYPOINT [“/myapp”]
# 最終イメージは数十MB。ビルドツールは含まれない
マルチステージビルドの実測比較(シングルステージ761MB → マルチステージ scratch 4.4MB など)は、別記事で詳しく扱っています。
Docker マルチステージビルド入門 — イメージを最大99%軽量化する実測ガイド
③.dockerignore で不要ファイルを除外する
ビルドコンテキスト(Dockerに送られるファイル一式)に .git や node_modules が含まれると、ビルドが遅くなります。.dockerignore ファイルを作っておくと解消できます。
.gitignore
node_modules
*.log
*.md
tests/
.env
docker-compose*.yml
# Dockerfile 自体も除外してOK(COPY . . の対象外に)
Dockerfile
④ RUN 命令をチェーンしてレイヤーを減らす
Dockerfile の RUN 命令は実行するたびに新しいレイヤー(イメージの差分の層)を作ります。apt-get install の後に rm -rf /var/lib/apt/lists/* を同じ RUN 命令の中で実行しないと、消したはずのキャッシュファイルが前のレイヤーに残ってしまいます。
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
# ✅ 良い例(1つのレイヤー内でクリーンアップまで完結)
RUN apt-get update && \
apt-get install -y –no-install-recommends curl ca-certificates && \
rm -rf /var/lib/apt/lists/*
リソース制限 — メモリ・CPU・tmpfs
リソース制限を設定しないと、1つのコンテナがホストの全メモリ・全CPUを使い果たして、他のプロセスやコンテナに影響を与えることがあります。本番環境では必ず上限を設定しましょう。

①メモリ上限を設定する(–memory)
‘cat /sys/fs/cgroup/memory.max’
536870912
# 536,870,912 バイト = 512 × 1024 × 1024 = 512MB ✓
--memory=512m と指定するだけで、cgroup v2 の memory.max に 536870912(512MB)が設定されることを実測で確認しました。コンテナがこの上限を超えてメモリを使おうとすると、OOM Killer(メモリ不足時にプロセスを強制終了するカーネルの仕組み)が起動してプロセスが終了します。
②CPU上限を設定する(–cpus)
‘cat /sys/fs/cgroup/cpu.max’
100000 100000
# quota=100000 / period=100000 → 1コア相当 ✓
# 0.5コアにしたい場合は –cpus=0.5 → 50000 100000
--cpus=1 で「1コア相当の CPU 時間」に制限されます。/sys/fs/cgroup/cpu.max の値は quota period の形式で、100000 100000 は「period 100ms のうち 100ms まで使える=1コア」を意味します。
③sysbench でコンテナ内 CPU 性能を実測する
ubuntu:24.04 コンテナ内で sysbench CPU ベンチ(--threads=2 --time=10)を3回実行した結果です。sysbench は CPU やメモリの性能を数値化する定番のベンチマークツールです。
‘apt-get install -y -qq sysbench && sysbench cpu –threads=2 –time=10 run’
— Run 1 —
events per second: 15434.57
— Run 2 —
events per second: 15377.62
— Run 3 —
events per second: 15384.30
3回平均: 15,398.8 events/sec (min=15,377.62 / max=15,434.57)
3回の計測で平均 15,398.8 events/sec(最小15,377.62〜最大15,434.57)という結果でした。3回の値がほぼ揃っており、変動が小さい=安定して計測できていることがわかります。これは Docker Desktop(ローカル macOS / 5コア割り当て)上での計測値なので、VPS の実機と比較する際の参考値として見てください。VPS上で同じコマンドを試すと、プランによってこの値は大きく変わります。
④tmpfs で一時領域を揮発性メモリに隔離する
–tmpfs /tmp:rw,noexec,nosuid,size=64m \
ubuntu:24.04 df -h /tmp
Filesystem Size Used Avail Use% Mounted on
tmpfs 64M 0 64M 0% /tmp
# noexec: スクリプト実行禁止 / nosuid: SUID 禁止
# コンテナ終了時にデータは自動消去される(揮発性)
mount で確認すると tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k) と表示され、noexec・nosuid がきちんと効いていることがわかりました。noexec オプションにより、攻撃者が /tmp にシェルスクリプトを置いても実行できなくなります。nosuid は SUID ビットを無効化して権限昇格を防ぎます。
注意:ディスクI/O測定について
コンテナ内で dd if=/dev/zero of=/tmp/test.img bs=1M count=256 conv=fsync を実行したところ、511 MB/s の書き込み速度を確認しました(256MiBを約0.52秒で書き込み / Docker Desktop on macOS の overlay2 ファイルシステム経由)。この値は同時に動かしている他コンテナの負荷で大きく上下します。実際の VPS 上では SSD への直接アクセスとなり、傾向が変わるため、あくまで環境ごとに計測し直してください。dd はテスト用ファイルを書き込むコマンドなので、必ず --rm コンテナ内かテスト用パスで実行してください。
Docker Compose ベストプラクティス
複数コンテナをまとめて管理するなら Docker Compose が便利です。docker run の長いオプション列を1つの設定ファイル(compose.yml)に集約でき、git で変更履歴も追えます。ここでは、よく見落とされがちな設定を整理します。
①セキュリティオプションを compose.yml に集約する
myapp:
image: myapp:latest
user: “1001:1001” # 非rootユーザー
read_only: true # ルートFS 読み取り専用
cap_drop:
– ALL # 全ケーパビリティ剥奪
cap_add:
– NET_BIND_SERVICE # 必要なものだけ追加
tmpfs:
– /tmp:rw,noexec,nosuid,size=64m
deploy:
resources:
limits:
cpus: ‘1.0’ # 1コア上限
memory: 512M # 512MB 上限
healthcheck:
test: [“CMD”, “curl”, “-f”, “http://localhost:8080/health”]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped
②環境変数を .env ファイルで管理する(シークレット漏洩対策)
注意:シークレットを compose.yml に直書きしない
DBパスワードや API キーを compose.yml の environment: に直書きすると、git にコミットした瞬間に漏洩します。.env ファイルを使い、必ず .gitignore に追加してください。
DB_PASSWORD=mysecretpassword
API_KEY=sk-xxxxxxxxxxxx
# compose.yml での参照
environment:
DB_PASSWORD: ${DB_PASSWORD}
API_KEY: ${API_KEY}
# .gitignore への追加
$ echo “.env” >> .gitignore
③HEALTHCHECK でサービスの死活監視を組み込む
restart: unless-stopped と組み合わせると、ヘルスチェックが失敗したコンテナを検知して扱えるようになります。Web サービスなら curl -f、DB なら pg_isready などを使います。実際に稼働中のコンテナを docker ps で見ると、ヘルスチェックの状態が (healthy) として表示されます。
$ docker ps –format ‘table {{.Names}}\t{{.Status}}’
NAMES STATUS
review_postgres Up 12 hours (healthy)
linuxlab_cadvisor_ss Up 22 hours (healthy)
linuxlab_jellyfin_ss Up 29 hours (healthy)
linuxlab_owua_ss Up 29 hours (healthy)
linuxlab_vaultwarden_ss Up 29 hours (healthy)
# STATUS に (healthy) と出ていれば正常稼働中
実際に手元で動かしているコンテナの docker ps 出力でも、複数のサービスで (healthy) ステータスが確認できました。これはヘルスチェックが機能している証拠です。逆に (unhealthy) と出るコンテナがあれば、そこに問題が起きているとすぐ気づけます。
定期メンテナンス — docker system prune と更新
Docker を使い続けると、使われていないイメージ・停止したコンテナ・未使用ボリュームがどんどんディスクを圧迫します。気づくと数十GBを食っていた、というのはよくある話です。
①docker system prune で不要リソースを一括削除する
$ docker system prune -f
Deleted Containers:
Deleted Images: …
Total reclaimed space: X.XXgB
# ボリュームも含めて削除(注意: データが消えます)
$ docker system prune –volumes -f
注意:–volumes フラグの破壊性
docker system prune --volumes は未使用のボリュームも削除します。DB データなどをボリュームで管理している場合は、必ずバックアップを取ってから実行してください。-f フラグを付けずに実行すると確認プロンプトが出るので、慣れないうちは -f なしで内容を確認してから進めるのがおすすめです。
②docker.io パッケージを最新に保つ(Ubuntu 24.04)
Ubuntu 24.04 で apt 経由で Docker をインストールしている場合、通常の apt upgrade で更新できます。実測では apt-cache show docker.io で 29.1.3-0ubuntu3~24.04.2 が最新版として確認できました。Docker のセキュリティ修正は CVE 対応で随時入るため、定期的なアップデートは重要です。
$ sudo apt-get install –only-upgrade docker.io containerd
# docker.io: 29.1.3-0ubuntu3~24.04.2 (Ubuntu 24.04 / 2026-06-15 時点)
# containerd: 2.2.1-0ubuntu1~24.04.2
まとめ — 2026年 Docker ベストプラクティスチェックリスト


2026年現在、Ubuntu 24.04 + Docker でのベストプラクティスをまとめます。
セキュリティ
--user 1000:1000または Dockerfile のUSER命令で非rootユーザーとして実行する--cap-drop=ALLを基本とし、必要なケーパビリティだけ--cap-addで追加する--read-onlyでルートFSを読み取り専用にし、--tmpfsで書き込み箇所を明示する--tmpfs /tmp:rw,noexec,nosuidでスクリプト実行・SUID を無効化するtrivyやdocker scanで定期的にイメージの脆弱性をスキャンする
イメージ最適化
- マルチステージビルドでビルド環境と実行環境を分離する
- 実行環境のベースは alpine(7.73MB)や distroless を選ぶ(ubuntu:24.04 は 101MB)
RUN apt-get update && apt-get install && rm -rf /var/lib/apt/lists/*を1つの RUN にまとめる.dockerignoreで.git・node_modulesなどを除外する
運用・パフォーマンス
--memory=512m --cpus=1でリソース上限を必ず設定する(ホスト保護)HEALTHCHECK+restart: unless-stoppedで自動復旧を組み込む- シークレットは
.envファイルで管理し、compose.yml には直書きしない - 定期的に
docker system pruneで不要リソースを削除する - Ubuntu 24.04 の
apt upgradeで docker.io と containerd を最新に保つ
一度に全部やろうとすると大変なので、最初はセキュリティの「非rootユーザー」と「リソース制限」だけでも設定しておくと効果的です。この2つだけでも、本番での事故リスクはぐっと下がります。
これらを自分の VPS で実践したい方は、Vultr の東京リージョンが最安クラスで始められます。Ubuntu 24.04 + Docker の構成を試すだけなら、月5ドルのプランで十分です。
また、VPS各社の料金・性能比較は別記事でまとめています。
VPS比較2026年版 — Vultr・DigitalOcean・ConoHa を実測ベンチで比べる



コメント