3

I have 2 Dockerfile, 1 for dev, and 1 for prod:

PROD:

FROM golang AS builder
WORKDIR /go/src/gitlab.com/company/project
COPY . .
RUN go build -o ./release/api .

FROM scratch
EXPOSE 9999
COPY --from=builder /go/src/gitlab.com/company/project/release/api .
CMD ["./api"]

and DEV:

FROM golang
WORKDIR /go/src/gitlab.com/company/PROJECT
COPY . .
RUN go build -o ./release/api .
CMD ["./release/api"]

I would like to merge those two into a single one, as maintaining 2 Dockerfile is a bad practice

The main difference is that in dev, I work on golang image, which is practical, and in prod, I work with scratch image, which reduce a lot the size of my binary.

It seems that I can use multiple stages in a Dockerfile, and specify stage name at build time:

docker build . --target=builder

But If I do this, I don't know how to conditionnaly run my app in the first stage = [ If I am in dev, run the app in the first stage, otherwise, run the app in the second stage]

How should I do it ?

Juliatzin
  • 18,455
  • 40
  • 166
  • 325
  • Just as a question, is there any reason why you would want to have two different images as a base for test and prod? One of the main reasons for using Docker in the first place is that the underlying os and dependencies on the image are the same for each environment. – Blokje5 May 13 '19 at 13:22
  • 1
    well, I wouldn't like to develop on a scratch image, there is nothing in it, not very practical. and I don't want golang image in production because it is too big. – Juliatzin May 13 '19 at 13:24
  • Possible duplicate of [How to configure different dockerfile for development and production](https://stackoverflow.com/questions/46440909/how-to-configure-different-dockerfile-for-development-and-production) – Murtaza Hussain May 13 '19 at 14:50
  • Why not just install the Go toolchain on your host, and use that for development? – David Maze May 14 '19 at 12:06

1 Answers1

2

What about something like this? I didn't test it and didn't think through your example deeply, but maybe is somewhere close to what you need/helps you finding out the final solution?

FROM golang:alpine AS base
WORKDIR /go/src/gitlab.com/company/project
COPY . .
RUN go build -o ./release/api .

FROM base AS dev
CMD ["./release/api"]

FROM scratch AS prod
EXPOSE 9999
COPY --from=base /go/src/gitlab.com/company/project/release/api .
CMD ["./api"]

Depending on the value specified in target docker build --target=prod or docker build --target=dev, a different image will get built.

Javier Aviles
  • 7,952
  • 2
  • 22
  • 28
  • 1
    It did the trick ! I didn't use FROM ${BUILD_ENVIRONMENT}, but I use docker build --target=prod... to build prod, and docker build --target=dev... to build dev – Juliatzin May 14 '19 at 08:58
  • Your solution is simpler=better than the one here: https://stackoverflow.com/questions/46440909/how-to-configure-different-dockerfile-for-development-and-production – Juliatzin May 14 '19 at 08:59
  • let's update it in the answer so it fits to your question :) – Javier Aviles May 14 '19 at 10:46
  • the only issue with this approach, as I used it a few days, is that if I use `docker build --target=prod`, it will also execute the `dev` part, that is useless. It is not a filter, but it gives you the opportunity to run partial Dockerfiles – Juliatzin May 16 '19 at 13:53
  • why don't you include `CMD ["./release/api"]` in the first image, and rename the "AS base" to "AS dev", then it will stop there, but if prod, will build the next one? `CMD ["./release/api"]` should not affect anything in the first image – Javier Aviles May 16 '19 at 14:58
  • yes, but I am working now in another case of NodeJs, and I install different libs depending on env, so, it works, but build takes more time. – Juliatzin May 16 '19 at 15:11