multi-stage buildでのfreshの運用

Goで書いているWebアプリケーションをDockerイメージにするとき、multi-stage buildを使ってビルド用のイメージと実行用のイメージを分けると思う。実行用のイメージをalpine linuxベースにするとイメージのサイズが異常に小さくなる。

FROM golang as builder
ENV CGO_ENABLED 0
WORKDIR /go/src/github.com/naoty/hello

RUN curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh \
  && go get github.com/pilu/fresh

# dep
COPY Gopkg.toml Gopkg.lock /go/src/github.com/naoty/hello/
RUN dep ensure -v --vendor-only=true

COPY . /go/src/github.com/naoty/hello/
RUN make install

FROM alpine
RUN apk --no-cache add ca-certificates 
WORKDIR /root/
COPY --from=builder /go/bin/hello /root/
CMD ["./hello"]

一方で、Goの開発ではpilu/freshを使ってファイルの更新時に自動的にビルドと実行をし直したい。だけど、multi-stage buildを使っていると、実行用のイメージにはGoのビルド環境がないため、少し工夫が必要になる。

docker-composeを使うとき、targetオプションを使うとビルド用のコンテナまででビルドを中断できる。ただし、3.4からの機能なのでversionを3.4以上にする必要がある。

version: "3.4"
services:
  app:
    build:
      context: .
      target: builder
    command: ["fresh"]