Docker ベストプラクティス2026 on Ubuntu — セキュリティ・最適化・運用

Docker

動作確認済み環境

本記事のコマンドは 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 が 00000000a80425fb0000000000000000 になることを実測確認)
  • ベースイメージを alpine に変えるだけで ubuntu:24.04(101MB)の約1/13(7.73MB)に軽量化できる(実測)
  • --memory=512m --cpus=1 でリソース上限を設定し、ホストを守れる(cgroup v2 で動作確認済み)
  • --tmpfs /tmp:rw,noexec,nosuid で一時領域へのスクリプト実行・SUID を禁止できる
  • 全ポイントをまとめたチェックリストを記事末に掲載しています

目次

  1. 動作確認済み環境
  2. セキュリティ強化 — 非rootユーザー・ケーパビリティ・read-only
  3. イメージ最適化 — マルチステージビルドと alpine
  4. リソース制限 — メモリ・CPU・tmpfs
  5. Docker Compose ベストプラクティス
  6. 定期メンテナンス — docker system prune と更新
  7. まとめチェックリスト

動作確認済み環境

まず、本記事で使った環境を docker versiondocker info で確認しておきます。Docker は「コンテナ」という隔離された箱の中でアプリを動かす仕組みで、docker info はその土台になっているストレージ方式やリソース管理の仕組み(cgroup)を教えてくれます。

Docker 20.10.12 + Ubuntu 24.04.4 LTS 環境情報(実測)
Docker 20.10.12 + Ubuntu 24.04.4 LTS 環境情報(実測)

重要な確認ポイントを整理します。

項目 今回の実測値 確認コマンド
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 cgroupCgroup 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つの観点で整理しています。本記事はこのうち、個人でもすぐ手を打てる部分を実際のコマンドで押さえていきます。

Docker公式 Docker Engine security ドキュメント(Playwright実撮影)
Docker公式 Docker Engine security ドキュメント(Playwright実撮影)

①非rootユーザーでコンテナを実行する(–user フラグ)

最も手軽な対策は --user フラグです。




ubuntu@linuxlab: ~
$ docker run –rm –user 1000:1000 ubuntu:24.04 bash -c ‘whoami; id’
ubuntu
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu)

--user 1000:1000(uid:gid の指定)を付けるだけで、コンテナ内プロセスが root ではなく uid=1000(ubuntu) で動くことが実際に確認できました。Dockerfile に USER 命令を書いておくと、毎回 --user を指定しなくて済みます。




Dockerfile 記述例
# アプリ用ユーザーを作成して切り替える
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(ファイル所有者の変更)など、アプリが必要としないものも多く含まれています。

非rootユーザー + --cap-drop=ALL 実測(ubuntu:24.04)
非rootユーザー + –cap-drop=ALL 実測(ubuntu:24.04)

実測では、デフォルトの CapPrm: 00000000a80425fb(多くのケーパビリティが有効)が、--cap-drop=ALL を付けると CapPrm: 0000000000000000(全ゼロ=ケーパビリティなし)になることを確認できました。CapPrm はそのプロセスが持つ許可済みケーパビリティをビット列で表したもので、ゼロは「特権を一切持たない」状態です。




ubuntu@linuxlab: ~
# デフォルト(多くのケーパビリティが有効)
$ 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 フラグを付けると、コンテナのルートファイルシステムへの書き込みが禁止されます。攻撃者がコンテナに侵入しても、マルウェアの設置や設定ファイルの改ざんができなくなります。




ubuntu@linuxlab: ~
$ docker run –rm –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 で書き込み可能にしている
著者アイコン
著者アイコン

正直、--read-only は最初は「面倒そう」と思いました。でも、アプリがどこに書き込んでいるのかを把握する良い機会になります。書き込みが必要な箇所だけ -v--tmpfs でマウントするクセをつけると、ファイルシステムの設計が自然と整理されてきますよ。

イメージ最適化 — マルチステージビルドと alpine

コンテナイメージは小さいほど良いです。理由は単純で、ダウンロード(プル)時間の短縮・攻撃面積の縮小・ストレージコストの削減の3点です。

①ベースイメージのサイズを比較する

