214
213

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Dockerのコンテナイメージサイズを1/10以下に軽量化してみた

Last updated at Posted at 2024-05-15

はじめに

VSCode + Python + Poetry + Docker(docker-compose)でdev-containerを作成して開発を行っていました。
Dockerを勉強し、イメージの軽量化に関する記事を読んでいると、自分が使っているコンテナイメージのサイズが気になりました。

docker images
> REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
> dev-container latest    a9b8e3df9087                    2.31GB

2.31GB!?
サーバとしてアプリを動かしていないのにここまで大きいなんて…

というわけで勉強も兼ねて、イメージの軽量化に取り組みました。

イメージが軽量であるメリット

ストレージの節約

これは言わずもがなだと思います。
限られたリソースを有効に使うことができます。

ビルド時間の短縮

Dockerは環境を作ったり壊したりが簡単なのもいいところだと思います。
ビルド時間が長いと、この恩恵を感じづらくなりますよね。

環境

OS:Ubuntu22.04
Docker: 26.1.1
Docker Compose: v2.27.0

軽量化していく

最初の状態

compose.yml
version: "3"
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    restart: always
    tty: true
    volumes:
      - type: bind
        source: ./
        target: /workspace/app
FROM python:3.11.9-slim

COPY pyproject.toml ./
# pipのアップグレード
RUN pip install --upgrade pip

# パッケージのアップグレード、インストール
RUN apt -y update && apt -y upgrade
RUN apt -y install libopencv-dev

# poetryのインストール、設定
RUN pip install poetry
RUN poetry config virtualenvs.create false \
    && poetry install --no-root

# コンテナの作業ディレクトリを作成
RUN mkdir -p /workspace/app
WORKDIR /workspace/app

EXPOSE 8888

この記事ではDockerfileしか触らないですが、compose.ymlも載せておきます。

今見るとかなり無駄な記述が多いと思います。

ベースイメージ変更、レイヤー数削減

# ベースイメージをslimからslim-bullseyeに変更
FROM python:3.11.9-slim-bullseye

# タイムゾーンを日本に設定
ENV TZ Asia/Tokyo
# COPY pyproject.toml .を削除
# 必要なパッケージ RUNコマンドを一つに結合
RUN apt update && \
    apt -y upgrade && \
    apt -y install libopencv-dev

# pipのアップグレードとpoetryのインストール
RUN pip install --upgrade pip && \
    pip install poetry

# コンテナの作業ディレクトリを作成
RUN mkdir -p /workspace/app
WORKDIR /workspace/app

# 仮想環境を作らないよう設定
RUN poetry config virtualenvs.create false

EXPOSE 8888

最初に更新後のものを載せておきます。

docker images
>REPOSITORY      TAG       IMAGE ID       CREATED          SIZE
>dev-container   latest    585f482be78b                    1.17GB

この時点でイメージサイズは約半分になりました。
変更点はベースイメージ、タイムゾーンの追加、レイヤーの削減です。
また、pyproject.tomlのコピーとパッケージインストールも作業ディレクトリをマウントするので削除しました。
※後で調査すると、コピーやpoetry installが7MBほどを占めていたようです。かなり無駄な記述をしていたと痛感しました。

イメージの軽量化に関わるのは、ベースイメージとレイヤーです。

ベースイメージ

ベースイメージはDocker Hubを使って決めました。

Docker Hubメリット

  • イメージのサイズや脆弱性のレベルや有無を確認できる
  • 公式や他の人のDockerfileを見ることができる

slimからslim-bullseyeへの変更は微々たる差ですが、slimが付いているものとそうでないものの差には驚きます。
slimは使用頻度の低いパッケージが除かれているため軽量になるそうです。

レイヤーの削減

レイヤーとはざっくり言うと、命令1つごとに作られる変更差分です。
Dockerfileでの命令コマンドRUNCOPYが実行されるたびにレイヤーが作られます。
つまり命令コマンドが多くなるとその分、変更差分が作られてしまいます。そのためイメージサイズがどんどん大きくなる原因になります。

今回はバラバラになっていたRUNコマンドをまとめたり、作業ディレクトリをマウントするため不要だったCOPYコマンドの削除など行いました。

ただし、レイヤーの削減は可読性の低下といった問題が起こり得ます。
また、本来なら複数の命令(apt updateとapt upgradeなど)をまとめて実行するので、どの処理が失敗したか分かりづらくなる可能性もあります。

マルチステージビルド

# パッケージをインストールするためのイメージ
FROM python:3.11.9-slim-bullseye as builder

# 必要なパッケージ
RUN apt-get update -q
RUN apt-get -y upgrade --no-install-recommends
RUN apt-get -y install libopencv-dev

# pipのアップグレードとpoetryのインストール
RUN pip install --upgrade pip
RUN pip install poetry

# 仮想環境を作らないよう設定
RUN poetry config virtualenvs.create false

# 実際に使用するイメージ
FROM python:3.11.9-slim-bullseye as dev
# タイムゾーンを日本に設定
ENV TZ Asia/Tokyo

# builderから必要な内容をコピー
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin

WORKDIR /workspace/app

EXPOSE 8888
docker images
>REPOSITORY      TAG       IMAGE ID       CREATED          SIZE
>dev-container   latest    585f482be78b                    188MB

一気にイメージサイズが減りました!

マルチステージビルドに伴って、レイヤーの削減をしないようにしました。

マルチステージビルドとは

Docker Engine17.05から導入された機能です。
マルチステージビルドを実行するにはFROM行を複数回記述します。
FROMのたびに新しいベースイメージを作成するビルドステージが開始され、一方の内容を他方にコピーすることができ、さらに最終イメージ以外を無視することができます。

1つ目のイメージで必要なパッケージのインストールやアップグレード、アプリのビルドなどを行い、使用したいイメージには使用するファイルやフォルダだけをコピーすることで、余分なレイヤーを作らずイメージを生成できます。

最後に

Dockerのコンテナイメージ軽量化には以下の3つが重要だとわかりました。

  • ベースイメージ
  • レイヤー削減
  • マルチステージビルド

特にマルチステージビルドは余分なレイヤーを、使わないイメージに押し付けることができるので、軽量なイメージの作成にはほぼ必須かと思いました。
他にもこんなDockerfileの作り方があるなど教えていただきたいです。

間違いがあれば指摘していただけますと幸いです。

214
213
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
214
213

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?