Override Spring boot properties in docker container - java

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.

Related

How do I get Spring to use an application.yml file in a Docker container?

I am creating a simple Java/Gradle/Spring application. I am working on Dockerizing the app. When I run the app locally without docker, it properly uses the values in my application.yml file. However, when I run the Docker image, it doesn't use any of the values from the application.yml file.
In my Dockerfile below, you'll see that I copy the application.yml file to the same directory as my jar in the docker image. Additionally, in the entrypoint, I reference the application.yml file appropriately (when I change this file path to something that is incorrect, the app breaks on start-up).
Dockerfile:
FROM eclipse-temurin:17-jdk
EXPOSE 8080
RUN mkdir -p /app/
ADD build/libs/image-name-0.0.1-SNAPSHOT.jar /app/image-name.jar
ADD build/resources/main/application.yml /app/application.yml
ENTRYPOINT ["sh", "-c", "java -Djava.security.egd=file:/dev/./urandom -jar /app/image-name.jar --spring.config.location=file:/app/application.yml"]
Below is my docker-compose.yml file. I don't think this matters much as I got the same result by just using the docker run ... command, but I'd like to add it for context:
version: '2'
services:
image-name:
image: 'image-name:latest'
container_name: image-name
ports:
- "8081:8080"
build:
context: .
depends_on:
- postgres_db
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/compose-postgres
- SPRING_DATASOURCE_USERNAME=admin
- SPRING_DATASOURCE_PASSWORD=password
- SPRING_JPA_HIBERNATE_DDL_AUTO=update
postgres_db:
image: 'postgres:13.1-alpine'
container_name: postgres_db
environment:
- POSTGRES_USER=admin # TODO: CHANGE THIS LATER
- POSTGRES_PASSWORD=password # TODO: CHANGE THIS LATER
I have added the Spring Actuator dependency and exposed the health endpoint using the application.yml. However, when I run this via the Docker image, the log below is missing (but is present when I run locally without Docker). I also get a 404 when I hit the /actuator/health endpoint:
2022-12-26T15:07:08.439-06:00 INFO 23289 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator'
Any idea as to what I am doing incorrectly? I have looked at seemingly every other related Stack Overflow thread with no luck.
Options should come first.
java [options] -jar jarfile [args ...]
In your case should be:
java -Dspring.config.location=/app/application.yml -jar /app/image-name.jar
Reference documentation
Okay, I managed to solve this, and I really hope this helps someone in the future as well because I was banging my head against the wall over this for days. I made the change that Elyorbek Ibrokhimov had mentioned, with no luck. I even re-wrote everything in its most basic form so that it was essentially verbatim from the docs with no luck.
I then decided to simply change my configuration to change my yaml file to a sub-environment yaml file by renaming it to application-local.yaml and then setting the active profile to local and it worked. I think I will have to dive into the docs on how application.yaml files are processed after learning this. I will update this with any findings I make. Perhaps someone who understands why this happens can add their own answer.
Below is my final Dockerfile:
FROM eclipse-temurin:17-jdk
EXPOSE 8080
RUN mkdir -p /app/
ADD build/libs/image-name-0.0.1-SNAPSHOT.jar /app/image-name.jar
ADD build/resources/main/application-local.yml /app/application-local.yml
ENTRYPOINT ["sh", "-c", "java -Djava.security.egd=file:/dev/./urandom -Dspring.config.location=file:/app/application-local.yml -Dspring.profiles.active=local -jar /app/image-name.jar"]
I will not mark this as the accepted answer until I fully understand why this works the way it does.

Quarkus application deployed on Heroku gives Error R10 (Boot Timeout)

