How can I pass JAVA_OPTS to tomcat in a docker container? - java

I want to run my spring-boot application with a certain profile. Therefore, I need to pass the -Dspring.profiles.active=dev argument to the JVM.
My dockerfile looks like this:
FROM tomcat:9.0.10-jre8
EXPOSE 8080
ENV JAVA_OPTS="-Dspring.profiles.active=dev"
COPY myapp.war /usr/local/tomcat/webapps/myapp.war
The application starts but the JVM option with the profile name does not seem to be set.
What am I missing?

Just simply add this in your Dockerfile :-
ENV spring.profiles.active=dev
and other option is below, by adding one ENTRYPOINT:-
ENTRYPOINT ["java","-Dspring.profiles.active=container","-jar","/app.jar"]

Related

Override Spring boot properties in docker container

I have a spring boot application that is dockerized. By default the application has spring.cloud.config.enabled=false hence the application doesn't pick up the application.properties from configserver. However while deploying in a separate env we need to integrate the application with configserver so we need to override and set the spring.cloud.config.enabled property to true.
To achieve this I am running the docker image using the following docker-compose file :
version: '3'
services:
my-app-new:
container_name: my-app
image: my-app:1.0.0-SNAPSHOT
ports:
- "8070:8070"
environment:
- SPRING_CLOUD_CONFIG_ENABLED=true
- SPRING_CLOUD_CONFIG_URI=http://localhost:14180
However, it just doesn't work. If I hard code the values in the property file then it integrates fine.
I also tried the following command but it still didn't work :
docker run -p 8070:8070 -e SPRING_CLOUD_CONFIG_ENABLED=true -e SPRING_CLOUD_CONFIG_URI=http://localhost:14180 my-app:1.0.0-SNAPSHOT
The spring boot version is 2.2.6.
Let me know what the problem is.
Update :
I cannot use profiles as there too many env in our company and even the VMs keep getting changed so cannot have hardcoded profiles. We want a solution where we can just pass certain variables from the outside.
As someone pointed out in the comments the above compose yml is not working as the environment variables need to read by the spring boot application. So did some research on the internet and instead we are now passing the JAVA_OPTS tomcat variable while running the image. Like so :
docker run --env JAVA_OPTS="-Dspring.cloud.config.uri=http://localhost:14180 -Dspring.cloud.config.enabled=true" -p 8080:8080 my-app-image
And in the docker file we have used the JAVA_OPTS while starting the jar like so
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar app.jar" ]
And this still doesnt work. Not sure what is going wrong.
I found the problem with my setup. I made a silly error. The config server is not in my docker network and I used localhost to communicate with the config server. Localhost would of course mean that I am referring to the app containers IP which only has the app running. Instead when I used the ip address or the hostname of my machine my application container could connect to the config server successfully.
Why you not run container --> go inside --> change configuration and commit to new images.
After that deploy to new env.

Docker container not printing logs not location specified in log4j2.xml

