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-jdkssh 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番目イメージになるので、イメージの軽量化になる。 ミニマルでキャッシュフレンドリーなイメージを作っていきましょう。