Help us understand the problem. What is going on with this article?

簡単にできるDockerイメージのダウンサイジング

概要

Dockerイメージのサイズが大きくなるとレジストリにPushやPullする時間が増します
運用環境や開発環境でイメージのやり取りを繰り返される場合は、回数を重ねるごとにバカにならないほどの待ち時間が発生することになる
また、ネットワーク帯域も無駄に消費します
なので、簡単にできるイメージサイズのダウンサイジングをご紹介します
下記のサンプルでは1.04GBのイメージ ⇒ 415MBまでにダウンサイジングしています
もし、下記以外にもダウンサイジングの方法がありましたら、ご教示ください!

以下のサンプルコードでは、差を分かりやすくするためにあえてjdkをダウンロードし、所有権を変更しています
なお、イメージのリビルド時にキャッシュの有効利用は考慮していません

おさらい

Dockerイメージはビルド時にDockerfileの各コマンドごとに中間イメージが作成される
各中間イメージにはそのコマンドで実行された変更履歴が含まれます
各コマンドが実行され、生成された中間イメージは以下のようになります
docker image layer.png

最適化していない状態

まず、なにも最適化していないDockerfileでビルドされたイメージサイズは1.04GBもあります!

Dockerfile
FROM node:12-slim

WORKDIR /tmp

RUN wget https://download.java.net/java/GA/jdk12.0.2/e482c34c86bd4bf8b56c0b35558996b9/10/GPL/openjdk-12.0.2_linux-x64_bin.tar.gz
RUN tar -zxvf ./openjdk-12.0.2_linux-x64_bin.tar.gz
RUN chown node:node -R /tmp/jdk-12.0.2/

RUN apt-get update -y
RUN apt-get upgrade -y

historyコマンドで中間イメージの容量を確認していきましょう
jdkの取得やファイル解凍で容量を消費しているのはわかりやすいのですが、
chownのようにファイルのメタデータ(所有権)の変更分も容量を消費します
ここは案外見落としがちなポイントです

> docker build -t downsize:1 ./

-----------------------------------------------------------------------------------------------------------
REPOSITORY      TAG                       IMAGE ID            CREATED              SIZE
downsize        1                         e7d7b8b217ba        About a minute ago   1.04GB


> docker history downsize:1

-----------------------------------------------------------------------------------------------------------
IMAGE               CREATED             CREATED BY                                      SIZE
e7d7b8b217ba        2 minutes ago       /bin/sh -c apt-get upgrade -y                   3.85MB
f70cff27b81a        2 minutes ago       /bin/sh -c apt-get update -y                    16.4MB
ce460fc686bc        2 minutes ago       /bin/sh -c chown node:node -R /tmp/jdk-12.0.…   335MB
29b8fb0905ac        2 minutes ago       /bin/sh -c tar -zxvf ./openjdk-12.0.2_linux-…   335MB
39545720b094        3 minutes ago       /bin/sh -c wget https://download.java.net/ja…   198MB
48b8f4c4641a        3 minutes ago       /bin/sh -c #(nop) WORKDIR /tmp                  0B
710340b3b82e        2 months ago        /bin/sh -c #(nop)  CMD ["node"]                 0B
<missing>           2 months ago        /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<missing>           2 months ago        /bin/sh -c #(nop) COPY file:238737301d473041…   116B
<missing>           2 months ago        /bin/sh -c set -ex   && for key in     6A010…   5.08MB
<missing>           2 months ago        /bin/sh -c #(nop)  ENV YARN_VERSION=1.16.0      0B
<missing>           2 months ago        /bin/sh -c buildDeps='xz-utils'     && ARCH=…   90.4MB
<missing>           2 months ago        /bin/sh -c #(nop)  ENV NODE_VERSION=12.6.0      0B
<missing>           2 months ago        /bin/sh -c groupadd --gid 1000 node   && use…   333kB
<missing>           2 months ago        /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 months ago        /bin/sh -c #(nop) ADD file:5ffb798d64089418e…   55.3MB

コマンドをまとめる

各コマンドをすべてひとつのRUNにまとめることで一連のコマンドで発生した履歴も1つになる
中間イメージが減る分容量消費も抑えられる
結果的に300MB減の704MBになりました

Dockerfile
FROM node:12-slim

WORKDIR /tmp

RUN wget https://download.java.net/java/GA/jdk12.0.2/e482c34c86bd4bf8b56c0b35558996b9/10/GPL/openjdk-12.0.2_linux-x64_bin.tar.gz \
    && tar -zxvf ./openjdk-12.0.2_linux-x64_bin.tar.gz \
    && chown node:node -R /tmp/jdk-12.0.2/ \
    && apt-get update -y \
    && apt-get upgrade -y
