Search code examples
dockerdockerfiledocker-multi-stage-builddocker-copy

Docker multistage: how to COPY built files between stages?


I'm beginner with Docker, and I'm trying to build an image in two stages, as explained here: https://docs.docker.com/develop/develop-images/multistage-build/

You can selectively copy artifacts from one stage to another

Looking at the examples given there, I had thought that one could build some files during a first stage, and then make them available for the next one:

FROM golang:1.7.3 AS builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go    .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]  

(Example taken from the above-linked page)

Isn't that what the COPY app.go . and the COPY --from=builder /go/src/github.com/alexellis/href-counter/app . are supposed to do?

I probably have a complete misunderstanding of what is going on, because when I try to do something similar (see below), it seems that the COPY command from the first stage is not able to see the files that have just been built (I can confirm that they have been actually built using a RUN ls step, but then I get a lstat <the file>: no such file or directory error).

And indeed, most other information I can gather regarding COPY (except the examples in the above link) rather suggest that COPY is actually meant to copy files from the directory where the docker build command was launched, not from within the build environment.

Here is my Dockerfile:

FROM haskell:8.6.5 as haskell
RUN git clone https://gitlab+deploy-token-75:[email protected]/bli/bioinfo_utils.git
WORKDIR bioinfo_utils/remove-duplicates-from-sorted-fastq/Haskell
RUN stack --resolver ghc-8.6.5 build && \
    stack --resolver ghc-8.6.5 install --local-bin-path .
RUN pwd; echo "---"; ls
COPY remove-duplicates-from-sorted-fastq .

FROM python:3.7-buster
RUN python3.7 -m pip install snakemake
RUN mkdir -p /opt/bin
COPY --from=haskell /bioinfo_utils/remove-duplicates-from-sorted-fastq/Haskell/remove-duplicates-from-sorted-fastq /opt/bin/remove-duplicates-from-sorted-fastq
CMD ["/bin/bash"]

And here is how the build ends when I run docker build . from the directory containing the Dockerfile:

Step 5/11 : RUN pwd; echo "---"; ls
 ---> Running in 28ff49fe9150
/bioinfo_utils/remove-duplicates-from-sorted-fastq/Haskell
---
LICENSE
Setup.hs
install.sh
remove-duplicates-from-sorted-fastq
remove-duplicates-from-sorted-fastq.cabal
src
stack.yaml
 ---> f551efc6bba2
Removing intermediate container 28ff49fe9150
Step 6/11 : COPY remove-duplicates-from-sorted-fastq .
lstat remove-duplicates-from-sorted-fastq: no such file or directory

How am I supposed to proceed to have the built file available for the next stage?


Solution

  • Well, apparently, I was mislead by the COPY step used in the first stage in the doc example. In my case, this is actually useless, and I can just COPY --from=haskell in my second stage, without any COPY in the first stage.

    The following Dockerfile builds without issues:

    FROM haskell:8.6.5 as haskell
    RUN git clone https://gitlab+deploy-token-75:[email protected]/bli/bioinfo_utils.git
    WORKDIR bioinfo_utils/remove-duplicates-from-sorted-fastq/Haskell
    RUN stack --resolver ghc-8.6.5 build && \
        stack --resolver ghc-8.6.5 install --local-bin-path .
    
    FROM python:3.7-buster
    RUN python3.7 -m pip install snakemake
    RUN mkdir -p /opt/bin
    COPY --from=haskell /bioinfo_utils/remove-duplicates-from-sorted-fastq/Haskell/remove-duplicates-from-sorted-fastq /opt/bin/remove-duplicates-from-sorted-fastq
    CMD ["/bin/bash"]