🐳

軽量なDockerイメージを作るために意識すること

2022/12/30に公開
2

はじめに

今まで個人開発でなんとなくDockerを触るレベルでしたが、
転職を機に実務でDockerを触れる機会が増えてきました。
なんとなく使っていたDockerへの理解を深めるためにも、
より軽量なDockerイメージの作り方についてメモします。

なぜ軽量なイメージを作るのか

  • ビルド時間の短縮
    • トライアンドエラーがしやすくなる
    • 生産性が高まる
  • Dockerイメージをpush/pullする時間の短縮
    • CI/CDにかかる時間の短縮
    • オートスケール時にかかる時間の短縮
  • ストレージの節約

軽量なDockerイメージを作るために

軽量なベースイメージを選ぶ

  • Debian
    • UbuntuなどのLinuxディストリベーションベース
    • 広く普及して安定している
    • バージョンごとに-buster(v10)や-bullseye(v11) などのコードネームがつく
  • Alpine
    • 組み込み系で多く利用されるBusyBoxベース
    • リソース効率を重視しており軽量
    • 標準Cライブラリがmuslのため、glibcとの互換性の問題が発生するケースがある
  • -slim
    • 上記のようなイメージから、使用頻度の低いライブラリを削ったもの
  • distoless
    • OSを含まずに、言語にフォーカスしたDockerイメージ
    • Googleにより公開
      • gcr.io/distroless/python3-debian11
      • gcr.io/distroless/nodejs18-debian11 など

不要なファイルをコンテナに含めない

  • Dockerfileを空のディレクトリに配置し、構築に必要なファイルだけ追加する
  • もしくは、Dockerfileと同じ階層に.dockerignoreを作成する
    • .gitなどの不要な隠しフォルダなどに注意する
.dockerignore
.git
*.log

レイヤー数を減らす

  • RUNCOPYなどの命令単位でレイヤーが作成される
  • &&\を使いコマンドを並列することで、レイヤー数を減らせる
# レイヤーが2つの場合
RUN apt update
RUN apt install -y bzr cvs git mercurial

# レイヤーが1つの場合
RUN apt update && \
    apt install -y bzr \
    cvs \
    git \
    mercurial \

頻繁に変更されるものは後に記述する

  • 変更のないレイヤーは処理をスキップすることができる
  • ソースコードのCOPYなど、頻繁に更新されるものはDockerfileの後ろ側に記述することで、ビルド内容をキャッシュできる
# キャッシュを活かせない場合(/appにソースコードが含まれる例)
COPY . /app
RUN apt update &&  apt install git

# キャッシュを活かせる場合(変更がない場合RUNのレイヤーをスキップできる)
RUN apt update &&  apt install git
COPY . /app

マルチステージビルドを活用する

  • コンテナをビルド用のコンテナと、実行用のコンテナに分ける
  • ビルド済みの軽量なコンテナのみデプロイできる(ビルド用のコンテナは破棄される)
# ビルド用のコンテナ
FROM golang:1.16 as build
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

# 実行用のコンテナ
FROM alpine:latest as prod
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=build /go/src/github.com/alexellis/href-counter/app ./
CMD ["./app"]

まとめ

軽量なDockerイメージを作るために、

  • 軽量なベースイメージを選ぶ
  • 不要なファイルをコンテナに含めない
  • レイヤー数を減らす
  • 頻繁に変更されるものは後に記述する
  • マルチステージビルドを活用する

の5つをまとめてみました。
上記以外にも有効な手段や、意識するといいことが見つかり次第、
内容追加していきたいと思います。

参考

https://docs.docker.jp/develop/develop-images/dockerfile_best-practices.html
https://blog.shinonome.io/lighter-docker-image/
https://prograshi.com/platform/docker/docker-image-tags-difference/
https://www.ted027.com/post/docker-debian-difference/
https://zenn.dev/jrsyo/articles/e42de409e62f5d
https://zenn.dev/ken3pei/articles/1abbf7d974cf5d
https://qiita.com/mumoshu/items/edd76958ea170a6b8e3d

Discussion