Dockerfile実践
目次
- 概要
- Dockerfileの基本
- layerとcache
- cacheを効かせる書き方
- multi-stage build
- 非root実行
- imageを小さくする
- secretを入れない
- BuildKit secrets
- healthcheck
- build contextと.dockerignore
- base imageとdigest
- runtime設定
- scanとSBOM
- トラブルシューティング
- 運用チェックリスト
- Docker セキュリティベストプラクティス(OWASP版)
- Docker Compose と本番運用
- Docker Volumes と Persistence
- Base Image の選択ガイド
- Digest による不変性の確保
- Build Arguments と Build-time Variables
- Image Scanning と Vulnerability Detection
- Software Bill of Materials (SBOM)
- Runtime の最適化
- Layer の最適化テクニック
- Security Best Practices
- Docker Compose とマルチコンテナ管理
- よくあるエラーと対策
- Dockerfile Linting
- まとめ
- 参考文献
概要
Dockerfileは、コンテナイメージの作り方を記述するファイルです。単に動くimageを作るだけでなく、再現性、セキュリティ、cache効率、運用しやすさに影響します。
Dockerfileは「環境構築手順」ではなく「配布する実行環境の設計」です。layer、cache、multi-stage build、非root実行、secretの扱いを意識すると、安全で速いimageに近づきます。
Dockerfileの基本
最小例です。
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
CMD ["node", "server.js"]
代表的な命令です。
| 命令 | 役割 |
|---|---|
FROM |
base image |
WORKDIR |
作業ディレクトリ |
COPY |
ファイルをimageに入れる |
RUN |
build時にコマンド実行 |
ENV |
環境変数 |
USER |
実行ユーザー |
EXPOSE |
想定ポート |
CMD |
container起動時の既定コマンド |
ENTRYPOINT |
起動時に必ず実行するコマンド |
layerとcache
Dockerfileの各命令はlayerを作ります。build cacheは、前のlayerが変わらなければ再利用されます。
依存関係のinstallをsource copyより前に置くと、ソース変更だけでは npm ci のlayerを再利用できます。
悪い例です。
COPY . .
RUN npm ci
良い例です。
COPY package*.json ./
RUN npm ci
COPY . .
cacheを効かせる書き方
Dockerのcacheは「前の命令までの入力が同じなら、同じlayerを再利用できる」という考え方で動きます。つまり、頻繁に変わるものを早い段階で COPY すると、その後ろの重い処理まで毎回やり直しになります。
依存関係のファイルとアプリケーションのソースを分けるのが基本です。
FROM node:22-bookworm-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM deps AS build
COPY . .
RUN npm run build
Pythonでも同じです。
FROM python:3.12-slim AS app
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
BuildKitを使える環境では、package managerのdownload cacheをlayerに焼き込まずに、build cacheとして使えます。
# syntax=docker/dockerfile:1.7
FROM node:22-bookworm-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
RUN npm run build
この書き方では、/root/.npm のcacheはimageの中身には残りません。buildを速くしつつ、runtime imageを肥大化させないための実践的な折衷です。
cacheを効かせる設計は、次の順で考えると整理しやすくなります。
| 変化しにくい | 変化しやすい |
|---|---|
| base image | アプリケーションコード |
| OS package install | テスト対象のファイル |
| language runtime | 静的アセット |
| dependency lockfile | 設定ファイル |
よくある失敗は、.dockerignore が弱いまま COPY . . を早く書いてしまうことです。node_modules、.git、dist、coverage、localの .env がcontextに入ると、cacheが壊れやすくなり、buildも遅くなります。
multi-stage build
multi-stage buildは、build用の環境と実行用の環境を分けます。
FROM node:22 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
build toolやdev dependenciesを最終imageに入れずに済みます。
multi-stage buildは「小さくする」ためだけではありません。build、test、runtimeを分けると、CIの中で同じDockerfileから目的別のtargetを作れます。
FROM node:22-bookworm-slim AS base
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM base AS test
COPY . .
RUN npm test
FROM base AS build
COPY . .
RUN npm run build
FROM nginx:1.27-alpine AS runtime
COPY --from=build /app/dist /usr/share/nginx/html
docker build --target test -t app:test .
docker build --target runtime -t app:runtime .
targetを分けておくと、CIではtestまで、releaseではruntimeまで、というように同じ設計を使い回せます。
非root実行
container内でもroot実行は避けるのが基本です。
RUN addgroup -S app && adduser -S app -G app
USER app
rootで動かすと、脆弱性があったときの影響が大きくなります。アプリケーションが書き込むディレクトリだけ権限を付け、不要な権限を持たせないようにします。
imageを小さくする
imageが大きいと、pullが遅くなり、脆弱性スキャン対象も増えます。
小さくする方法です。
.dockerignoreを使う- multi-stage buildを使う
- 不要なpackageを入れない
- build cacheとruntimeを分ける
- base imageを見直す
.dockerignore の例です。
node_modules
dist
.git
.env
*.log
secretを入れない
Dockerfileにsecretを書いてはいけません。
悪い例です。
ENV API_TOKEN=secret
image layerや履歴に残る可能性があります。secretはruntimeの環境変数、secret manager、CI/CDのsecret機能で渡します。
BuildKit secrets
private registryやprivate package repositoryに接続するため、build中だけtokenが必要になることがあります。この場合も ARG や ENV で渡すのは避けます。BuildKitのsecret mountを使うと、secretをlayerに残さず、特定の RUN 命令だけに渡せます。
# syntax=docker/dockerfile:1.7
FROM node:22-bookworm-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
COPY . .
RUN npm run build
build時にsecretを渡します。
docker build \
--secret id=npmrc,src="$HOME/.npmrc" \
-t app:local .
この場合、.npmrc はbuild中の一時的なmountとして見えるだけです。image historyや最終imageのfilesystemに残す前提で設計しないことが重要です。
secretの扱いは、次の3段階で分けます。
| 種類 | 渡し方 | Dockerfileに書くか |
|---|---|---|
| build中だけ必要なtoken | BuildKit secret mount | 書かない |
| runtimeで必要なsecret | orchestrator、secret manager、CI/CD secret | 書かない |
| 公開してよい設定値 | ENV または設定ファイル |
書いてよい |
ARG はbuild-time parameterですが、secretを安全に隠す仕組みではありません。proxy URLやpackage mirrorのような非secret設定には使えますが、credentialには使わない方が安全です。
healthcheck
HEALTHCHECK は、containerが生きているだけでなく、アプリケーションとして応答できるかを確認します。
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -qO- http://localhost:8080/health || exit 1
ただし、healthcheckが重すぎると負荷になります。軽量で依存が少ないendpointを使います。
build contextと.dockerignore
Docker buildでは、Dockerfileのある場所だけでなく、build contextに含まれるファイルがdaemonへ送られます。
docker build -t app .
この . がbuild contextです。不要なファイルが含まれると、buildが遅くなり、secretを誤って送る危険もあります。
.dockerignore には、imageに不要なものを書きます。
.git
node_modules
dist
.env
*.log
coverage
COPY . . は便利ですが、contextに含まれるものをまとめてimageに入れるため、.dockerignore とセットで考えます。
build contextはlocal directoryだけとは限りません。Git repositoryやremote tarballをcontextにできます。ただし、Dockerfileから参照できるのはcontextに含まれるファイルだけです。親ディレクトリのファイルを COPY ../secret . のように直接持ち込むことはできません。
contextを小さくすると、次の効果があります。
| 効果 | 理由 |
|---|---|
| buildが速くなる | daemonやremote builderへ送る量が減る |
| cacheが壊れにくい | 無関係なファイル変更がbuild入力に入りにくい |
| secret混入を避けやすい | .env やcredentialをcontextから除外できる |
| CIが安定する | localにはあるがCIにはないファイルへの依存を減らせる |
base imageとdigest
base imageは、アプリケーションの土台です。サイズだけで選ぶと、debugしにくい、必要なlibcがない、security updateの運用が難しい、といった問題が出ます。
| 選択肢 | 向いている場面 | 注意点 |
|---|---|---|
debian / ubuntu 系 |
汎用性と互換性を重視する | imageは大きめ |
slim 系 |
互換性を保ちつつ小さくしたい | 必要なtoolが省かれる |
alpine |
小さいimageが必要 | musl libc差分で詰まることがある |
| distroless | runtimeだけを最小化したい | shellがなくdebugしにくい |
| language official image | Node、Python、Goなどの標準環境 | tagの更新方針を確認する |
tagは便利ですが、同じtagが将来も同じ中身を指すとは限りません。再現性を強めたい場合はdigest固定を検討します。
FROM node:22-bookworm-slim@sha256:...
digest固定にはtrade-offがあります。完全に固定するとbuildは再現しやすくなりますが、security updateは自動で入らなくなります。そのため、固定する場合は「定期的にdigestを更新する」「scanで更新必要性を検知する」という運用とセットにします。
runtime設定
Dockerfileはbuildだけでなく、containerの起動時の振る舞いも決めます。CMD、ENTRYPOINT、ENV、EXPOSE、USER、WORKDIR はruntimeの読みやすさに直結します。
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER 10001
EXPOSE 8000
ENTRYPOINT ["python", "-m", "uvicorn"]
CMD ["app:app", "--host", "0.0.0.0", "--port", "8000"]
ENTRYPOINT は「このimageの主役となる実行ファイル」、CMD は「既定の引数」と考えると分かりやすいです。
docker run app
docker run app app:app --host 0.0.0.0 --port 9000
運用では、次の点を明示しておくと事故が減ります。
| 設定 | 意味 | 注意 |
|---|---|---|
WORKDIR |
相対pathの基準 | / のまま作業しない |
USER |
起動ユーザー | rootのままにしない |
EXPOSE |
想定ポート | 実際のpublishではない |
ENV |
公開してよい既定値 | secretを入れない |
ENTRYPOINT |
主コマンド | shell formよりexec formが扱いやすい |
CMD |
既定引数 | composeやrunで上書きされる |
scanとSBOM
imageには、アプリケーションコードだけでなく、OS package、language runtime、native library、依存package、設定ファイルが含まれます。脆弱性対応では「アプリの依存だけを見る」では足りません。
実務では、次のような確認を組み合わせます。
| 観点 | 例 |
|---|---|
| vulnerability scan | Docker Scout、Trivy、Grype |
| SBOM | Syft、Docker build attestation |
| base image更新 | Renovate、Dependabot、Docker Scout |
| 署名と検証 | cosign、registry policy |
| 不要ファイル確認 | docker image history、docker run --rm -it image sh |
scan結果は、件数だけで判断しません。重要なのは、修正版があるか、runtimeに到達するpathか、外部入力から悪用可能か、base imageの更新で直るかです。
また、SBOMは「何が入っているか」を説明するための材料です。監査、incident response、license確認、脆弱性影響調査の入口になります。
トラブルシューティング
Dockerfileの問題は、build時、起動時、runtimeの3段階で切り分けます。
| 症状 | 見る場所 | よくある原因 |
|---|---|---|
| buildが遅い | --progress=plain |
contextが大きい、cacheが効いていない |
| cacheが効かない | COPY の順序 |
source全体を先にcopyしている |
| imageが大きい | docker image history |
build tool、cache、不要ファイルが残っている |
| containerがすぐ終了 | docker logs |
foreground processがない、CMDが間違い |
| ファイルが見つからない | WORKDIR、COPY |
context外のファイルを期待している |
| permission error | USER、file owner |
非root化後に書き込み先権限がない |
| secretが残る | docker history、layer |
ENV、ARG、copy済みファイルに含まれる |
調査時によく使うコマンドです。
docker build --progress=plain -t app:debug .
docker image history app:debug
docker run --rm app:debug
docker logs <container>
docker exec -it <container> sh
runtime imageにshellがない場合は、debug用targetを別に用意する手もあります。
FROM runtime AS debug
USER root
RUN apt-get update && apt-get install -y --no-install-recommends curl procps \
&& rm -rf /var/lib/apt/lists/*
本番imageにdebug toolを入れっぱなしにするのではなく、調査用targetとして分けるのが安全です。
運用チェックリスト
Dockerfileをレビューするときの観点です。
| 観点 | 確認 |
|---|---|
| base image | 公式・更新状況・サイズ |
| cache | 依存installとsource copyの順序 |
| runtime | build toolが最終imageに残っていないか |
| user | rootで動いていないか |
| secret | ENV やlayerにsecretがないか |
| package | 不要なpackageを入れていないか |
| healthcheck | 軽量で意味のある確認か |
| reproducibility | tagやdigestの固定方針 |
| context | .dockerignore で不要ファイルを除外しているか |
| scan | image scanとSBOMの確認があるか |
| command | ENTRYPOINT と CMD の意図が分かるか |
本番運用では、image scan、SBOM、署名、registryの権限も関わります。Dockerfileは開発用の便利ファイルではなく、供給chainの入口でもあります。
Docker セキュリティベストプラクティス(OWASP版)
Open Web Application Security Project (OWASP) は、Docker コンテナのセキュリティに関する Cheat Sheet を公開。
イメージスキャンと脆弱性管理
Docker イメージビルド時の脆弱性スキャン
docker build --build-arg SCAN=true .
docker scout cves myapp:latest
Trivy(OSSの脆弱性スキャナ)による検査:
trivy image myapp:latest
ルートユーザーの回避
Dockerfile で非ルートユーザーを指定:
FROM ubuntu:22.04
# ユーザーを作成
RUN useradd -m -u 1000 appuser
# ファイルの所有権を変更
COPY --chown=appuser:appuser app/ /app/
# ユーザーを切り替え
USER appuser
CMD ["./app"]
マルチステージビルド による最小化
最終イメージサイズを削減し、攻撃面を減らす:
# Stage 1: Build
FROM golang:1.21 AS builder
WORKDIR /build
COPY . .
RUN CGO_ENABLED=0 go build -o app
# Stage 2: Runtime
FROM scratch
COPY --from=builder /build/app /
CMD ["/app"]
scratch ベースイメージを使用することで、OS全体のオーバーヘッドを排除。
機密情報の管理
ビルド時シークレット(BuildKit)
# --mount=type=secret を使用
RUN --mount=type=secret,id=docker_token \
curl -H "Authorization: token $(cat /run/secrets/docker_token)" \
https://api.github.com/user
ビルドコマンド:
docker buildx build --secret docker_token=~/.docker_token .
実行時環境変数
Kubernetes Secrets または Docker Secrets を利用。
イメージレイヤキャッシュの活用
頻繁に変わるコマンドを下に配置して、キャッシュヒット率を上げる:
FROM node:20-alpine
# 変わらない層
RUN apk add --no-cache python3 build-base
# 次に変わらない層
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# 最後に変わる層
COPY . .
Network Policies と Egress の制限
Kubernetes での Pod間通信を制限:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: app-policy
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
egress:
- to:
- podSelector:
matchLabels:
app: backend
Docker Compose と本番運用
開発環境と本番環境の分離
# docker-compose.yml (開発環境)
version: '3.8'
services:
app:
build: .
ports:
- "5000:5000"
volumes:
- .:/app
environment:
DEBUG: "true"
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: devpass123
本番環境では:
# docker-compose.prod.yml
version: '3.8'
services:
app:
image: registry.example.com/myapp:1.2.3
restart: always
environment:
DEBUG: "false"
db:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
ヘルスチェックの実装
FROM python:3.11-alpine
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:8000/health')"
ログ管理
コンテナログを直接ファイルに書かず、stdout/stderr に出力して、Docker ログドライバで処理:
CMD ["python", "-u", "app.py"] # -u で出力をバッファしない
Docker Volumes と Persistence
Named Volumes(推奨)
docker volume create mydata
docker run -v mydata:/data myimage
Bind Mounts(開発用)
docker run -v /host/path:/container/path myimage
Volume ドライバ(NFS、S3等)
docker run --volume-driver nfs \
--mount src=mydata,dst=/data \
myimage
Base Image の選択ガイド
Base Image サイズ比較
| Base Image | サイズ | 用途 |
|---|---|---|
| ubuntu:24.04 | ~70 MB | 汎用、ツール豊富 |
| debian:bookworm-slim | ~30 MB | 標準、バランス |
| alpine:latest | ~7 MB | 最小化、軽量 |
| python:3.11 | ~900 MB | Python全セット |
| python:3.11-slim | ~150 MB | Python最小化 |
| python:3.11-alpine | ~50 MB | Python+Alpine |
| node:22-alpine | ~180 MB | Node+Alpine |
| scratch | 0 MB | バイナリのみ(Go等) |
Alpine vs Debian
Alpine の利点:
- 非常に小さい
- Package manager (apk) が高速
- セキュリティ更新が迅速
Alpine の課題:
- mulibc 使用(glibc との非互換)
- ビルドツールが少ない
- 一部のバイナリが動作しない
実装例:
# 開発環境:Debian slim(ツール豊富)
FROM python:3.11-bookworm
# 本番環境:Alpine(小さい)
FROM python:3.11-alpine
Digest による不変性の確保
Base image を pin することで、再現性を保証します。
# 危険:image タグは時間とともに変わる
FROM node:22-alpine
# 推奨:digest で固定(SHA256ハッシュ)
FROM node:22-alpine@sha256:abc123def456...
digest を取得するには:
docker inspect node:22-alpine --format='{{index .RepoDigests 0}}'
# Output: node@sha256:abc123def456...
digest を含めた Dockerfile:
# Node.js 22.0.0, Alpine 3.20 (2024-05-10時点)
FROM node:22.0.0-alpine@sha256:abc123def456...
Build Arguments と Build-time Variables
Dockerfile のビルド時に変数を渡す:
ARG NODE_VERSION=22
ARG REGISTRY=docker.io
FROM ${REGISTRY}/node:${NODE_VERSION}-alpine
ARG BUILD_DATE
ARG VCS_REF
ARG VERSION=1.0.0
LABEL \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${VCS_REF}" \
org.opencontainers.image.version="${VERSION}"
ビルド時:
docker build \
--build-arg NODE_VERSION=22 \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
--build-arg VCS_REF=$(git rev-parse --short HEAD) \
--build-arg VERSION=1.2.3 \
-t myapp:1.2.3 \
.
Image Scanning と Vulnerability Detection
Docker Scout
# Local image をスキャン
docker scout cves myapp:latest
# Output example:
# 3 packages with known vulnerabilities
# │ CVE-2024-1234 │ HIGH │ openssl
# │ CVE-2024-5678 │ MEDIUM │ curl
Trivy(オープンソース)
trivy image myapp:latest
# 詳細レポート出力
trivy image --format json --output report.json myapp:latest
Software Bill of Materials (SBOM)
SBOM は image に含まれるすべてのパッケージ・依存関係の一覧です:
# SBOM を生成
docker build --sbom=true .
# または
syft myapp:latest > sbom.json
SBOM の構造(CycloneDX 形式):
{
"bom-format": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"components": [
{
"type": "library",
"name": "openssl",
"version": "3.1.2",
"purl": "pkg:deb/debian/openssl@3.1.2"
}
]
}
Runtime の最適化
ENTRYPOINT vs CMD
# CMD のみ
FROM alpine
CMD ["echo", "hello"]
# docker run myimage → "hello" 出力
# docker run myimage echo foo → "foo" 出力
# ENTRYPOINT + CMD(推奨)
FROM alpine
ENTRYPOINT ["sh", "-c"]
CMD ["echo hello"]
# docker run myimage → "hello" 出力
# docker run myimage "echo foo" → "foo" 出力
# ENTRYPOINT のスクリプト化
FROM node:22-alpine
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
CMD ["node", "server.js"]
entrypoint.sh の例:
#!/bin/sh
set -e
# ヘルスチェック
if [ -n "$HEALTH_CHECK" ]; then
echo "Running health check..."
curl -f http://localhost:8000/health || exit 1
fi
# セットアップ
if [ "$RUN_MIGRATIONS" = "true" ]; then
npm run migrate
fi
# メインプロセス実行
exec "$@"
Layer の最適化テクニック
RUN コマンドの連鎖
# 非効率:各行が個別 layer
RUN apt-get update
RUN apt-get install -y curl git vim
RUN apt-get clean
# 効率的:単一 layer
RUN apt-get update && \
apt-get install -y curl git vim && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
Intermediate images の削除
# 不要な images を削除
docker image prune
# dangling images のみ削除
docker image prune -f
Security Best Practices
Secrets の分離
# 危険:secret を COPY や RUN で記録
COPY secret.txt .
RUN echo $SECRET > config.txt
# 推奨:BuildKit secrets を使用
# Dockerfile
RUN --mount=type=secret,id=api_key \
API_KEY=$(cat /run/secrets/api_key) \
npm run build
# ビルド実行
docker build \
--secret api_key=/path/to/secret \
.
Network Isolation
# Network access を必要な場合のみ許可
FROM alpine:latest
RUN apk add --no-cache curl
RUN curl https://example.com/file.tar.gz | tar xz
User & Permissions
FROM python:3.11-alpine
# ユーザ作成(非root)
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# ファイルのオーナーシップ
COPY --chown=appuser:appgroup . /app
WORKDIR /app
USER appuser
CMD ["python", "app.py"]
Docker Compose とマルチコンテナ管理
Development Compose
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
environment:
DATABASE_URL: postgresql://postgres@db/myapp
DEBUG: "true"
depends_on:
- db
volumes:
- .:/app
db:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp
ports:
- "5432:5432"
Production Compose
version: '3.8'
services:
app:
image: registry.example.com/myapp:1.2.3@sha256:abc...
restart: always
environment:
DATABASE_URL: postgresql://user@db.internal/myapp
DEBUG: "false"
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 3s
retries: 3
db:
image: postgres:15-alpine@sha256:xyz...
restart: always
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 10s
timeout: 3s
retries: 3
secrets:
db_password:
file: /run/secrets/db_password.txt
よくあるエラーと対策
| エラー | 原因 | 対策 |
|---|---|---|
no space left on device |
Image が大きすぎる | Multi-stage build で runtime を削減 |
permission denied |
Root 以外で実行不可 | USER で非root ユーザに切り替え |
entrypoint is not a shell |
ENTRYPOINT で sh/bash が必須 | ENTRYPOINT を shell 形式で記述 |
dependency not found |
Package manager のキャッシュ古い | --no-cache で cache を無視 |
Dockerfile Linting
hadolint
hadolint Dockerfile
# Output:
# DL3007 warning: Using latest is prone to errors
# DL3009 warning: Delete the apt-get lists after installing
まとめ
Dockerfileは、動くimageを作るだけのファイルではありません。layerとcacheを意識し、multi-stage buildでruntimeを小さくし、非root実行とsecret分離を徹底すると、運用しやすいimageになります。さらに、build context、base image、digest、scan、SBOMまで含めて考えると、Dockerfileはsupply chainの入口としてレビューできるようになります。