2

I'm doing a multi-stage Docker build:

# Dockerfile

########## Build stage ##########
FROM golang:1.10 as build

ENV TEMP /go/src/github.com/my-id/my-go-project
WORKDIR $TEMP
COPY . .
RUN make build

########## Final stage ##########
FROM alpine:3.4

# ...
ENV HOME /home/$USER
ENV TEMP /go/src/github.com/my-id/my-go-project

COPY --from=build $TEMP/bin/my-daemon $HOME/bin/
RUN chown -R $USER:$GROUP $HOME

USER $USER
ENTRYPOINT ["my-daemon"]

and the Makefile contains in part:

build: bin
        go build -v -o bin/my-daemon cmd/my-daemon/main.go

bin:
        mkdir $@

This all works just fine with a docker build.


Now I want to use Codeship, so I have:

# codeship-services.yml
cachemanager:
  build:
    image: my-daemon
    dockerfile: Dockerfile

and:

# codeship-steps.yml
- name: my-daemon build
  tag: master
  service: my-service
  command: true

The issue is if I do jet steps --master, it builds everything OK, but then runs the container as if I did a docker run. Why? I don't want it to do that.

It's as if I would have to have two separate Dockerfiles: one only for the build stage and one only for the run stage and use the former with jet. But then this defeats the point of Docker multi-stage builds.

Paul J. Lucas
  • 6,895
  • 6
  • 44
  • 88

1 Answers1

1

I was able to solve this problem using multi-stage builds split into two different files following this guide: https://documentation.codeship.com/pro/common-issues/caching-multi-stage-dockerfile/

Basically, you'll take your existing Dockerfile and split it into two files like so, with the second referencing the first:

# Dockerfile.build-stage
FROM golang:1.10 as build-stage

ENV TEMP /go/src/github.com/my-id/my-go-project
WORKDIR $TEMP
COPY . .
RUN make build
# Dockerfile
FROM build-stage as build-stage

FROM alpine:3.4

# ...
ENV HOME /home/$USER
ENV TEMP /go/src/github.com/my-id/my-go-project

COPY --from=build $TEMP/bin/my-daemon $HOME/bin/
RUN chown -R $USER:$GROUP $HOME

USER $USER
ENTRYPOINT ["my-daemon"]

Then, in your codeship-service.yml file:

# codeship-services.yml
cachemanager-build:
  build:
    dockerfile: Dockerfile.build-stage
cachemanager-app:
  build:
    image: my-daemon
    dockerfile: Dockerfile

And in your codeship-steps.yml file:

# codeship-steps.yml
- name: cachemanager build
  tag: master
  service: cachemanager-build
  command: <here you can run tests or linting>
- name: publish to registry
  tag: master
  service: cachemanager-app
  ...

I don't think you want to actually run the Dockerfile because it will start your app. We use the second stage to push a smaller build to an image registry.

mikefrey
  • 4,653
  • 3
  • 29
  • 40