> docker build -t downsize:2 ./

-----------------------------------------------------------------------------------------------------------
REPOSITORY      TAG                       IMAGE ID            CREATED              SIZE
downsize        2                         30a607b1a778        About a minute ago   704MB

> docker history downsize:2

-----------------------------------------------------------------------------------------------------------
IMAGE               CREATED             CREATED BY                                      SIZE    
30a607b1a778        2 minutes ago       /bin/sh -c wget https://download.java.net/ja…   553MB
48b8f4c4641a        7 minutes ago       /bin/sh -c #(nop) WORKDIR /tmp                  0B
710340b3b82e        2 months ago        /bin/sh -c #(nop)  CMD ["node"]                 0B
<missing>           2 months ago        /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<missing>           2 months ago        /bin/sh -c #(nop) COPY file:238737301d473041…   116B
<missing>           2 months ago        /bin/sh -c set -ex   && for key in     6A010…   5.08MB
<missing>           2 months ago        /bin/sh -c #(nop)  ENV YARN_VERSION=1.16.0      0B
<missing>           2 months ago        /bin/sh -c buildDeps='xz-utils'     && ARCH=…   90.4MB
<missing>           2 months ago        /bin/sh -c #(nop)  ENV NODE_VERSION=12.6.0      0B
<missing>           2 months ago        /bin/sh -c groupadd --gid 1000 node   && use…   333kB
<missing>           2 months ago        /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 months ago        /bin/sh -c #(nop) ADD file:5ffb798d64089418e…   55.3MB

一時ファイルを削除する

これも忘れがちですが、一時ファイルを削除するだけでサイズ減に繋がる
上記のコマンドに rm -f ./openjdk-12.0.2_linux-x64_bin.tar.gz を追加しただけで、
さらに200MB減の506MBになりました

Dockerfile
FROM alpine

WORKDIR /tmp

RUN wget https://download.java.net/java/GA/jdk12.0.2/e482c34c86bd4bf8b56c0b35558996b9/10/GPL/openjdk-12.0.2_linux-x64_bin.tar.gz \
    && tar -zxvf ./openjdk-12.0.2_linux-x64_bin.tar.gz \
    && chown postgres:postgres -R /tmp/jdk-12.0.2/ \
    && rm -f ./openjdk-12.0.2_linux-x64_bin.tar.gz

openjdk-12.0.2_linux-x64_bin.tar.gz分のサイズが減った!

> docker build -t downsize:3 ./

-----------------------------------------------------------------------------------------------------------
REPOSITORY      TAG                       IMAGE ID            CREATED              SIZE
downsize        2                         92986480403b        About a minute ago   506MB

> docker history downsize:3
-----------------------------------------------------------------------------------------------------------
IMAGE               CREATED             CREATED BY                                      SIZE
92986480403b        4 seconds ago       /bin/sh -c wget https://download.java.net/ja…   355MB
48b8f4c4641a        9 minutes ago       /bin/sh -c #(nop) WORKDIR /tmp                  0B
710340b3b82e        2 months ago        /bin/sh -c #(nop)  CMD ["node"]                 0B
<missing>           2 months ago        /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<missing>           2 months ago        /bin/sh -c #(nop) COPY file:238737301d473041…   116B
<missing>           2 months ago        /bin/sh -c set -ex   && for key in     6A010…   5.08MB
<missing>           2 months ago        /bin/sh -c #(nop)  ENV YARN_VERSION=1.16.0      0B
<missing>           2 months ago        /bin/sh -c buildDeps='xz-utils'     && ARCH=…   90.4MB
<missing>           2 months ago        /bin/sh -c #(nop)  ENV NODE_VERSION=12.6.0      0B
<missing>           2 months ago        /bin/sh -c groupadd --gid 1000 node   && use…   333kB
<missing>           2 months ago        /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 months ago        /bin/sh -c #(nop) ADD file:5ffb798d64089418e…   55.3MB

これだと減らないので注意!

コマンドを分けることでIMAGE ID:30a607b1a778の結果は553MBのままなので、そのまま中間イメージとして加算される

Dockerfile
FROM node:12-slim

WORKDIR /tmp

RUN wget https://download.java.net/java/GA/jdk12.0.2/e482c34c86bd4bf8b56c0b35558996b9/10/GPL/openjdk-12.0.2_linux-x64_bin.tar.gz \
    && tar -zxvf ./openjdk-12.0.2_linux-x64_bin.tar.gz \
    && chown node:node -R /tmp/jdk-12.0.2/ \
    && apt-get update -y \
    && apt-get upgrade -y

