はじめに
Dockerfile は、Docker を使い始めた頃は
「アプリが起動すればOK」 という感覚で書かれがちです。
しかし、Dockerfile は単なる起動設定ではありません。
本番環境においては、
- どの OS・どのライブラリが含まれるか
- どの権限でアプリケーションが動くか
- 障害時に調査できるか
- セキュリティ事故が起きたとき、被害を最小限に抑えられるか
といった 運用・セキュリティ・信頼性すべてに影響する設計書 です。
Dockerfile の怖い点は、
「今は動いている」「問題が起きていない」状態でも、
将来の事故要因を静かに抱え込んでしまう ところにあります。
この記事では、実務現場で本当によく見かける
Dockerfile の本番アンチパターンを取り上げ、
- なぜそれが危険なのか
- 実際にどんな事故につながるのか
- どう直せばよいのか
- 手元で確認できるハンズオン
までを、できるだけ具体的に解説します。
アンチパターン①:latest タグを使い続ける
❌ 悪い例
FROM node:latest
なぜ問題になるのか?
latest は一見便利に見えますが、
本番運用では最も危険なタグのひとつです。
- いつ Node.js のバージョンが変わるか分からない
- ある日突然、ビルドが失敗する
- 依存ライブラリの互換性が壊れる
- 本番と検証環境で再現できなくなる
つまり、再現性が完全に失われます。
実務で起きがちな事故
- 昨日まで動いていた CI が突然失敗
- 緊急リリース時に原因が分からない
- 「Dockerfile は変えていないのに壊れた」
👉 原因は latest だった、というケースは非常に多いです。
✅ 改善例
FROM node:20.11-alpine
- バージョンを固定する
- 更新は「意図的な作業」として行う
ハンズオン
docker build -t app:latest .
docker build -t app:fixed .
数か月後、同じ Dockerfile を再ビルドすると
結果が変わる可能性があるのは latest の方です。
アンチパターン②:root ユーザーで本番実行する
❌ 悪い例
FROM node:20
WORKDIR /app
COPY . .
CMD ["node", "index.js"]
なぜ危険なのか?
Docker コンテナは仮想マシンではありません。
root 権限で動いているコンテナに侵入されると、
- ファイル改ざん
- 不正コマンド実行
- 他コンテナへの横展開
といった被害につながる可能性があります。
ハンズオン(確認)
docker run -it image-name sh
whoami
root
👉 侵入=即 root 権限取得
✅ 改善例
FROM node:20-alpine
WORKDIR /app
COPY . .
USER node
CMD ["node", "index.js"]
whoami
node
非 root 実行にするだけで、
被害範囲をコンテナ内部に限定できます。
アンチパターン③:不要なツールを本番に入れる
❌ 悪い例
RUN apt update && apt install -y \
vim \
curl \
git \
net-tools
なぜやってしまうのか?
- デバッグ用に入れたまま忘れる
- 開発環境と本番を分けていない
なぜ危険か?
- 攻撃者が使えるツールが増える
- 脆弱性を含む可能性が高まる
- イメージサイズが無駄に大きくなる
✅ 改善例
- 開発用と本番用 Dockerfile を分ける
- マルチステージビルドを使う
FROM node:20 AS build
RUN npm install
FROM node:20-alpine
COPY --from=build /app/dist ./dist
アンチパターン④:.env や secrets を COPY する
❌ 悪い例
COPY . .
.env が含まれていると、
その時点で情報漏洩が確定します。
ハンズオン(確認)
docker inspect image-name
- APIキー
- DBパスワード
が平文で見えることもあります。
✅ 改善例
.dockerignore
.env
.git
node_modules
実行時に注入:
docker run -e API_KEY=xxxxx app
アンチパターン⑤:単一ステージ Dockerfile を本番で使う
❌ 悪い例
FROM node:20
COPY . .
RUN npm install && npm run build
CMD ["node", "dist/index.js"]
問題点
- ビルドツールが残る
- 開発用ファイルが混入
- 攻撃対象領域が広がる
✅ 改善例(マルチステージ)
FROM node:20 AS build
WORKDIR /app
COPY . .
RUN npm install && npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/index.js"]
アンチパターン⑥:COPY の順序を考えない
❌ 悪い例
COPY . .
RUN npm install
なぜ問題か?
- ちょっとした変更でキャッシュ無効
- CI ビルドが遅くなる
- 無駄な再インストール
✅ 改善例
COPY package.json package-lock.json ./
RUN npm install
COPY . .
👉 ビルド時間短縮 = 開発体験向上
アンチパターン⑦:ログをファイルに出力する
❌ 悪い例
fs.appendFileSync("app.log", "log");
なぜ本番で困るのか?
- コンテナ再起動でログ消失
- Kubernetes で取得しづらい
- 集約・監視が難しい
✅ 改善例
console.log("application started");
- stdout / stderr に出力
- Docker / Kubernetes と相性が良い
アンチパターン⑧:開発用設定を本番に流用する
よくある例
- debug モード ON
- hot reload 有効
- テストコード混入
改善策
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
- 本番・開発を明確に分離
- 意図しない設定混入を防ぐ
本番向け Dockerfile チェックリスト
- latest を使っていない
- 非 root ユーザーで実行
- secrets を含めていない
- マルチステージを使用
- .dockerignore を設定
- ログは stdout
まとめ
Dockerfile のアンチパターンは、
- 「知らなかった」より
- 「後回しにした」ことで起きる
ケースがほとんどです。
Dockerfile は
早い段階で正しく設計すれば、後から楽になる技術でもあります。
「動く Dockerfile」から
「本番で安心して使える Dockerfile」へ
このアンチパターン集が、その一歩になれば幸いです。
コメントを残す