How to pass System property to docker containers? - java

So I know you can pass Environment variables to a docker container using -e like:
docker run -it -e "var=var1" myDockerImage
But I need to pass a System Property to a docker container, because this is how I run my JAR:
java -Denvironment=dev -jar myjar.jar
So how can I pass a -D System property in Docker? Like:
docker run -it {INSERT Denvironment here} myDockerImage

Use the variable you passed into the container on the java command:
docker run -it -e "ENV=dev" myDockerImage
java -Denvironment=$ENV -jar myjar.jar

One more way to do it, if running under Tomcat, is setting your system variables in your Dockerfile using ENV JAVA_OPTS like this:
ENV JAVA_OPTS="-Djavax.net.ssl.trustStore=C:/tomcatDev.jks -D_WS_URL=http://some/url/"
Hope it helps!

One can also use the following start.sh ENTRYPOINT for the Docker container, make sure to use the array syntax, e.g.:
Dockerfile:
...
ENTRYPOINT ["/start.sh"]
The actual start.sh script:
#!/bin/bash
export JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64"
exec $JAVA_HOME/bin/java -jar myjar.jar $#
Then you can just pass the Java system properties directly to your application as docker run container arguments:
docker run myDockerImage "-Dvar=var1"

Have a start.sh file, e.g.:
#!/usr/bin/env sh
exec java -Djava.security.egd=file:/dev/./urandom $* -jar /app.jar
In your Dockerfile:
...
COPY start.sh /start.sh
RUN chmod a+rx /start.sh
ENTRYPOINT ["/start.sh"]

Related

Converting Shell Script to Dockerfile

I have Java app and want to generate docker image, I have shell script like this:
#!/bin/sh
java -version
export APPLICATION_DIR=$PWD
for rJarFile in `ls ${APPLICATION_DIR}/lib/*.jar`
do
export CLASSPATH=$rJarFile:$CLASSPATH
done
export CLASSPATH=$APPLICATION_DIR/classes:$CLASSPATH
java -Xverify:none -Xmx2048m -Djava.awt.headless=true -DFI_IS_CONFIGSER=N -DFICLIENT_APP_PATH=${APPLICATION_DIR} -DFI_APP_NAME=FIONLINE -DFI_BASE_INSTANCE_ID=1 -DPRODUCT_BOOTSTRAP_FILE=${APPLICATION_DIR}/data/BootstrapFile.properties -DFEBA_SYS_PATH=${APPLICATION_DIR}/data
And I try to convert it into Dockerfile like this
# FROM openjdk:8
FROM openjdk:11
RUN javac -version
# Create app directory
WORKDIR /usr/src/app
# Bundle app source
COPY . .
ENV APPLICATION_DIR=/usr/src/app
RUN echo $APPLICATION_DIR
RUN for rJarFile in `ls ${APPLICATION_DIR}/lib/*.jar`; do export CLASSPATH=$rJarFile:$CLASSPATH; done
RUN echo $CLASSPATH
ENV $CLASSPATH=$APPLICATION_DIR/classes:$CLASSPATH
# Run app
ENTRYPOINT ["java", "-Xverify:none", "-Xmx2048m", "-Djava.awt.headless=true", "-DFI_IS_CONFIGSER=N", "-DFICLIENT_APP_PATH=${APPLICATION_DIR} -DFI_APP_NAME=FIONLINE -DFI_BASE_INSTANCE_ID=1", "-DPRODUCT_BOOTSTRAP_FILE=${APPLICATION_DIR}/data/BootstrapFile.properties", "-DFEBA_SYS_PATH=${APPLICATION_DIR}/data"]
It can be generated, but there's an error when I try to run it like this:
Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: process_linux.go:459: container init caused: setenv: invalid argument: unknown
I've also changed this script RUN for rJarFile in `ls ${APPLICATION_DIR}/lib/*.jar`; do export into this RUN for rJarFile in ls ${APPLICATION_DIR}/lib/*.jar; do export CLASSPATH=$rJarFile:$CLASSPATH; done, but none of them working. I don't want to make Dockerfile execute the script. Below is logs when i generate and run it.
You cannot update the classpath as you do with:
ENV $CLASSPATH=$APPLICATION_DIR/classes:$CLASSPATH
instead you can do
ENV CLASSPATH=$APPLICATION_DIR/classes:$CLASSPATH
Also - please consider moving the script into a separate shell script and adding into the container. This would greatly simplify the Dockerfile, for example:
# FROM openjdk:8
FROM openjdk:11
RUN javac -version
# Create app directory
WORKDIR /usr/src/app
# Bundle app source
COPY . .
ENV APPLICATION_DIR=/usr/src/app
RUN echo $APPLICATION_DIR
ENTRYPOINT ["/usr/src/app/start_java.sh"]
and keep your existing script inside start_java.sh

Use cp in entrypoint for docker run

