I'm developing a Spring Boot application which I'd like to deploy with Docker.
The trouble I'm having is we need to store the properties file on the server, similar to how Tomcat allows you to put the properties file in /lib.
How would I go about getting Spring Boot to use this file when running inside Docker?
Docker provides a way to do this using Volumes:
In addition to creating a volume using the -v flag you can also mount a directory from your own host into a container.
$ sudo docker run -d -P --name yourapp -v /lib:/lib yourcontainer/name
So in your containerized app, you would just look in /lib (or wherever you find convenient to mount it), and when you book the container, you specify the host directory you want mounted.
Another option I've used is to create a container with just the configuration (use busybox or something small) and then export a directory from within that as a volume that you share in other containers. This does set up a dependency between containers that you have to manage, but it gives you the benefit of being able to version your configuration and not have to have it just sitting on the host file system.
Both of these strategies are discussed at the link above.
You can also override application.properties file directly:
docker run -v custom.properties:/data/application.properties spring-boot-app
Related
Is there any way to copy files from the host to Docker container without using Docker cp command?
I am developing a web project using Java. In that I need to download a file from the web and copy that file to my Docker container.
How can I do it without using Docker cp command?
Take a look at this link. Let me know if it works for you http://docs.docker.oeynet.com/machine/reference/scp/#example
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.
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.
I have a two custom xml property files that are environment specific used in my spring boot project. Is it possible to use mount or volume tag to get the files from a location specified during docker run? The xml files are required to successfully connect to a db server.
Also if I specify an env-file command in the docker run can i put my sh files in any location on the docker server and specify the path there in the run command?
Yes, you can do that by mounting a volume. It will swap your in-container location with chosen server location. Inside container there will be no difference between this shared location and any other. Use flag -v "SERVER_LOCATION:CONTAINER_LOCATION":
docker run -v /etc/xmlsFolder:/etc/appConfig/destinationFolder your_image
Yes, you can specify run command in script anywhere on server.
According to http://www.eclipse.org/jetty/documentation/current/quickstart-running-jetty.html it is possible to manage web applications in base directories in jetty 9.x. The guide explains what can be put inside those and gives an example by pointing to the demo-base directory in the binary distribution. However it would have been useful to point out what actually needs to be in such a jetty base in order to make deployment successful, e.g. so that
cd /path/to/my-base/
java -jar ~/jetty-distribution-9.2.3.v20140905/start.jar jetty.home=~/jetty-distribution-9.2.3.v20140905/ jetty.base=.
succeeds. Putting a minimal valid war file (with only one jsf file) into /path/to/my-base or /path/to/my-base/webapps/ fails with WARNING: Nothing to start, exiting ..., although it would make sense to deploy a minimal application or display a helpful warning what needs to be added.
What needs to be added to be able to deploy an application from a separate base directory?
Jetty can make this for you through flags to the start.jar
There's an exmample in the docs, here: http://www.eclipse.org/jetty/documentation/9.3.0.v20150612/quickstart-running-jetty.html
"The following commands: create a new base directory; enables a HTTP connector and the web application deployer; copies a demo webapp to be deployed.
Simplified:
mkdir /home/me/mybase
cd /home/me/mybase
java -jar $JETTY_HOME/start.jar --add-to-startd=http,deploy
Then copy your war, if you use ROOT.war, it will map to /, and start jetty:
cp my.war webapps/ROOT.war
java -jar $JETTY_HOME/start.jar
Alternatively, if you have docker installed, you can also get the official setup by copying it, like so:
First, have docker download and run jetty, map a directory on the host to the docker container. I was already mapping webapps, so I just continued to use that mapping. This removes the container when done (-rm) so it's clean and it starts an interactive bash shell, logging you right into an official barebones jetty container that is ready to deploy wars plopped into the webapps directory (just what we want!)
sudo docker run --rm -it -v /home/myuser/jetty/webapps:/var/lib/jetty/webapps jetty:latest /bin/bash
If you run and env on the container, you'll see:
JETTY_BASE=/var/lib/jetty
Just tar this base up, copy the tar to the webapps directory, which is mapped back to the localhost, and exit. (feel free to map
root#f99cc00c9c77:/var/lib# tar -czvf ../jetty-base.tar.gz .
root#f99cc00c9c77:/var/lib# cp ../jetty-base.tar.gz jetty/webapps/
root#f99cc00c9c77:/var/lib# exit
Back on the localhost, you have a tar of the official jetty base! The docker container should have stopped on exit, you can test this with sudo docker ps, which should show an empty list (just headers).
Just to finish this off, back on the host, create a base directory (as myuser, not root, of course):
mkdir ~/jetty/localbase
cp ~/jetty/jetty-base.tar.gz ~/jetty/localbase/
cd ~/jetty/localbase/
tar xvzf jetty-base.tar.gz
Then start it up like before:
java -jar $JETTY_HOME/start.jar