LoginSignup
48
48

More than 5 years have passed since last update.

Dockerイメージを軽量化する

Last updated at Posted at 2018-09-13

Dockerfileを工夫して、Dockerイメージを軽量化する

最近、Dockerを使い始めました。まずはDockerfileをゴリゴリ書いていたんですが、書いているうちに軽量化のテクニックを知っているかどうかで最終的にできるDockerイメージのサイズが劇的に変わることがわかったので、ここにそのテクニックをまとめてみようと思います。

ちなみに、Dockerイメージのサイズが小さくなると以下のようなメリットがあります。

  • ホストのディスク容量を圧迫しない
  • イメージの配布が効率的に行える

今回のお題

今回は人気サンドボックスゲーム Minecraft向けのオープンソースサーバーであるSpigotのDockerイメージを作成します。

記事中ではDockerイメージの作成で一般的に使えるテクニックについて解説するため、Minecraftに全く興味がない方も安心してご覧ください。

Spigotのビルド方法は以下を参考にしています。

BuildTools | SpigotMC

注意:Spigotは権利関係の事情により、ビルド済み実行ファイルを配布することができません。(詳しい経緯は以下が参考になるかと思います。)Dockerイメージでの配布も同様に問題になると考えられるため、Docker Hub等で公開しません。

DMCA - Bukkit Spigot Japan Wiki

まずは思いついたままに作る

とりあえず、一番単純なDockerfileを書いてみたら、どれぐらいのイメージサイズになるのか確認してみます。

以下のDockerfileをビルドすると、イメージサイズは1.24GBになりました。かなり大きいですね。

FROM openjdk:8-jdk

ENV SPIGOT_VER 1.12.2

WORKDIR /minecraft
RUN wget "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar" -O BuildTools.jar
RUN java -jar BuildTools.jar –rev $SPIGOT_VER

WORKDIR /data
RUN echo "eula=true" > ./eula.txt

EXPOSE 25565
ENTRYPOINT java -jar /minecraft/spigot-${SPIGOT_VER}.jar nogui

軽量イメージを使用する

openjdk:8-jdk イメージはDebianを基に作られていますが、Javaを実行するだけならDebianに付随する多くのソフトウェアは必要ありません。そこで、最小限の機能を備えた軽量OSを基に作られたイメージを利用します。この用途にはAlpine Linuxが使われることが多く、openjdkのAlpine Linux版イメージもDocker Hubで公開されているため、今回はこれを使ってみます。

Alpine Linuxにはgit等も入っていないため、必要であれば随時インストールする必要があります。Alpine Linuxでは主にapkというパッケージマネージャを利用してソフトウェアをインストールします。

以下のようにAlpine Linux版のopenjdkイメージを利用してDockerfileを書き直し、ビルドしたところ、イメージサイズは734MBになりました。

FROM openjdk:8-jdk-alpine

ENV SPIGOT_VER 1.12.2

WORKDIR /minecraft
RUN apk --no-cache add git
RUN wget "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar" -O BuildTools.jar
RUN java -jar BuildTools.jar –rev $SPIGOT_VER

WORKDIR /data
RUN echo "eula=true" > ./eula.txt

EXPOSE 25565
ENTRYPOINT java -jar /minecraft/spigot-${SPIGOT_VER}.jar nogui

RUNをまとめる

docker build ではRUN, COPY, ADDを実行するたびにイメージのレイヤーを作成し、キャッシュ等に利用しています。つまり、これらの文が増えるほどイメージ内にレイヤーが作られるため、イメージサイズが大きくなってしまいます。各コマンドを && で繋げて1つのRUN文内に押し込めることで、余計なレイヤーが作られるのを防ぐことができます。

...というはずだったんだすが、この方法を使って書き直したDockerfileをビルドしてみたところ、イメージサイズは先程の方法と同じ734MBでした。おそらく、もっとビルド手順が多い場合にある程度効果が出てくると思われます。

FROM openjdk:8-jdk-alpine

ENV SPIGOT_VER 1.12.2

WORKDIR /minecraft
RUN apk --no-cache add git && \
  wget "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar" -O BuildTools.jar && \
  java -jar BuildTools.jar –rev $SPIGOT_VER && \
  mkdir /data && \
  echo "eula=true" > /data/eula.txt

WORKDIR /data

EXPOSE 25565
ENTRYPOINT java -jar /minecraft/spigot-${SPIGOT_VER}.jar nogui

マルチステージビルドを使う

今回のようにJavaソフトウェアのビルドを行う場合、ビルド時にはJDKが必要ですが、実行イメージにはJREだけ入っていれば十分です。つまり、ビルドの成果物だけをJREが入ったコンテナにコピーすればいいわけですが、これはDocker 17.05から追加されたマルチステージビルドを使うことで簡単に実現することができます。

ちなみに、マルチステージビルドを使えばビルド用のコンテナでどれだけレイヤーが作られても最終的な結果には影響がないため、先程のRUNをまとめるテクニックは使う必要がありません。

マルチステージビルドを使って書き直したDockerfileをビルドしてみたところ、イメージサイズは126MBになりました。マルチステージビルドすごい!!!

FROM openjdk:8-jdk-alpine AS build-env

ENV SPIGOT_VER 1.12.2

WORKDIR /build
RUN apk --no-cache add git
RUN wget "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar" -O BuildTools.jar
RUN java -jar BuildTools.jar –rev $SPIGOT_VER
RUN mkdir minecraft
RUN cp spigot-${SPIGOT_VER}.jar minecraft/spigot.jar
RUN mkdir data
RUN echo "eula=true" > data/eula.txt


FROM openjdk:8-jre-alpine

WORKDIR /data
COPY --from=build-env /build/minecraft /minecraft
COPY --from=build-env /build/data /data

EXPOSE 25565
ENTRYPOINT java -jar /minecraft/spigot.jar nogui

まとめ

最終的にDockerイメージのサイズを1.24GBから126MBと大幅に小さくすることができました。同じような機能を持つDockerイメージでも、ちょっとした工夫によって劇的に軽量化できるので、ぜひ皆さん参考にしてみてください。

48
48
0

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
48
48