There is Dockerfile
FROM openjdk:11.0.12-jre-slim
COPY target/app.jar /app.jar
COPY configs configs
ENTRYPOINT ["java","-jar","/app.jar"]
In folder configs contains json configs for java application.
The build docker command is:
docker build --build-arg -f ~/IdeaProjects/app --no-cache -t app:latest
And the run command is:
docker run --entrypoint="cp configs var/opt/configs/ && java -jar app.jar" app:latest
Let's omit the ability to copy configs in the Dockerfile via COPY command. Unfortunately, this must be done using --entrypoint.
An error occurs when the docker run command was executed:
docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: exec: "cp configs var/opt/configs/ && java -jar app.jar": stat cp configs var/opt/configs/ && java -jar app.jar: no such file or directory: unknown.
Could you explain why the error occurred in this case?
I would do this with an entrypoint wrapper script. A Dockerfile can have both an ENTRYPOINT and a CMD; if you do, the CMD gets passed as arguments to the ENTRYPOINT. This means you can make the ENTRYPOINT a shell script that does first-time setup, then ends with exec "$#" to replace itself with the CMD.
#!/bin/sh
# docker-entrypoint.sh
# copy the configuration to the right place
cp configs var/opt/configs/
# run the main container command
exec "$#"
In the Dockerfile, make sure to COPY the script in (it should be checked in to source control as executable) and set it as the ENTRYPOINT.
...
COPY docker-entrypoint.sh .
ENTRYPOINT ["./docker-entrypoint.sh"] # must be JSON-array syntax
CMD ["java", "-jar", "/app.jar"] # what was previously ENTRYPOINT
When you run the container it's straightforward to replace the CMD, so you can double-check that this is doing the right thing by running an interactive shell in place of the java application.
docker run -v "$PWD/alt-configs:/configs" --rm -it my-image sh
If you do need to override the command like this at docker run time, the command you show uses && to run two commands consecutively. This needs to run a shell to be understood correctly, and in this context you need to manually provide a /bin/sh -c wrapper.
I would still recommend changing ENTRYPOINT to CMD in your Dockerfile; then you could run a relatively straightforward
docker run \
... \
-v "$PWD/alt-configs:/configs" \
my-image \
/bin/sh -c 'cp configs var/opt/configs && java -jar /app.jar'
If you use --entrypoint, it only takes the first word out of this command, and it is a Docker options so it needs to come before the image name. I'd recommend designing your image to avoid needing this awkward construct.
docker run \
... \
-v "$PWD/alt-configs:/configs" \
--entrypoint /bin/sh \
my-image \
-c 'cp configs var/opt/configs && java -jar /app.jar'
Your proposed command is having problems because it's trying to pass the entire command, including the embedded spaces and shell operators, as a single word, but that causes the OS-level process handling to try to look for an executable file with spaces and ampersands in the filename, hence the "no such file or directory" error.

How to pass Java options/variables to Springboot app in docker run command

I have a Spring Boot application which uses profiles to configure in different environments. I want to pass this profile information as a parameter to my docker run command. How do I go about doing it?
Here is my dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/demo-app-1.0-SNAPSHOT.jar
COPY ${JAR_FILE} /opt/lib/demo-app.jar
EXPOSE 80
# ENTRYPOINT ["java","-Dspring.profiles.active=dockerdev","-jar","/opt/lib/demo-app.jar"]
# Above line works, but not desired as profile will change in diff envs
ENTRYPOINT ["java","-jar","/opt/lib/demo-app.jar"]
I have tried the following, but, none works
docker run -p 8000:80 demo-app -Dspring.profiles.active=dockerdev
docker run -p 8000:80 demo-app --rm -e JAVA_OPTS='-Dspring.profiles.active=dockerdev'
Please help.
Clarification: I am using multiple profiles. Hence I do not want the active profile to be mentioned within the application or the docker file. Instead, I want to use the same application and docker file and run it in different environments, and pass the active profile to be used in the docker run command. Apologies if anything above did not clarify that.
Solution 1
You can override any property from your configuration by passing it to docker container using -e option. As explained in Externalized configuration the environment variable name should be uppercased and splitted using underscore. So for example to pass spring.profiles.active property you could use SPRING_PROFILES_ACTIVE environment variable during container run :
docker run -p 8000:80 -e SPRING_PROFILES_ACTIVE=dockerdev demo-app
And this variable should be picked automatically by Spring from environment.
Solution 2
Change Dockerfile to :
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/demo-app-1.0-SNAPSHOT.jar
# environment variable with default value
ENV SPRING_PROFILE=dev
COPY ${JAR_FILE} /opt/lib/demo-app.jar
EXPOSE 80
#run with environment variable
ENTRYPOINT java -Dspring.profiles.active=$SPRING_PROFILE jar /opt/lib/demo-app.jar
and then run the container passing the environment variable :
docker run -p 8000:80 --rm -e SPRING_PROFILE=dockerdev demo-app
Make use of application.properties in springboot to override any variables from outside. We heavily use this in our production environments.
You need to:
Change your ENTRYPOINT to:
ENTRYPOINT ["java","-jar","/opt/lib/demo-app.jar","--spring.config.additional-location=/application.properties"]
Create application.properties file with contents:
spring.profiles.active=dockerdev
You can also override any variables used in your springboot code using application.properties and can also override springboot specific variables as mentioned here.
Also change your docker run command to:
docker run -itd -v /path/to/application.properties:/application.properties image-name
So that application.properties from your host will get mounted
inside your docker container.
NOTE: If --spring.config.additional-location don't works then try --spring.config.location option.
Hope this helps.
JAVA_TOOL_OPTIONS maybe the right answer.
docker run -p 8000:80 -e JAVA_TOOL_OPTIONS='-Dspring.profiles.active=dockerdev' demo-app
People who are looking for the answer for non Spring (Plain Java Applications)
This is how to send System properties/arguments: Change the Dockerfile to
FROM openjdk:8-jdk-alpine
COPY target/demo-app-1.0-SNAPSHOT.jar demo-app.jar
EXPOSE 8080
ENTRYPOINT java -jar demo-app.jar
Build the image:
docker build -t demo-app .
Then run the docker container using following command:
docker run -e "JAVA_TOOL_OPTIONS=-Xms1024m -Xmx2048m -Dspring.profiles.active=dockerdev" -p 8080:8080 demo-app
you have to provide the JAVA_OPTS inside the docker file, example of a docker file is below.
FROM {{ env "DOCKER_REGISTRY" }}/asdf/osX-jre8:{{ env "BASE_IMAGE_VERSION" }}
ADD target/yourapp.jar /app.jar
#Environment vars
ENV NO_PREFIX true
ENV APP_NAME "xxx"
ENV APP_UUID "81b35e09-2a10-48c3-a091-xxxxxxxxx"
ENV HEALTH_CHECK_URL http://localhost:9000/health
ENV SERVICE_PORT 8080
ENV JAVA_OPTS "-Dsun.net.client.defaultConnectTimeout=2000 -Dsun.net.client.defaultReadTimeout=20000 -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/alloc/logs"
You should add the env variable JAVA_OPTS to your Dockerfile
FROM tomcat:8.5.47-jdk8-openjdk
LABEL build_date="2020-07-14" \
name="Ousama EL IDRISSI" \
version="1.0" \
description="Docker Image made by la7ya"
EXPOSE 8080
COPY ./target/la7yaman-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/ROOT.war
ENV JAVA_OPTS="-Dspring.profiles.active=docker-demo"
CMD ["catalina.sh", "run"]

