Golang - Dockerfileの最小構成
Dockerfile
本番環境で動くGoアプリのためのミニマルdockerfileを記す。
- 実行ファイルが、軽量でセキュアなscratchイメージ上で動く
- go.modとgo.sumに従って、バージョン込みの依存パッケージをインストールする
- 依存パッケージに変更がなければ、再ビルド時のインストールにはキャッシュが使われる
FROM golang:1.14.4 as builder
WORKDIR /go/src
COPY go.mod go.sum ./
RUN go mod download
COPY ./main.go ./
ARG CGO_ENABLED=0
ARG GOOS=linux
ARG GOARCH=amd64
RUN go build \
-o /go/bin/main \
-ldflags '-s -w'
FROM scratch as runner
COPY /go/bin/main /app/main
ENTRYPOINT ["/app/main"]
補足
FROM golang:1.14.4 as builder
ベースイメージには、golangのバージョン 1.14.4 を使いbuilderと名付けた。
後でマルチステージビルドを利用して、実行ファイルをより軽量なベースイメージに移す。
本番環境で動くアプリはイメージサイズが小さく、かつ、セキュリティホールが少ないイメージが好まれる。
--
WORKDIR /go/src
/go/srcで活動することを宣言。
--
COPY go.mod go.sum ./
go.mod と go.sum をWORKDIRにCOPY。
ベストプラクティスでは、ADDではなくCOPYがを推奨されているのでCOPYを採用した。
--
RUN go mod download
go mod download
が go.mod と go.sum に従って正確にパッケージをダウンロードしてくれる。
go.mod と go.sum が以前ビルドしたイメージから変更が無ければ、このレイヤーの処理に対してキャッシュを使って高速に処理される。
--
COPY ./main.go ./
main.goを、イメージ内のWORKDIRにCOPY。
今回はmain.goというファイル一つだけをCOPYしているが、依存パッケージがあればそれらもCOPYする。
この辺りは不必要なものは.dockerignoreで指定して、COPY . ./
で必要なものを一気にCOPYするなどの工夫で楽にしても良い。
--
ARG CGO_ENABLED=0
CGO_ENABLEDを0に設定。
Goはコンパイル時に、CGOを使ってC言語のライブラリを使うように設定する事ができる。
しかし、scratchイメージにはこのライブラリは用意されていない。
よって、今回はC言語のライブラリを使って欲しく無いので、CGO_ENABLEDを0にしてこの機能をOFFにした。
--
ARG GOOS=linux
GOOS=linuxを設定。
Goはクロスコンパイルを採用していて、実行環境を指定できる。
今回はscratchイメージで動かすので、linuxを宣言した。
--
ARG GOARCH=amd64
GOARCH=amd64を設定
amdの64Bitを宣言した。
--
RUN go build \
-o /go/bin/main \
-ldflags '-s -w'
アプリのビルド。
オプションに関して
- -o /go/bin/main: 実行ファイルを/go/binの中にmainという名前で作成する
- -ldflags '-s -w': 実行ファイルにアプリの動作に関係ないものを入れないためのオプションを付与
--
FROM scratch as runner
本番環境でのベースイメージを用意し、runnerと名付けた。
--
COPY /go/bin/main /app/main
builderイメージの/go/bin/mainを、runnerの/app/mainにCOPYした。
--
ENTRYPOINT ["/app/main"]
このdockerイメージを起動したときのエントリーポイントを指定。
Discussion