Distrolessで、運用コストの低いDockerイメージを作る
Googleが公開しているDistrolessは、アプリケーションの実行に特化したDockerイメージで、パッケージマネージャやシェル、その他不要なプログラムを含まないのが特徴です。
余分なものが含まれないため、セキュリティスキャン結果のノイズが少なくなる、運用コストが減るなどのメリットが考えられます。
本記事では、このDistorolessをベースに、Goで書かれたHello Worldアプリの実行用イメージを作ってみます。
2018年11月現在、PythonやNode.jsといった言語用のイメージは実験的なステータスとなっています。実験的とされていないのは、GoやRust、Javaなどの言語用イメージのみです。
hello.go
まずは、Hello Worldアプリのソースです。よくある内容ですね。
$ cat hello.go
package mainimport "fmt"func main() {
fmt.Println("Hello, world")
}
Dockerfile
そして、Dockerfileです。まずアプリビルド用のイメージで go install
し、その結果をDistrolessベースのイメージにコピーしています。
$ cat Dockerfile
FROM golang:1.8 as build
WORKDIR /go/src/hello
COPY hello.go .
RUN go installFROM gcr.io/distroless/base
COPY --from=build /go/bin/hello /
CMD ["/hello"]
ビルドして実行
上記のDockerfileを使い、イメージをビルドして実行してみます。
$ docker build -t distroless-hello .$ docker run -t distroless-hello
Hello, world
はい、意図通り Hello, world
と出力されました。
コンテナのシェルに入るには
Distrolessにはシェルが含まれないため、コンテナのシェルに入るには、デバッグ用のイメージ (:debug
) を使う必要があります。
$ cat Dockerfile-debug
FROM golang:1.8 as build
WORKDIR /go/src/hello
COPY hello.go .
RUN go installFROM gcr.io/distroless/base:debug
COPY --from=build /go/bin/hello /
CMD ["/hello"]
シェルに入ってみる
シェルに入るには --entrypoint=sh
を指定します。
$ docker build -t distroless-hello-debug -f Dockerfile-debug .$ docker run --entrypoint=sh -ti distroless-hello-debug
/ # ls -l
total 1532
drwxr-xr-x 2 root root 6 Jan 1 1970 bin
drwxr-xr-x 2 root root 6 Jan 1 1970 boot
drwxr-xr-x 2 root root 12288 Nov 28 05:17 busybox
drwxr-xr-x 5 root root 360 Nov 28 05:36 dev
drwxr-xr-x 1 root root 66 Nov 28 05:36 etc
-rwxr-xr-x 1 root root 1551621 Nov 28 05:15 hello
drwx------ 1 root root 26 Nov 28 05:36 home
drwxr-xr-x 3 root root 30 Nov 28 05:17 lib
drwxr-xr-x 2 root root 34 Nov 28 05:17 lib64
dr-xr-xr-x 113 root root 0 Nov 28 05:36 proc
drwx------ 2 root root 6 Jan 1 1970 root
drwxr-xr-x 2 root root 6 Jan 1 1970 run
drwxr-xr-x 2 root root 6 Jan 1 1970 sbin
dr-xr-xr-x 13 root root 0 Nov 28 05:36 sys
drwxrwxrwt 2 root root 6 Jan 1 1970 tmp
drwxr-xr-x 9 root root 92 Nov 28 05:17 usr
drwxr-xr-x 11 root root 116 Nov 28 05:17 var
Alpine Linuxイメージとのサイズ比較
参考のため、Alpineベースのイメージとのサイズを比較してみます。
Distroless: 18.4MB
$ docker images distroless-hello --format "{{.Size}}"
18.4MB
Alpine: 5.96MB
$ cat Dockerfile-alpine
FROM golang:1.8 as build
WORKDIR /go/src/hello
COPY hello.go .
RUN go installFROM alpine
COPY --from=build /go/bin/hello /
CMD ["/hello"]$ docker run -t distroless-hello-alpine
Hello, world$ docker images distroless-hello-alpine --format "{{.Size}}"
5.96MB
意外にも、Alpineベースのほうが小さいですね。サイズが重要な場合、現状ではAlpineが無難だといえます。
まとめ
本記事では、Distrolessを使い、アプリケーションの実行に特化したイメージを作ってみました。運用コストが抑えられるので、マッチするユースケースがあれば、ぜひプロダクション環境で使ってみたいところです。
なお、下記のGitHubリポジトリに本記事で使ったファイルをまとめています。よろしければご利用ください。