How do I pass external application properties to springboot app in a docker container

Please I have read posts that seem to address this, but I am still not able to solve my problem. I have a default application.properties in my spring boot app running inside a docker container, However I want to add external application.properties.
This is my docker file:
FROM tomcat:8-alpine
COPY target/demoapp.war /usr/local/tomcat/webapps/demo.war
RUN sh -c 'touch /usr/local/tomcat/webapps/demo.war'
EXPOSE 8080
ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom -jar /usr/local/tomcat/webapps/demo.war", "--spring.config.location=C:/Users/650/Documents/Workplace/application.properties"]
I build the file with:
docker build . -t imagename
And I run the spring boot docker container with:
docker run -p 8080:8080 -v C:/Users/650/Documents/Workplace/application.properties:/config/application.properties --name demosirs --link postgres-
standalone:postgres -d imagename
The container still doesnt locate my external application.properties, please how do I overcome this challenge ?
You are referring to the host path in the docker ENTRYPOINT command. Just refer to the container specific path:
ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom -jar /usr/local/tomcat/webapps/demo.war", "--spring.config.location=/config/application.properties"]
And, I notice, you are using files as values to the -v argument to docker run. So change that to the corresponding directory:
-v C:/Users/650/Documents/Workplace:/config
In your entrypoint pass another argument
-Dspring.config.location=<your custom property file location>
you can try giving file path instead of the classpath.
"--spring.config.location=file:${configDirectory}/application.yml"
You can make use of spring cloud config project.
https://spring.io/guides/gs/centralized-configuration/

pass parameters to docker entrypoint

I have Dockerfile
FROM java:8
ADD my_app.jar /srv/app/my_app.jar
WORKDIR /srv/app
ENTRYPOINT ["java", "-jar", "my_app.jar", "--spring.config.location=classpath:/srv/app/configs/application.properties"]
How I can do dynamic paramethers for java without ./run.sh in entrypoint? ( as -Dversion=$version or others )
I want pass this parameters when start container.
--entrypoint something doesn't work on Docker 1.11 ;(
You can append your dynamic parameters at the end of the docker run .... You haven't specified any CMD instruction, so it'll work.
What is actually run without specifying any command at the end, when running the docker run ..., is this:
ENTRYPOINT CMD (it's concatenated and there is a space in between)
So you can also use something like
...
ENTRYPOINT ["java", "-jar", "my_app.jar"]
CMD ["--spring.config.location=classpath:/srv/app/configs/application.properties"]
which means, when using
docker run mycontainer the
java -jar my_app.jar --spring.config.location=classpath:/srv/app/configs/application.properties
will be invoked (the default case), but when running
docker run mycontainer --spring.config.location=classpath:/srv/app/configs/some_other_application.properties -Dversion=$version
it'll be run w/ different property file and with the system property called version (overriding the default case)

Categories

Resources