RUN rm -f ./openjdk-12.0.2_linux-x64_bin.tar.gz
> docker build -t downsize:3.1 ./

-----------------------------------------------------------------------------------------------------------
REPOSITORY      TAG                       IMAGE ID            CREATED              SIZE
downsize        3.1                       4ee2a610be24        About a minute ago   704MB

> docker history downsize:3.1
-----------------------------------------------------------------------------------------------------------
IMAGE               CREATED             CREATED BY                                      SIZE
4ee2a610be24        About a minute ago   /bin/sh -c rm -f ./openjdk-12.0.2_linux-x64_…   0B
30a607b1a778        8 minutes ago        /bin/sh -c wget https://download.java.net/ja…   553MB
48b8f4c4641a        13 minutes ago       /bin/sh -c #(nop) WORKDIR /tmp                  0B
710340b3b82e        2 months ago         /bin/sh -c #(nop)  CMD ["node"]                 0B
<missing>           2 months ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<missing>           2 months ago         /bin/sh -c #(nop) COPY file:238737301d473041…   116B
<missing>           2 months ago         /bin/sh -c set -ex   && for key in     6A010…   5.08MB
<missing>           2 months ago         /bin/sh -c #(nop)  ENV YARN_VERSION=1.16.0      0B
<missing>           2 months ago         /bin/sh -c buildDeps='xz-utils'     && ARCH=…   90.4MB
<missing>           2 months ago         /bin/sh -c #(nop)  ENV NODE_VERSION=12.6.0      0B
<missing>           2 months ago         /bin/sh -c groupadd --gid 1000 node   && use…   333kB
<missing>           2 months ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 months ago         /bin/sh -c #(nop) ADD file:5ffb798d64089418e…   55.3MB

マルチステージング化

今回のサンプルでは残念ながらサイズ減にはならなかったが、
中間イメージサイズの起算が COPY --from=base /tmp/jdk-12.0.2 /tmp/jdk-12.0.2になりますので、
事前処理であれこれ(ソースのコンパイルなど)した場合は、マルチステージング化することで簡単に容量減に繋がります

Dockerfile
FROM node:12-slim as base

WORKDIR /tmp

RUN wget https://download.java.net/java/GA/jdk12.0.2/e482c34c86bd4bf8b56c0b35558996b9/10/GPL/openjdk-12.0.2_linux-x64_bin.tar.gz \
    && tar -zxvf ./openjdk-12.0.2_linux-x64_bin.tar.gz \
    && chown node:node -R /tmp/jdk-12.0.2/

FROM node:12-slim

COPY --from=base /tmp/jdk-12.0.2 /tmp/jdk-12.0.2

RUN apt-get update -y \
    && apt-get upgrade -y
> docker build -t downsize:4 ./
-----------------------------------------------------------------------------------------------------------
REPOSITORY      TAG                       IMAGE ID            CREATED              SIZE
downsize        4                       593b49b2ed5e        About a minute ago     506MB

> docker history downsize:4
-----------------------------------------------------------------------------------------------------------
IMAGE               CREATED             CREATED BY                                      SIZE
593b49b2ed5e        12 minutes ago      /bin/sh -c apt-get update -y     && apt-get …   20.3MB
f5659402be7a        12 minutes ago      /bin/sh -c #(nop) COPY dir:523c1f51e78e02aa1…   335MB
710340b3b82e        2 months ago        /bin/sh -c #(nop)  CMD ["node"]                 0B
<missing>           2 months ago        /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<missing>           2 months ago        /bin/sh -c #(nop) COPY file:238737301d473041…   116B
<missing>           2 months ago        /bin/sh -c set -ex   && for key in     6A010…   5.08MB
<missing>           2 months ago        /bin/sh -c #(nop)  ENV YARN_VERSION=1.16.0      0B
<missing>           2 months ago        /bin/sh -c buildDeps='xz-utils'     && ARCH=…   90.4MB
<missing>           2 months ago        /bin/sh -c #(nop)  ENV NODE_VERSION=12.6.0      0B
<missing>           2 months ago        /bin/sh -c groupadd --gid 1000 node   && use…   333kB
<missing>           2 months ago        /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 months ago        /bin/sh -c #(nop) ADD file:5ffb798d64089418e…   55.3MB

パッケージマネージャのキャッシュを削除

これも忘れがちなのですが、パッケージマネージャのキャッシュを削除することで容量減に繋がります
さらに20MB減の490MBになりました

