概要
突然ですが、Dockerfile適当に書いていませんか?
ほんの少しの工夫で、軽量になったり可読性が上がったりするので、今回はそんなTipsを紹介します。
この記事は人力で書きました。
その1 : マルチステージビルドを使う
Dockerのマルチステージビルドとは、ビルドと実行用のイメージに分割することで最終的なイメージをコンパクトにできるものです。
実際にgo
のコンテナを作成するときの例を挙げてどのようなメリットがあるか確認してみます。
FROM golang:1.25
WORKDIR /app
COPY . .
RUN go build -o myapp .
CMD ["./myapp"]
# Stage 1: Build
FROM golang:1.25 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .
# Stage 2: Run
FROM alpine:3.22.1
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]
では、実際に上記の2ファイルをbuildしてみて、どれくらいの容量差分が出てくるのか確認してみます。一旦の構成でmain.go
とgo.mod
でgoアプリを構成します。
package main
import "fmt"
func main() {
fmt.Println("Hello, Docker!")
}
module myapp
go 1.21
# それぞれbuildビルド
docker build -f Dockerfile.junior -t myapp-junior .
docker build -f Dockerfile.senior -t myapp-senior .
実際にbuildして比べてみた結果、なんと80倍も変わりました。今回小さい構成で実施したのですが、これくらいの差が出ていますが、ガッツリ使用した場合はもっと大きくなりそうですね。。
isoda@shota-mac junior % docker images | grep myapp
myapp-junior latest f1c396cf8580 41 seconds ago 888MB
myapp-senior latest eab45bab740d About a minute ago 10.8MB
その2 : ベースイメージは必ずバージョンを固定する
これを怠ると今日動いたbuildが明日動かなくなるかもしれません。
NG例
FROM golang:latest
今日、上記の記載方法でbuildが成功したとしても、明日latestが更新されたらどうなるでしょう?
急にbuildが失敗してしまうかもしれません。
OK例
FROM golang:1.25-alpine
ポイントとしては、以下になります。
- LTSの特定バージョンを明示的に指定する
- 可能なら軽量イメージ(alpineやbullseye-slimなど)を使用する
バージョン指定することで、思わぬトラブルを防ぐのとイメージの軽量化にも貢献してくれます。4倍くらいイメージ容量が変わってきますね。
isoda@shota-mac junior % docker image ls | grep golang
golang latest d7e6adee7899 7 days ago 855MB
golang 1.25-alpine 6ea50bc9f564 7 days ago 211MB
その3 : レイヤーはできるだけ減らす
続いてのポイントとしては、レイヤはできるだけ減らすということです。そうすることで以下のようなメリットがあります。
- イメージサイズ削減(不要ファイルを残さない)
- キャッシュ効率アップ(再ビルド時間の短縮)
- 配布・展開の高速化(レイヤが少ないほどpush/pullが速い)
NG例
FROM debian:bullseye
RUN apt-get -y update
RUN apt-get install -y python
OK例
FROM debian:bullseye
RUN apt-get -y update && apt-get install -y python && rm -rf /var/lib/apt/lists/*
今回の例では、イメージサイズの削減は見られませんが、大きなDockerfileになれば差も大きくなってくると思います。
isoda@shota-mac junior % docker images | grep myapp
myapp-junior latest c30825b58d07 19 seconds ago 216MB
myapp-senior latest 818501d91809 34 seconds ago 198MB
その4 : .dockerignore
を活用する
これは、.gitignore
と同じような感覚でイメージに含まないファイルを指定することができます。
例えばですが、以下のようなDockerfileがあり
COPY . /app
もしも、ディレクトリに以下のような不要なファイルが含まれていたとしたらどうでしょうか?
その不要ファイルを.dockerignore
に記載すればその分の容量を節約できます。
venv/
.git/
logs
node_modules
...etc
.dockerignore
の記載方法は簡単で、プロジェクトルートに.dockerignore
というファイルを作成して、不要なファイルを記載するだけです。
node_modules
.git
*.log
Dockerfile
...etc
※以下のようにbuild時にオプションを指定すると実際どのようなファイルが送られているか確認できるので、試してみてください。
docker build . --no-cache --progress=plain
その5 : セキュリティを意識したDockerfileを構築する
Dockerのセキュリティのベストプラクティスとして、以下の4点を意識しましょう。
- 信頼できる正しいベースイメージを使用し軽量化させる
- マルチステージビルドを使う
- イメージは定期的に再構築をする
- イメージの脆弱性を確認する
それぞれ詳しく解説していきます。
信頼できる正しいベースイメージを使用し軽量化させる
まずは、信頼できるベースイメージを使用することが大切です。
Docker Hubにはかなりの量のイメージが公開されていますが、その中でもOfficial Image
やVerified Publisher
を使用すると良いです。
Docker Official Imagesは、以下のようなマークがついています。
また、攻撃対象や脆弱性を減らすためにも、できるだけ小さなイメージ(alpine
やslim
)を使用するようにしましょう。
マルチステージビルドを使う
前述もしましたが、マルチステージビルドを活用することによって「最終イメージには 不要なツールやファイルを含めない」ということができます。
それによって、不要なツールの脆弱性を回避できたり、攻撃対象を減らすということに繋がります。
イメージは定期的に再構築をする
例えば、何年も前に構築されたイメージを使用し続ける場合もしそのイメージ内で使用しているソフトウェアの脆弱性が発見および対応された場合でも再構築しない場合、脆弱性が対応されていないイメージを使い続けることになってしまいます。
そこで、定期期的に以下のようにイメージの再構築をしましょう。
docker build --no-cache -t myImage:myTag myPath/
※--no-cache
を使用することで、キャッシュが使用されなくなります。(確実に新しいものをインストールするためにこのオプションを利用しましょう)
イメージの脆弱性を確認する
脆弱性を定期的にスキャンして、もし脆弱性が見つかった時はイメージの更新/再構築をするというのも大切です。
一番手軽に診断できるツールとしては、docker scout
があります。これは、公式から提供されているツールで、現時点では、ローカルイメージは無料でスキャンできるようです。
docker scout cves <image-name>
実際に作成したイメージに対して、動作させて出力を確認してみました。(一部割愛)
✓ Image stored for indexing
✓ Indexed 356 packages
✓ Provenance obtained from attestation
✗ Detected 29 vulnerable packages with a total of 106 vulnerabilities
## Overview
│ Analyzed Image
────────────────────┼─────────────────────────────────────────────
Target │ <image-name>:latest
digest │ XXXXXXXXXXXXX
platform │ linux/arm64
provenance │ git@github.com:XXXXXXXXXXXXX/XXXXXXXXXXXXX.git
│ XXXXXXXXXXXXXXXXXXXXXXXXXXX
vulnerabilities │ 0C 1H 3M 102L
size │ 249 MB
packages │ 356
## Packages and Vulnerabilities
0C 1H 0M 11L XXXXXXXXXXXXX XXXXXXXXXXXXX
pkg:deb/debian/XXXXXXXXXXXXX
os_distro=XXXXXXXXXXXXX
✗ HIGH CVE-2025-55154
https://scout.docker.com/v/CVE-2025-55154
Affected range : >=8:7.1.1.43+dfsg1-1
Fixed version : not fixed
--- 略 ---
106 vulnerabilities found in 29 packages
CRITICAL 0
HIGH 1
MEDIUM 3
LOW 102
What's next:
View base image update recommendations → docker scout recommendations XXXXXXXXXXXXX:latest
こういったスキャンを定期的に実行して、検出された脆弱性に対処していきましょう。
まとめ
今回紹介したTipsは、難しいものではなく日々の開発で少し意識するだけで取り入れることができると思います。振り返ると以下の5つです。
- マルチステージビルドを活用する → イメージを軽量化し、不要な依存を排除できる
- ベースイメージは必ずバージョン固定 → 再現性を高め、予期せぬビルドエラーを防ぐ
- レイヤーを減らす → キャッシュ効率やビルド速度、イメージサイズを改善
-
.dockerignore
を活用する → 不要ファイルを含めず、効率的なビルドを実現 - セキュリティを意識する → 信頼できるイメージを選び、定期的に再構築&脆弱性チェック
これらを少しずつ取り入れていくだけで、イメージは軽く・速く・安全になります。
次にDockerfileを書くときは、ぜひ一つでも試してみてください。