Dockerイメージサイズ比較(実測 — ubuntu vs alpine)
Dockerイメージサイズ比較(実測 — ubuntu vs alpine)

実際に docker images で確認した結果です。ubuntu:24.04101MBubuntu:22.0469.6MBalpine:3.197.73MBと、ubuntu:24.04 と alpine では約13倍の差があります。本番環境では Alpine(musl libc ベースの超軽量Linux)を検討するだけで、イメージの転送・プルの時間が大幅に短縮されます。




ubuntu@linuxlab: ~
$ docker images –format ‘{{.Repository}}:{{.Tag}}\t{{.Size}}’
ubuntu:24.04 101MB
ubuntu:22.04 69.6MB
alpine:3.19 7.73MB
# alpine は ubuntu:24.04 の約1/13サイズ

②マルチステージビルドで本番イメージを軽量化する

Go や Rust のようにコンパイルが必要な言語では、ビルド環境と実行環境を分けるマルチステージビルドが特に効果的です。ビルドに必要なコンパイラやツール類を最終イメージに含めずに済みます。




Dockerfile — マルチステージビルド例(Go アプリ)
# ステージ1: ビルド環境(golang:1.24 = 約800MB)
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に送られるファイル一式)に .gitnode_modules が含まれると、ビルドが遅くなります。.dockerignore ファイルを作っておくと解消できます。




.dockerignore(プロジェクトルートに配置)
.git
.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 命令の中で実行しないと、消したはずのキャッシュファイルが前のレイヤーに残ってしまいます。




Dockerfile — 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を使い果たして、他のプロセスやコンテナに影響を与えることがあります。本番環境では必ず上限を設定しましょう。

メモリ・CPU・tmpfs リソース制限実測(cgroup v2確認)
メモリ・CPU・tmpfs リソース制限実測(cgroup v2確認)

①メモリ上限を設定する(–memory)




ubuntu@linuxlab: ~
$ docker run –rm –memory=512m ubuntu:24.04 bash -c \
‘cat /sys/fs/cgroup/memory.max’
536870912
# 536,870,912 バイト = 512 × 1024 × 1024 = 512MB ✓

--memory=512m と指定するだけで、cgroup v2 の memory.max536870912(512MB)が設定されることを実測で確認しました。コンテナがこの上限を超えてメモリを使おうとすると、OOM Killer(メモリ不足時にプロセスを強制終了するカーネルの仕組み)が起動してプロセスが終了します。

②CPU上限を設定する(–cpus)




ubuntu@linuxlab: ~
$ docker run –rm –cpus=1 ubuntu:24.04 bash -c \
‘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 やメモリの性能を数値化する定番のベンチマークツールです。




ubuntu@linuxlab: ~ [sysbench CPU × 3回実測]
$ docker run –rm ubuntu:24.04 bash -c \
‘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 で一時領域を揮発性メモリに隔離する




ubuntu@linuxlab: ~
$ docker run –rm \
–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) と表示され、noexecnosuid がきちんと効いていることがわかりました。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 に集約する




compose.yml — ベストプラクティス設定例
services:
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 に追加してください。




シークレット管理の推奨構成
# .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) として表示されます。




ubuntu@linuxlab: ~
# ヘルスチェック付きコンテナの状態確認
$ 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 で不要リソースを一括削除する




ubuntu@linuxlab: ~
# 停止コンテナ・未使用イメージ・ネットワーク・キャッシュを削除
$ 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.io29.1.3-0ubuntu3~24.04.2 が最新版として確認できました。Docker のセキュリティ修正は CVE 対応で随時入るため、定期的なアップデートは重要です。




ubuntu@linuxlab: ~
$ sudo apt-get update
$ 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 ベストプラクティスチェックリスト

Docker ベストプラクティスチェックリスト(2026年 Ubuntu対応)
Docker ベストプラクティスチェックリスト(2026年 Ubuntu対応)
Docker コマンド実出力(非root・ケーパビリティ・イメージサイズ比較)
Docker コマンド実出力(非root・ケーパビリティ・イメージサイズ比較)

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 を無効化する
  • trivydocker 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.gitnode_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 を実測ベンチで比べる

コメント

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