パパエンジニアのポエム

奥さんと娘ちゃんへの愛が止まらない

Docker の multi-stage builds 試してみた

multi-stage buildsとは

まずはドキュメントから。
Use multi-stage builds | Docker Documentation

multi-stage buildsとは、アプリケーションのビルド環境と実行環境を分けることが出来る機能 っぽいです。
これは最高ですね。
今開発しているElixirアプリケーションのDockerfileでは、Elixirのビルド環境で使用したソースや、依存ライブラリを最後に削除しております。
こういう使い方してるところ多いんじゃないかなと思いますが、すべてはコンテナイメージを軽量化するためですね、以下例。

FROM elixir:1.6-alpine

-- 省略 --

# Install
RUN apk update && \
    apk upgrade && \
    apk add bash && \
    apk --no-cache add imagemagick && \
    apk --no-cache add --virtual build-dependencies build-base musl-dev && \
    mix local.hex --force && \
    mix local.rebar --force

-- 省略 --

# Delete
RUN apk del --purge build-dependencies && \
    rm -f opt/app/.mix && \
    cp ${TARBALL} ${APP}.tar.gz && \
    ls | grep -v ${APP}.tar.gz | xargs rm -r && \
    tar xfz ${APP}.tar.gz && \
    rm -f ${APP}.tar.gz

Golangで試す

yuki-toida.hatenablog.com

前回Golangで作ったmp4連結アプリのDockerfileをmulti-stage builds で書いてみます。

FROM golang:latest as builder
WORKDIR /go/src/github.com/yuki-toida/video-concater/
COPY . .
RUN go get -u github.com/golang/dep/cmd/dep && \
    dep ensure -v && \
    CGO_ENABLED=0 GOOS=linux ENV=dev go build -o app .

FROM alpine:latest
EXPOSE 8080
ENV ENV=dev \
    GOOGLE_APPLICATION_CREDENTIALS="./cred/gcs.json"
RUN apk update && \
    apk upgrade && \
    apk add --no-cache ca-certificates && \
    apk add --no-cache ffmpeg
WORKDIR /opt/app
COPY --from=builder /go/src/github.com/yuki-toida/video-concater/app .
COPY --from=builder /go/src/github.com/yuki-toida/video-concater/index.html .
COPY --from=builder /go/src/github.com/yuki-toida/video-concater/config ./config
COPY --from=builder /go/src/github.com/yuki-toida/video-concater/cred ./cred
CMD ["./app"]

いいですね。
最初のfromがビルド環境、次のfromが実行環境。
見ての通りビルド環境のイメージはgolang:latestで、実行環境のイメージはalpine:latestになってます。
実行環境ではビルド環境でビルドされた実行ファイルをCOPYしてるだけのシンプルな構成です。

まとめ

おそらく今後は基本 multi-stage builds 使うんじゃないかなというくらい良いですね。
ビルドとランタイムでは担っている責務が大きく違うので、見通しがよいmulti-stage buildsを使うのが自然ですね。