How to rebuild go project efficiently while using Docker Compose?
Asked Answered
M

2

14

This may be a stupid question, but I'm new to using Docker-compose. So far, I love it... but I'm having some long build times. I have a project with several dependencies, and I need to obviously rebuild the source every time I make a change. Right now, I'm calling docker-compose build to rebuild the container, followed by a docker-compose up. The problem is:

  1. It's rebuilding the entire container for every change I make to the source code (which takes a long time -- fetching dependencies/etc). This is significantly slowing me down.

  2. I really feel like I should just be able to run a command on the container to rebuild and then re-run the executable, like-so:

    docker-compose run web go build .
    docker-compose run web ./app
    or
    docker-compose run web go build .
    docker-compose restart
    
    This should work because I'm using a volume to share code amongst the host and container. There shouldn't be a need to refetch all the dependencies. Shouldn't it use the freshly built executable? However, this does not reflect the built changes and port forwarding appears to break.

For reference, here is my Dockerfile:

FROM golang:1.8

COPY . /go/src/github.com/codeblooded/test1
WORKDIR /go/src/github.com/codeblooded/test1

RUN echo $PATH
RUN go get -d -v ./...
RUN go install -v ./...

RUN go build -o test1 .
CMD ["test1"]
EXPOSE 3470

And my docker-compose.yml file:

version: '3'
services:
  postgres:
    image: postgres
    volumes:
      - ./db/data/psql:/var/lib/postgresql/data
      - ./db/schema:/db/schema
  redis:
    image: redis
    volumes:
      - ./db/data/redis:/data
  server:
    build: .
    command: test1
    volumes:
      - .:/go/src/github.com/codeblooded/test1
    ports:
      - "3470:3470"
    depends_on:
      - postgres
      - redis

Is there something I'm missing?

Maidservant answered 11/6, 2017 at 2:28 Comment(1)
Another thing you can try to speed up your builds is to copy over intermediary build artifacts from previous Docker builds, using COPY --from. You can have a look at my article about Efficient Docker builds for large monorepos, which also covers reducing image size using multi-stage builds, and making good use of the Docker build cache.Versicolor
M
13

You have asked a good question.

The command's order in the Dockerfile really matters. Put first the things that don't change frequently, and later those that are most likely to change in every build:

FROM golang:1.8

RUN go get -d -v ./...
RUN go install -v ./...

COPY . /go/src/github.com/codeblooded/test1
WORKDIR /go/src/github.com/codeblooded/test1

RUN echo $PATH

RUN go build -o test1 .
CMD ["test1"]
EXPOSE 3470

When a layer change regarding the previous build, docker discards the following cached layers and runs them again, sometimes wasting your time.

Pay attention to the "Using cache" sentence that docker outputs in each layer that is re-used from the previous build.

Another recommendation, for your dev work, use fresh to re-build your go app automatically every time you change the code. Just install it in the container and simply using command: fresh in your docker-compose.yml

Menderes answered 11/6, 2017 at 3:21 Comment(1)
I came across this comment about fresh. Can you elaborate on how you would setup fresh?Kiger
E
4

And if you want to improve your Docker impl, you can make a smaller image. I suggest "multi-stage builds" to do that

The image size for this build is like 600mb

FROM golang:1.8

RUN go get -d -v ./...
RUN go install -v ./...

COPY . /go/src/github.com/codeblooded/test1
WORKDIR /go/src/github.com/codeblooded/test1

RUN echo $PATH

RUN go build -o test1 .
CMD ["test1"]
EXPOSE 3470

Using multi-stage builds, the image weight is the size of the binary and a scratch

FROM golang:1.8 as builder

RUN go get -d -v ./...
RUN go install -v ./...

COPY . /go/src/github.com/codeblooded/test1

WORKDIR /go/src/github.com/codeblooded/test1

RUN echo $PATH
RUN CGO_ENABLED=0 GOOS=linux go build -o test1 .


FROM alpine:latest

RUN apk --no-cache add ca-certificates

WORKDIR /go/src/github.com/codeblooded/

COPY --from=builder /go/src/github.com/codeblooded/test1 .

CMD ["test1"]

EXPOSE 3470

Using multi-stage builds you are using a heavy image for build the app and another really smaller for run your app.

Enzootic answered 1/8, 2017 at 13:42 Comment(1)
Not sure multi-stage support rebuilding binary.Adelia

© 2022 - 2024 — McMap. All rights reserved.