I have a dockerfile that declares some environment variables that are being used later in the entrypoint, but the entrypoint never picks up the values for those variables. I tried the shell form but looks like its not doing anything. Here is my sample dockerfile :-
FROM java:8
ENV JAVA_OPTS="
RUN apt-get -y install ca-certificates curl
RUN mkdir /app
RUN mkdir /docker
CMD ["java", "-version"]
ADD /target/app.jar /app/app.jar
ENV spring.profiles.active dev
ENV encryptor.password xyz
COPY entrypoint.sh /docker/entrypoint.sh
RUN ["chmod", "+x", "/docker/entrypoint.sh"]
EXPOSE 8080
ENTRYPOINT ["/bin/bash", "-c", "/docker/entrypoint.sh"]
CMD ""
My entrypoint.sh is very simple and uses these ENV variables :-
#!/bin/bash
java -Djava.security.egd="file:/dev/./urandom" -Dencryptor.password=$encryptor.password -Dspring.profiles.active=$spring.profiles.active -jar /app/app.jar
How should i make my ENTRYPOINT to be able to access those ENV variables declared earlier in the Dockerfile so that its able to assign appropriate values to the arguments passed in. Went through several posts and stuffs on the internet and tried lot of ways to get this work, but didn't seem to work a single time.
I think an issue is the periods (dots) within the environment variable names. I think, valid identifiers may only include alphanumeric characters and underscores.
You will also need to use the shell form of ENTRYPOINT to get a shell that can do environment variable substitution:
FROM busybox
ENV spring_profiles_active dev
ENV encryptor_password xyz
ENTRYPOINT echo ${spring_profiles_active} ${encryptor_password}
Then:
docker build --tag=example --file=./Dockerfile .
docker run --interactive --tty example
Returns:
dev xyz
Related
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"]
I have a docker container which runs a springboot java application. Dockerfile:
# Create container with java preinstalled
FROM openjdk:8-jdk-alpine
# Create app directory
VOLUME /tmp
# Handle Arguments
ARG JAR_FILE
ARG ENV_NAME
ENV SPRING_PROFILES_ACTIVE=${ENV_NAME}
RUN echo ${ENV_NAME}
# Bundle app source
COPY ${JAR_FILE} app.jar
COPY application.yml application.yml
# Run the server
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.config.location=application.yml","-jar","app.jar"]
Now, I have a custom library I need to install in that container. I'll need to copy the installation, extract it, run the install script and answer prompts (Y/n)
I understood the easiest way to do this is to connect to the container, install the package and commit the changes.
First - I start the container using:
docker run --name local-jdk8 -d openjdk:8-jdk-alpine
The next step is to copy the data and run the install script, but the container keeps on exiting since the run command is empty ("/bin/sh") which means I can't run
docker exec -it local-jdk8 bash
Any ideas on how I can modify such a container?
Solved it using expect library
My dockerfile :
# Create container with java preinstalled
FROM openjdk:8
# Create app directory
VOLUME /tmp
# Handle Arguments
ARG JAR_FILE
ARG ENV_NAME
ARG DRIVER_FILE
# Environment
ENV SPRING_PROFILES_ACTIVE=${ENV_NAME}
RUN echo ${ENV_NAME}
# Fingerprint Driver
RUN apt-get update -y
RUN apt-get install -y expect
COPY ${DRIVER_FILE} driver.tar.gz
COPY driver-install.exp driver-install.exp
RUN tar -xzf driver.tar.gz
RUN /driver-install.exp
# Copy app source
COPY ${JAR_FILE} app.jar
COPY application.yml application.yml
# Run the server
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.config.location=application.yml","-jar","app.jar"]
driver-install.exp is the expect scripts that automatically interacts with the package installation
For what it's worth, here is a little trick that allows you to keep your container running to modify and commit it:
docker run --name local-jdk8 -d openjdk:8-jdk-alpine tail -f /dev/null
Furthermore, there is no bash installed on the container so sh will have to do:
docker exec -it local-jdk8 sh
Nevertheless, modifying Dockerfile is the better approach, since your change is persisted in code, rather than done on an potentially ephemeral container.
I'm trying to set docker container hostname (HOSTNAME env var) during startup, this is .sh script specified in ENTRYPOINT of dockerfile:
#!/bin/sh
export HOSTNAME=something-$(hostname)
java $JAVA_OPTS -jar /app.jar
I want this new hostname to be seen for jvm.
All I get is standard docker hostname like that:
/ # env
HOSTNAME=04dbf311a3be
When i set the hostname manually using this export above after the container is started everything works just fine. Everything is being run in swarm using compose stackfile.
EDIT1:
I am not doing this during container build but during startup
EDIT2:
To be clear, what i have:
DOCKER SWARM:
CONTAINER1
HOSTNAME=391fa2c7e184
CONTAINER2
HOSTNAME=39123a43242asd4
CONTAINER3
HOSTNAME=123123123123
what i want:
CONTAINER1
HOSTNAME=APPNAME-391fa2c7e184
CONTAINER2
HOSTNAME=APPNAME-123fa2c7e184
CONTAINER3
HOSTNAME=APPNAME-343fa345e184
And want this to be autmatically set during startup of n-containers
how do i try to achieve this:
I try to set this in start.sh file called on container startup (pointed in ENTRYPOINT command in dockerfile):
#!/bin/sh
export HOSTNAME=something-$(hostname)
java $JAVA_OPTS -jar /app.jar
there is no effect, the HOSTNAME is not being changed
I don't think that the entrypoint script is right place to name your container, as it is already created at that point. You have a couple possibilities. Name it at runtime like this.
~
$ docker run -it -h myContainer 3bee3060bfc8 /bin/bash
[root#myContainer /]# echo $HOSTNAME
myContainer
[root#myContainer /]#
The -h option let's you name your container when you run it.
That value should be valid in your ENTRYPOINT script.
Or, if you want to create your container names more dynamically, you should name them in a docker compose file. Even if you don't use the container_name option, docker-compose will append -1
version: '2'
services:
myService:
container_name: myService-$(envVariable)
I don't know swarm, but as it works with a yaml file, you should get similar naming options.
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)
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"]