諸々で gRPC サーバを構築したりしているのですが、フロントを開発している人に gRPC サーバ + データベース一式を簡単に立ち上げられるようにしたいという思いがありました。 また、他にもシステム間連携を行う想定もあるので、できれば docker-compose に載せたい。
せっかく golang でアプリケーションを作っているので、Multi-stage build にチャレンジしてみました。
Multi-stage builds とは
Multi-stage builds を説明するためには、Multi-stage builds の前の世界観を説明する必要があります。 たとえば今回のような golang のアプリケーションを Docker で構築する場合、
- go の開発環境の入ったコンテナを作り、その中で go build を行う
- 同じコンテナで build したアプリを立ち上げる
ということをしていました。
ここで問題となるのは、本来は「アプリケーションを立ち上げる」だけのコンテナの中に、「アプリケーションをビルドする」ためのファイル群が入っていることです。 結果としてコンテナは肥大化し、軽くあるべきのコンテナが重くなり、有史以来人類は必死にコンテナイメージを小さくしようとしてきました。
Multi-stage builds は 1 つの Dockerfile の中で、あるコンテナでアプリケーションをビルドし、別のコンテナでアプリケーションを動かすということを実現します。
以下が Docker の公式 からの引用ですが、
ビルドとアプリケーションの起動が明確に分離されていることが分かります。
ビルドされたアプリケーションは、COPY --from
によってアプリ起動用コンテナ (下記の例だと、alpine:lateest
) にコピーされ、起動されます。
FROM golang:1.7.3 WORKDIR /go/src/github.com/alexellis/href-counter/ RUN go get -d -v golang.org/x/net/html COPY app.go . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=0 /go/src/github.com/alexellis/href-counter/app . CMD ["./app"]
作ってみる
というわけで、簡単につくってみました。
最初のコンテナ builder
で、alpiine ベースの golang のコンテナで Protocol Buffer をコンパイルし、gRPC サーバのアプリケーションをビルドします。
それをアプリ起動用のコンテナへコピーし、起動するということで、シンプルですね。
FROM golang:1.11.1-alpine3.8 As builder WORKDIR /go/src/github.com/kiririmode/grpc-sandbox COPY . . RUN apk --no-cache add protobuf make git RUN go get -u github.com/golang/protobuf/protoc-gen-go RUN make pb deps RUN GOOS=linux go build -o grpc-server . FROM alpine:latest WORKDIR /app COPY --from=builder /go/src/github.com/kiririmode/grpc-sandbox/grpc-server ./ EXPOSE 8000 CMD ["/app/grpc-server"]
これを docker build すると、gRPC サーバのコンテナサイズはおよそ 16 MB 足らずになりました。
$ docker system df -v | grep -B5 grpc-server Images space usage: REPOSITORY TAG IMAGE ID CREATED ago SIZE SHARED SIZE UNIQUE SiZE CONTAINERS grpc-server latest 67c54e99d8bc 7 hours ago ago 15.58MB 4.148MB 11.43MB 1n
このような Dockerfile を構成すると、docker-compose の方に組込むことで、ローカル環境で容易にシステム間連携も実現できるようになります。 便利な時代ですね。