Dockerfile COPY command copies file as a directory

2.1k Views Asked by At

Please note: this question mentions Java and Java keystores, but in reality has nothing to do with Java and should be answerable by anyone with sufficient knowledge of Docker and writing Dockerfiles.


I have a web service (myservice) that is a JVM application that has been Dockerized. The Dockerfile for it looks like this:

FROM openjdk:8-jdk-alpine as myenv

COPY application.yml application.yml
COPY ${KS_FILE} mykeystore.p12
COPY build/libs/myservice.jar myservice.jar

EXPOSE 9200

ENTRYPOINT [ \
    "java", \
    "-Dspring.config=.", \
    "-Dkeystore.file=mykeystore.p12", \
    "-jar", \
    "myservice.jar" \
]

For the record, mykeystore.p12 is a file (not a directory!) that stores the SSL certificate that the service will serve back to any clients attempting to make a connection with it. Specifically it is an encrypted Java keystore but that is way outside the scope of this question, and is besides the point. All that matters is that you understand it is a file, not a directory. I have the file stored on my local machine.

I have the following .env file in the root of this project as well:

MYENV=local
KS_FILE=../apprunner/certs/mykeystore.p12

Hence, ../apprunner/certs/mykeystore.p12 is a relative path to a location on my file system where mykeystore.p12 lives, and I want that URI stored in the .env file and used as an environment variable from inside the Dockerfile.

I build the image like so:

docker build -t myorg/myservice .

And I run a container of that image like so:

docker run -d -p9200:9200 --name myservice --net myrunner_default --env-file .env myorg/myservice

When I SSH into the running container, I do see mykeystore.p12 on the local file system, except...

Its a directory! Not a file!

$ docker exec -it 8391601f451b /bin/sh
/ # ls -al
total 62936
drwxr-xr-x    1 root     root          4096 Feb  1 21:24 .
drwxr-xr-x    1 root     root          4096 Feb  1 21:24 ..
-rwxr-xr-x    1 root     root             0 Feb  1 21:24 .dockerenv
-rw-r--r--    1 root     root          1510 Jan 29 16:27 application.yml
drwxr-xr-x    2 root     root          4096 May  9  2019 bin
drwxr-xr-x    7 root     root          4096 Jan 30 22:50 mykeystore.p12
-rw-r--r--    1 root     root      64371878 Jan 29 16:27 myservice.jar
drwxr-xr-x    5 root     root           340 Feb  1 21:24 dev
drwxr-xr-x    1 root     root          4096 Feb  1 21:24 etc
... etc.

And its got lots of weird, unexpected stuff in it, like source files from other directories in my project!

Clearly, something is wrong with either the use of ${KS_FILE} from inside my Dockerfile, or with how the URI value is stored in my .env file. Regardless, what do I have to change such that:

  1. I specify the file path and name of the KS_FILE env var in my .env file; and
  2. Between my .env and Dockerfile, that filepath + name are copied over as a file into the running container, such that when I ls -al from inside the container, I see it as a file?
1

There are 1 best solutions below

4
On BEST ANSWER

There are two problems here.

You can only copy files from your build directory

You cannot copy files that exist outside of your build directory (such as ../apprunner/certs/mykeystore.p12). If you try reference this file directory in your Dockerfile, like this:

FROM openjdk:8-jdk-alpine as myenv

COPY application.yml application.yml
COPY ../apprunner/certs/mykeystore.p12 mykeystore.p12

You will see the following error:

Step 3/6 : COPY ../apprunner/certs/mykeystore.p12 mykeystore.p12
COPY failed: forbidden path outside the build context: ../apprunner/certs/mykeystore.p12 ()

Environment variable expansion doesn't work that way

From the documentation:

Environment variables (declared with the ENV statement) can also be used in certain instructions as variables to be interpreted by the Dockerfile. Escapes are also handled for including variable-like syntax into a statement literally.

Since you haven't declared any ENV statements in your Dockerfile, that environment expands as an empty string, so you are getting, in effect:

COPY "" mykeystore.p12

This will simply copy the contents of the build directory into mykeystore.p12.

docker build doesn't make use of a .env file.

This article might be helpful.