これは、なにをしたくて書いたもの?
前々から、DistrolessというDockerイメージが気になっていて、ちょっと試して見ることにしました。
Base Image Journey 2018 - Speaker Deck
Distroless
Distroless Dockerイメージとは、アプリケーション(というか言語)と、その依存関係のみが含まれるDockerイメージです。
"Distroless" images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.
その他のプログラムは入っておらず、シェルすらありません。よって、イメージのサイズも小さめです。
どうしてこういったイメージが存在するのかというと、不要なものを極力省くことによって、セキュリティリスクを抑えることが
できるとされています。
Why should I use distroless images?
各言語のベースとなるDockerイメージに、どんなものが含まれているかはこちらに記載があります。
https://github.com/GoogleContainerTools/distroless/tree/master/base
- ca-certificates
- /etc/passwd (root only)
- /tmp directory
- tzdata
- glibc
- libssl
- openssl
このDockerイメージの使い方としては、シェルが含まれないので、実行対象となるファイルやスクリプトを入れたDockerイメージを作り、
ENTRYPOINTやCMDで実行対象のファイルを指定するようです。
How do I use distroless images?
例えば、Javaであれば以下のように書きます。
CMD ["main.jar"]
https://github.com/GoogleContainerTools/distroless/blob/master/examples/java/Dockerfile
ベースイメージの方では、「java -jar」が指定されています。
Distroless Dockerイメージではアプリケーションのビルドはできないので、ビルドが必要な言語の場合はマルチステージビルドを使って
別のDockerイメージでビルドした結果を使用します。
ベースとなるOSイメージは、Debianのようです。現時点では、Debian 10です。
各言語のイメージとしては、以下があります。
distroless/examples at master · GoogleContainerTools/distroless · GitHub
今回は、Java(OpenJDK)のイメージを使用してみます。
Distroless(OpenJDK)のDockerイメージ
以下のようにして、まずはDockerイメージを取得してみます。
$ docker image pull gcr.io/distroless/java:latest $ docker image pull gcr.io/distroless/java:8 $ docker image pull gcr.io/distroless/java:11
確認。
$ docker container run -it --rm gcr.io/distroless/java:latest -version openjdk version "1.8.0_232" OpenJDK Runtime Environment (build 1.8.0_232-8u232-b09-1~deb9u1-b09) OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode) $ docker container run -it --rm gcr.io/distroless/java:8 -version openjdk version "1.8.0_232" OpenJDK Runtime Environment (build 1.8.0_232-8u232-b09-1~deb9u1-b09) OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode) $ docker container run -it --rm gcr.io/distroless/java:11 -version openjdk version "11.0.5" 2019-10-15 OpenJDK Runtime Environment (build 11.0.5+10-post-Debian-1bpo91) OpenJDK 64-Bit Server VM (build 11.0.5+10-post-Debian-1bpo91, mixed mode)
latestは、JDK 8を指しているようです。細かいバージョンを指定できるタグは…なさそうです。
起動時には「java -jar」を実行しようとするので、シェルを実行することはできません。
$ docker container run -it --rm gcr.io/distroless/java:8 bash Error: Unable to access jarfile bash
イメージのサイズですが、こんな感じでした。
$ docker image ls | grep distroless gcr.io/distroless/java 8 0ca884705e30 50 years ago 125MB gcr.io/distroless/java latest 0ca884705e30 50 years ago 125MB gcr.io/distroless/java 11 032fa27b8c17 50 years ago 195MB
比較として、OpenJDKのイメージを見てみます。
$ docker image ls | grep openjdk | grep -v none | sort openjdk 11-jdk 193af7392c2e 4 days ago 606MB openjdk 11-jdk-slim 724512274dbb 4 days ago 401MB openjdk 11-jre 67edbda57bd6 4 days ago 267MB openjdk 11-jre-slim fa68260be6bf 4 days ago 204MB openjdk 8-jdk 0bfcee65c8ca 4 days ago 488MB openjdk 8-jdk-alpine a3562aa0b991 9 months ago 105MB openjdk 8-jdk-slim 4229f5fb33f9 4 days ago 284MB openjdk 8-jre 5557c40af992 4 days ago 246MB openjdk 8-jre-alpine f7a292bbb70c 9 months ago 84.9MB openjdk 8-jre-slim 9c82c74fbc96 4 days ago 184MB
Alpineほどではないですが、JREに比べるとスリムになりますね。できる限りイメージは小さくしたいけれど、Alpineを避けたい人には
Distroless Dockerイメージは有力な選択肢になるんでしょうね。
インストールされているOpenJDKは、Debianでパッケージ管理されているものみたいです。
https://github.com/GoogleContainerTools/distroless/blob/master/java/BUILD
Quarkusで試す
せっかくなので、Distroless Dockerイメージを使って、自前のイメージを作ってみましょう。
お題は、Quarkusの最小構成でいきます。1.2.0.Finalを使用します。
プロジェクトの作成。
$ curl -o app.zip 'https://code.quarkus.io/d?g=org.example&a=app&v=1.0.0&b=MAVEN&c=org.example.ExampleResource&s=&cn=code.quarkus.io' $ unzip app.zip
Dockerfileは、こんな感じで作成。
Dockerfile
FROM openjdk:8-jdk-slim AS build-env ADD ./app /app WORKDIR /app RUN ./mvnw package -DskipTests=true FROM gcr.io/distroless/java:8 COPY --from=build-env /app/target/app-1.0.0-runner.jar /app/app-1.0.0-runner.jar COPY --from=build-env /app/target/lib /app/lib WORKDIR /app CMD ["app-1.0.0-runner.jar"]
こちらを参考にしています。
https://github.com/GoogleContainerTools/distroless/blob/master/examples/java/Dockerfile
ビルド。
$ docker image build -t kazuhira/quarkus-app:latest .
起動。
$ docker container run -it --rm -p 8080:8080 kazuhira/quarkus-app:latest
確認。
$ curl localhost:8080/hello hello
OKそうですね。
くどいようですが、このイメージを使っても「docker container exec」でそのままではコンテナ内に入ることはできません。
$ docker container exec dazzling_ritchie -it bash OCI runtime exec failed: exec failed: container_linux.go:346: starting container process caused "exec: \"-it\": executable file not found in $PATH": unknown
これをやりたかったら、BusyBoxを使ったりすることになるでしょう。
とりあえず、こんな感じで。