I have configured a Docker Image for my Spring boot application. I have also configured logs using log4j.xml. But, on running the docker image, the logs are getting printed neither in the docker logs nor on the location specified in log4j.xml.
Below is my Dockerfile
FROM openjdk:8
ADD <relative path to jar>/jar-name.jar jar-name.jar
ADD <relative path to property file>/application.properties /app/application.properties
ADD <relative path to log4j file>/log4j2-8081.xml /logs/log4j2-8081.xml
ENV JAVA_OPTS="8080"
ENTRYPOINT ["java", "-Dapp.home=classpath:file:/app/", "-
Dlog4j.configurationFile=classpath:file:/logs/log4j2-8081.xml", "-jar", "jar-name.jar"]
I need to pass the log4j.xml file path during the execution of the docker run command.
Thanks in advance
Docker Run Command:-
docker run -p 8081:8081 -e JAVA_OPTS=-Dserver.port=8081 rdsstg
So per your query you are saying the logs aren't getting printed per the log4j config in application code and in your docker container, kindly correct my inference. Thanks.
Now per your comment,
I want to create logs outside the container. In the location /log of the system.
The answer is to use volumes, where-in the path of host machine and docker container is provided. The bare minimal usage is to use -v option See below. For deep dive please refer Use volumes for more details.
docker run -p 8081:8081 -e JAVA_OPTS=-Dserver.port=8081 -v /host_machine/log:/container/var/app/log rdsstg
BUT, you do need to understand in order for your docker container to direct log files(or any files per say) on host machine, those files should be generated in container i.e app logging should be working in container. This is your #1
Let me know if above make sense.
On a side note
for -e usage, I would recommend to use the --env-file option so that you can keep multiple env variables in one file instead of passing multiple -e.
It would have been difficult to explain in comments section.

Best way to run jar application with arguments from env variables

I have a very simple java jar application that fetches DB properties from the env variables.
I`ve dockerized it and migrated to Kubernetes. I also created a config map and secret with parameters to my DB - so I have access to these properties in the container.
Is it possible to fetch all properties and inject it in Dockerfile? How can I do it?
FROM openjdk:8-jre
ADD target/shopfront-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8010
ENTRYPOINT ["java","-Ddb.host=**value-from-env-variable**","-jar","/app.jar"]
You can use them like this
ENTRYPOINT ["java", "-jar", "-Ddb.host=${DB_HOST}", "/app.jar"]
where DB_HOST should be defined in config map you have created.
I have tried this in my Spring Boot Application for setting Spring Profile.
The array or "exec form" of entrypoint uses exec to run the specified binary rather than a shell. Without a shell the string $DB_HOST is passed to your program as argument.
Shell form
ENTRYPOINT java -Ddb.host="${DB_HOST}" -jar /app.jar
Shell script
If your startup get more complex you can also use an ENTRYPOINT script.
ENTRYPOINT ["/launch.sh"]
Then launch.sh contains:
#!/bin/sh -uex
java -Ddb.host="${DB_HOST}" -jar /app.jar
As I understand you need to fetch parameters from config map and secret and set them as environment variables in your container. Furtunately it's quite nicely described in Kubernetes documentation.
Have a look at below links:
How to use secret: https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables
How to use config map: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#use-configmap-defined-environment-variables-in-pod-commands
To sum up, such resources need to be just defined in Pod's configuration.

docker with a java -jar but with arguments?

I am wondering if is possible to do the following...
I have a small application in java (and gradle)
I am trying to set it in a container, so I created the Dockerfile and worked fine UNTIL I have to set a parameter.
To run it locally on my IDLE I set these program arguments:
server application-local.yml
That actually loads a file with many properties, without this the app will fail.
On my Dockerfile I have this
FROM openjdk:8-jdk-alpine
USER root:root
ENV NAME test
LABEL maintainer="myself"
WORKDIR /opt/apps
COPY build/libs/myapp.jar /opt/apps/myapp.jar
EXPOSE 8080
CMD ["java", "myapp.jar"]
I was wondering if I could do the following:
CMD ["java", "-server:application-local.yml", "myapp.jar"]
but doesnt work, also I cannot do
java -jar myapp.jar -server:application-local.yml
simply doesnt do anything
Dont wanna do a gradleBuild because it is supposed to use java only at my docker image...
Any idea how to do this?
Edit:
So, I have done the following, move my application-local.yml to a folder I can copy and added this
COPY some-path/application-local.yml /opt/apps/local.yml
and moved the CMD for this
CMD ["java", "myapp.jar", "server", "local.yml"]
I still get the same error, basically cannot resolve the values from that yml file.
EDIT 2 ---
Basically what I cannot do is to figure out how to send the application.default.yml as configuration file, I realise also that the -server does not anything, is my config file the one I cannot load and is not present in the jar (normal behaviour)
When using the java command, order of the arguments matter
First you put the java options, like -server, then the -jar ... Or the class name in the case of running classes directly, and then the application arguments
The proper way to run your app is:
CMD ["java", "-jar", "myapp.jar", "server", "application-local.yml"]
Then you have another problem, you are only copying the final jar file to your docker container, so it can can't find the application-local.yml file, copy this also to your docker container
COPY build/libs/application-local.yml /opt/apps/application-local.yml

How to use docker passed environment variable in log4j2?

I have a spring-boot based application that uses log4j2.xml in a dockerized environment.
When I launch the docker I pass -e "LOG4J_PATH=/tmp/app.log" to specify where the logs should go to.
Next, in the log4j2.xml I use fileName="${env:LOG4J_PATH}" but this doesn't work. I searched the web for hours and thus tried double $ and tried sys instead of env... nothing.
This System.getenv("LOG4J_PATH") and (new EnvironmentLookup()).lookup("LOG4J_PATH") work fine, so I know that the variable is being passed to the running image ok, but from some reason the log4j doesn't seem to pick it up.
If I run this not via a docker and set the LOG4J_PATH environment variable in my .bash_profile it works fine so this is something between docker and log4j.
What am I doing wrong?
I believe you need to change the key value structure a bit for your passed environment variable. Can you try
docker run -e LOG4J_PATH='/tmp/app.log'

Categories

Resources