dockerfiledocker-builddocker-multi-stage-build

Using variables across multi-stage docker build


I want to use variables across multi-stage docker builds. Similar to this question (unanswered at the time of writing.)

My specific use case is to build my Go project in a builder stage and save the directory. This is done in a variable and use the same variable in the next stage(s): The BUILD_DIR variable.

My Dockerfile is (The example in the commented lines doesn't work.):

FROM golang:1.11.5 as builder

WORKDIR /project-name
# What I want to do:
#ENV BUILD_DIR /project-name
#WORKDIR ${BUILD_DIR}


# Vendored dependencies of my project:
COPY ./vendor ./vendor
COPY ./*.go ./
# Source code:
COPY ./go.* ./

RUN GOFLAGS=-mod=vendor GOOS=linux go build .

FROM something-else:some-version

WORKDIR some-folder

# Executable from previous stage:
COPY --from=builder /project-name/executable-name .
# Config files:
COPY ./conf ./conf

# What I want to do to copy the executable:
#COPY --from=builder /${BUILD_DIR}/executable-name .

ENTRYPOINT ["./executable-name"]

Solution

  • To send variable we can use "ARG" solution, the "base" solution, and "file" solution.

    ARG version_default=v1
    
    FROM alpine:latest as base1
    ARG version_default
    ENV version=$version_default
    RUN echo ${version}
    RUN echo ${version_default}
    
    FROM alpine:latest as base2
    ARG version_default
    RUN echo ${version_default}
    

    another way is to use base container for multiple stages:

    FROM alpine:latest as base
    ARG version_default
    ENV version=$version_default
    
    FROM base
    RUN echo ${version}
    
    FROM base
    RUN echo ${version}
    

    You can find more details here: https://github.com/moby/moby/issues/37345

    Also you could save the hash into a file in the first stage, and copy the file in the second stage and then read it and use it there.

    From what I understand you want to copy the built program into the new docker for multistage build that the output size is smaller. Basically you do not need to send a variable you need to know were you built it in the first image and copy it from there

    FROM golang:alpine as gobuilder
    RUN apk update && apk add git
    
    COPY sources/src/ $GOPATH/src/folder/
    WORKDIR $GOPATH/src/folder/
    #get dependencies
    RUN go get -d -v
    #build the binary
    RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -ldflags="-w -s" -o /go/bin/myGoProgram myGoSource.go
    
    FROM alpine:latest
    COPY --from=gobuilder /go/bin/myGoProgram /usr/local/bin/myGoProgram
    ENTRYPOINT ["myGoProgram"] # or ENTRYPOINT ["/usr/local/bin/myGoProgram"]