Dockerfile Best Practices

Dockerfile作成のベストプラクティス

Intro Guide to Dockerfile Best Practices

Docker blogにこんなのがあったので、写経ついでにざっと読む

ビルドタイム増加対策

Tips 1.Order matters for caching

from debian
COPY . /app
RUN apt-get update
RUN apt-get -y install openjdk-8-jdk ssh vim
COPY . /app
CMD [“java”, “-jar”, “/app/target/app.jar”]

Dockerfileをキャッシュを意識した順序でかく。Dockerfileが上から読まれていき(build step)、変更された行があったり、新規ファイルがあったりした場合、dockerはキャッシュを捨てるようになっているので、更新が多いものはなるべくbuild stepの最後の方に配置した方が良い。

Tip 2. More specific COPY to limit cache busts

from debian
RUN apt-get update
RUN apt-get -y install openjdk-8-jdk ssh vim
COPY . /app
COPY target/app.jar /app
CMD [“java”, “-jar”, “/app/target/app.jar”]

キャッシュ効率をよくするため、COPYするファイルは必要最低限に抑える。特定ファイルのみに指定できれば、関係ないファイル更新でキャッシュが壊れることはなくなる。

Tip 3: Identify cacheable units such as apt-get update & install

from debian
RUN apt-get update
RUN apt-get -y install openjdk-8-jdk ssh vim
RUN apt-get update && RUN apt-get -y install openjdk-8-jdk ssh vim
COPY target/app.jar /app
CMD [“java”, “-jar”, “/app/target/app.jar”]

RUNコマンド1実行ごとにキャッシュを作成しようとするので、多すぎるキャッシュの生成は不必要で、RUNコマンドをなんども書くことは、キャッシュ破壊(失敗?)を容易にし、デプロイサイクルに影響を少なくない影響を与えます。パッケージマネージャーからパッケージをインストールするときは、キャッシュを1つにまとめるため、同じRUNで実行しましょう。

Reduce Image size

Imageサイズを減らす為にやること

Tip #4: Remove unnecessary dependencies

from debian
RUN apt-get update && RUN apt-get -y install --no-install-recommends openjdk-8-jdk ssh vim
COPY target/app.jar /app
CMD [“java”, “-jar”, “/app/target/app.jar”]

不要なパッケージを入れないようにする。aptの場合recommendedなパッケージが自動でインストールされるので、–no-install-recommendsオプションをつける

Tip #5: Remove package manager cache

from debian
RUN apt-get update && RUN apt-get -y install –no-install-recommends openjdk-8-jdk && rm -rf /var/lib/apt/lists/*
COPY target/app.jar /app
CMD [“java”, “-jar”, “/app/target/app.jar”]

パッケージマネージャーのキャッシュを削除する。同じRUNコマンドないで削除を実行すること。もう一つRUNコマンドを追加してしまうとイメージサイズを減らすことにはならないので注意。

Maintainability

Tip #6: Use official images when possible

Tip #7: Use more specific tags

Tip #8: Look for minimal flavors

from debian
RUN apt-get update && RUN apt-get -y install --no-install-recommends openjdk-8-jdk && rm -rf /var/lib/apt/lists/*
from openjdk:8
COPY target/app.jar /app
CMD [“java”, “-jar”, “/app/target/app.jar”]

6,7,8はまとめて、可能ならオフィシャルのイメージを使おう。特定のタグをつけよう。タグのうち自分の環境に最適かつ小さいサイズのimageを選びましょうという話。

Reproducibility

Tip #9: Build from source in a consistent environment

from openjdk:8
FROM maven:3.6-openjek-8-alpine
WORKDIR /app
COPY app.jar /app
COPY pom.xml
COPY src ./src
RUN mvn -e -B package
CMD [“java”, “-jar”, “/app/app.jar”]

Dockerコンテナに常に同じビルド環境を作るようにすし、ソースコードからのアプリのビルドが、ホストの環境によって左右されないようにできる。

Tip #10: Fetch dependencies in a separate step

FROM maven:3.6-openjek-8-alpine
WORKDIR /app
COPY pom.xml
RUN mvn -e -B depenency:resolve
COPY src ./src
RUN mvn -e -B package
CMD [“java”, “-jar”, “/app/app.jar”]

mvnの依存関係だけのcache unitを作る。このdockerfileのばあい、RUN mvnの2つのcache unitが作成される。

Tip #11: Use multi-stage builds to remove build dependencies (recommended Dockerfile)

最後にキャッシュの削除と、実行環境の軽量化のためにmulti-stage buildsを使います。

FROM maven:3.6-openjek-8-alpine as builder
WORKDIR /app
COPY pom.xml
RUN mvn -e -B depenency:resolve
COPY src ./src
RUN mvn -e -B package
CMD ["java", "-jar", "/app/app.jar"]

FROM open-jdk:8-jre-alpine
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "app.jar"]

ビルド環境のコンテナで作成したjarファイルを実行環境用のコンテナに引き継いで実行する。最終的にできるコンテナのサイズは2番目イメージになるので、イメージの軽量化になる。 ミニマルでキャッシュフレンドリーなイメージを作っていきましょう。

connvoi's Picture

About connvoi

肉とビールと料理と写真とゲーム たまに技術 python / Solr / PHP / ansible

Jp, Tokyo https://connvoi.com