I'm having issues deploying a Quarkus 1.10 application to Heroku as a Docker image.
The same application, using SpringBoot and a similar Docker Image boots successfully, but somehow Quarkus triggers the infamous R10 Boot Timeout error due to bad bind of $PORT, even when I see that the boot times are really small (2 seconds vs. 4.5 of the SpringBoot version).
If I start the image locally, it works perfectly without issues.
My final Docker Image is like this (omitting the Multi-stage build steps for brevity):
FROM gcr.io/distroless/java:11
ENV QUARKUS_MAILER_FROM=${EMAIL_USERNAME} \
QUARKUS_MAILER_USERNAME=${EMAIL_USERNAME} \
QUARKUS_MAILER_PASSWORD=${EMAIL_PASSWORD}
EXPOSE 8080
COPY --from=backend /usr/src/app/target/*-runner.jar /usr/app/app.jar
COPY --from=backend /usr/src/app/target/lib /usr/app/lib
ENTRYPOINT [ "java", "-jar" ]
CMD ["/usr/app/app.jar", "-Dquarkus.http.host=0.0.0.0", "-Dquarkus.http.port=${PORT}"]
I'm using the commands to deploy the application:
heroku container:push web
heroku container:release web
I don't see where the error is. I've also tried to remove the EXPOSE directive from the Dockerfile but that's not the cause of error.
I've solved the issue, which is really dumb.
Modifying the ENTRYPOINT and the CMD sections of the Dockerfile as follows:
ENTRYPOINT [ "java" ]
CMD ["-Dquarkus.http.host=0.0.0.0", "-Dquarkus.http.port=${PORT}", "-jar", "/usr/app/app.jar"]
it works. The problem is, the system properties have to be passed before the -jar parameter, otherwise Quarkus doesn't pick the right value for ${PORT}

How to connect to the docker daemon on the host using spotify docker client

I want to run a Java Spring application inside of a docker container and this application should be able to deploy sibling containers. When I run the Java application directly on my machine it works fine and can deploy containers, but as soon as I try to run the application inside a container it does not work any more (im using supervisord to run the mongodb and Java Spring app in one container and I know that thats not best practice). The container starts up fine, but crashes as soon as my application tries to connect to the docker deamon without any stacktraces from Java, just the error WARN received SIGTERM indicating exit request. The supervisord logs dont contain additional info.
I tried mounting the docker socket from the host (Windows 10 Pro with Docker Desktop, also tried Ubuntu Server 18.04) into the container using -v /var/run/docker.sock:/var/run/docker.sock.
I also tried to use --net="host".
Both did not work, although with the second one the container does not crash but produces a different error ({}->unix://localhost:80: Connection refused) visible in the log of my java application, which indicates that it cant even find the right address for the deamon.
I also activated "Expose deamon on tcp://localhost:2375 without TLS".
I also tried to set the DOCKER_HOST environment variable inside the container to default values such as "tcp://localhost:2375" or "/var/run/docker.sock".
Here is the code that I use to initialize the docker client.
DockerClient docker = DefaultDockerClient.fromEnv().build();
The DefaultDockerClient.fromEnv().build(); should create a docker client that uses the DOCKER_HOST environment variable to connect to the host or the default adress ("/var/run/docker.sock" on *NIX).
Here is my DOCKERFILE:
FROM openjdk:8-jre-alpine
ENV PACKAGES mongodb supervisor
VOLUME /opt/server
VOLUME /data/db
WORKDIR /opt/accservermanager
ADD supervisord.conf /etc/supervisor.conf
ADD accservermanager.jar /opt/accservermanager/accservermanager.jar
ADD application.properties /opt/accservermanager/application.properties
RUN apk update && \
apk add --update $PACKAGES --no-cache && \
rm -rf /var/cache/apk/*
EXPOSE 8000
CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor.conf"]
And finally, my supervisord.conf
[supervisord]
user=root
stderr_logfile=/var/log/supervisord.err.log
stdout_logfile=/var/log/supervisord.out.log
loglevel=debug
[program:mongodb]
command=mongod --smallfiles
autostart=true
autorestart=true
stderr_logfile=/var/log/mongo.err.log
stdout_logfile=/var/log/mongo.out.log
[program:accservermanager]
directory=/opt/accservermanager/
command=java -jar accservermanager.jar
autostart=true
autorestart=true
stderr_logfile=/var/log/accservermanager.err.log
stdout_logfile=/var/log/accservermanager.out.log
Expected result: Application connects to the docker client from the host and is able to deploy/manage containers on the host
Actual result: Container crashes or outputs errors.
Turns out that there is a new version of spotify-docker that fixes my problem.
Updating from v8.15.1 to v8.15.2 solved my issue.

Docker container is only able to access MSSQL running inside another container with the internal IP/port

I have deployed a very simple MSSQL docker container using the following docker run command :
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=NotYourBusiness" -p 2433:1433 --name sql1 -d mcr.microsoft.com/mssql/server:2017-latest
I have SSMS installed on my machine and i'm able to connect to this instance with the following URL :
MyHostName,2433
I am able to run my spring boot app from my machine also with the following connection string :
dataSource.setJdbcUrl("jdbc:sqlserver://localhost:2433;database=SomeDatabase;");
With only MSSQL in a docker container, my application works perfectly from my machine.
Now, i want to put my spring boot app into a container as well. I have therefore built the following docker file :
FROM openjdk:11-jre-slim
VOLUME /tmp
EXPOSE 8082
ADD target/tno-1.0.jar tno-1.0.jar
ENTRYPOINT ["java","-jar","tno-1.0.jar"]
This is the build command i use to create the image :
docker build -f Dockerfile -t tno .
And this is the command i use to build the container :
docker run -t --name tno --link sql1:mssql -p 8082:8082 tno
Using the same connection string that works on my machine, the spring boot app fails to start with a connection refused error. I did look at many posts and they pointed out that the term "localhost" no longer really applies when running from a container since it refers to that container only. The only way i was able to make it work is to replace localhost:2433 with the container IP address : 1433.
This is perfectly acceptable but is there a way for a container to behave like my dev machine and be able to connect to another container as if the connection was coming from the outside world?
Thanks
If you can access to the database from the application running in other containers, try to configure your jdbc url from localhost to mssql (name of db link).
jdbc:sqlserver://mssql:2433;database=SomeDatabase;
Let me know or check this how to link container in docker?

Spring Boot External Configuration when using Docker

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

Categories

Resources