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:
KS_FILE
env var in my .env
file; and.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?There are two problems here.
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 ()
From the documentation:
Environment variables (declared with the
ENV
statement) can also be used in certain instructions as variables to be interpreted by theDockerfile
. 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.