0

Currently, In my dockerfile i am using multiple COPY commands to copy directories from my repository.

  • COPY requirements.txt requirements.txt
  • COPY validation /opt/validation
  • COPY templates /opt/templates
  • COPY goss /opt/goss
  • COPY newman /opt/newman
  • COPY conftest.py /opt/validation/conftest.py

How can i achieve the same results as above using a single COPY command. Is there a way?

  • 1
    There's no particular benefit to reducing the number of layers other than that there's a relatively large limit that you're unlikely to encounter, it's kind of like writing a lot of words in a single sentence instead of breaking it into several, and so unless you're hitting a specific problem or you're actually getting up to the 127-layer limit, the way you have it now is probably fine and I'd just leave it as it is. – David Maze Sep 01 '21 at 09:47
  • Does this answer your question? [How to copy multiple files in one layer using a Dockerfile?](https://stackoverflow.com/questions/30256386/how-to-copy-multiple-files-in-one-layer-using-a-dockerfile) – Noam Yizraeli Sep 02 '21 at 15:47

2 Answers2

2

There is a little hack with the scratch image:

FROM scratch as tmp

COPY foo /opt/some/path/foo
COPY bar /usr/share/tmp/bar

FROM debian:buster

COPY --from=tmp / /

CMD bash -c "ls /opt/some/path /usr/share/tmp"
❯ docker build -t test . && docker run --rm test
/opt/some/path:
foo

/usr/share/tmp:
bar

scratch is a pseudo-image, it is much like an empty directory. The hack is to copy everything there as it should be in the final image, then merge root directories. The merge produces a single layer.

❯ docker inspect --format '{{.RootFS}}' test
{layers [ 
 sha256:c2ddc1bc2645ab5d982c60434d8bbc6aecee1bd4e8eee0df7fd08c96df2d58bb
 sha256:fd35279adf8471b9a168ec75e3ef830046d0d7944fe11570eef4d09e0edde936
] }
anemyte
  • 17,618
  • 1
  • 24
  • 45
0

If you just want to copy things to the same folder /opt, maybe simply using next:

Folder structure:

.
├── conftest.py
├── Dockerfile
├── .dockerignore
├── goss
├── newman
├── requirements.txt
├── templates
└── validation

Dockerfile:

FROM alpine
COPY . /opt
#RUN mv /opt/conftest.py /opt/validation
RUN ls /opt

.dockerignore:

Dockerfile

Execution:

$ docker build -t abc:1 . --no-cache
Sending build context to Docker daemon  6.144kB
Step 1/3 : FROM alpine
 ---> 28f6e2705743
Step 2/3 : COPY . /opt
 ---> 8beb53be958c
Step 3/3 : RUN ls /opt
 ---> Running in cfc9228124fb
conftest.py
goss
newman
requirements.txt
templates
validation
Removing intermediate container cfc9228124fb
 ---> 4cdb9275d6f4
Successfully built 4cdb9275d6f4
Successfully tagged abc:1

Here, we use COPY . /opt to copy all things in current folder to /opt/ of container. We use .dockerignore to ignore the files/folders which won't want to copy to containers.

Additional, not sure the rules for COPY conftest.py /opt/validation/conftest.py correct or not, if it's correct, you may have to use RUN mv to move it to specified folder.

atline
  • 28,355
  • 16
  • 77
  • 113
  • Running `mv` on a copied file will increase final image size because the affected file will be in both places on different layers. Same goes for `rm` or any other command that'll modify files. The only way this will work as intended is when you create file and move it both in a single layer, e.g. `wget` and `mv` in one `RUN` command. – anemyte Sep 01 '21 at 09:20