Dockerfile
FROM node:12-slim as base

WORKDIR /tmp

RUN wget https://download.java.net/java/GA/jdk12.0.2/e482c34c86bd4bf8b56c0b35558996b9/10/GPL/openjdk-12.0.2_linux-x64_bin.tar.gz \
    && tar -zxvf ./openjdk-12.0.2_linux-x64_bin.tar.gz \
    && chown node:node -R /tmp/jdk-12.0.2/

FROM node:12-slim

COPY --from=base /tmp/jdk-12.0.2 /tmp/jdk-12.0.2

RUN apt-get update -y \
    && apt-get upgrade -y \
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*
> docker build -t downsize:5 ./
-----------------------------------------------------------------------------------------------------------
REPOSITORY      TAG                       IMAGE ID            CREATED              SIZE
downsize        5                       6de3a6ddead6          About a minute ago   490MB

> docker history downsize:5
-----------------------------------------------------------------------------------------------------------
IMAGE               CREATED              CREATED BY                                      SIZE
6de3a6ddead6        About a minute ago   /bin/sh -c apt-get update -y     && apt-get …   3.85MB
f5659402be7a        12 minutes ago       /bin/sh -c #(nop) COPY dir:523c1f51e78e02aa1…   335MB
710340b3b82e        2 months ago         /bin/sh -c #(nop)  CMD ["node"]                 0B
<missing>           2 months ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<missing>           2 months ago         /bin/sh -c #(nop) COPY file:238737301d473041…   116B
<missing>           2 months ago         /bin/sh -c set -ex   && for key in     6A010…   5.08MB
<missing>           2 months ago         /bin/sh -c #(nop)  ENV YARN_VERSION=1.16.0      0B
<missing>           2 months ago         /bin/sh -c buildDeps='xz-utils'     && ARCH=…   90.4MB
<missing>           2 months ago         /bin/sh -c #(nop)  ENV NODE_VERSION=12.6.0      0B
<missing>           2 months ago         /bin/sh -c groupadd --gid 1000 node   && use…   333kB
<missing>           2 months ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 months ago         /bin/sh -c #(nop) ADD file:5ffb798d64089418e…   55.3MB

スリムなベースイメージを使う

上記のサンプルだとベースイメージにDebian系を使用していますが、超軽量なAlpine Linuxを使用することで劇的にサイズ減が図れます
ただし下記のnode:12-alpineはNode.js込みのため、さほどサイズ減につながりませんが、素のAlpine Linuxだと5.53MB !

Dockerfile
FROM node:12-alpine as base

WORKDIR /tmp

RUN wget https://download.java.net/java/GA/jdk12.0.2/e482c34c86bd4bf8b56c0b35558996b9/10/GPL/openjdk-12.0.2_linux-x64_bin.tar.gz \
    && tar -zxvf ./openjdk-12.0.2_linux-x64_bin.tar.gz \
    && chown node:node -R /tmp/jdk-12.0.2/

FROM node:12-alpine

COPY --from=base /tmp/jdk-12.0.2 /tmp/jdk-12.0.2

RUN apk update \
    && apk upgrade \
    && rm -rf /var/cache/apk/*
> docker build -t downsize:6 ./
-----------------------------------------------------------------------------------------------------------
REPOSITORY      TAG                       IMAGE ID            CREATED              SIZE
downsize        6                       2389f4627226          About a minute ago   415MB

> docker history downsize:5
-----------------------------------------------------------------------------------------------------------
IMAGE               CREATED              CREATED BY                                      SIZE
2389f4627226        About a minute ago   RUN /bin/sh -c apk update     && apk upgrade…   22.1kB
<missing>           About a minute ago   COPY /tmp/jdk-12.0.2 /tmp/jdk-12.0.2 # build…   335MB
<missing>           3 days ago           /bin/sh -c #(nop)  CMD ["node"]                 0B
<missing>           3 days ago           /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<missing>           3 days ago           /bin/sh -c #(nop) COPY file:238737301d473041…   116B
<missing>           3 days ago           /bin/sh -c apk add --no-cache --virtual .bui…   5.5MB
<missing>           3 days ago           /bin/sh -c #(nop)  ENV YARN_VERSION=1.17.3      0B
<missing>           3 days ago           /bin/sh -c addgroup -g 1000 node     && addu…   69.3MB
<missing>           3 days ago           /bin/sh -c #(nop)  ENV NODE_VERSION=12.10.0     0B
<missing>           4 months ago         /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>           4 months ago         /bin/sh -c #(nop) ADD file:a86aea1f3a7d68f6a…   5.53MB
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away