Externalize application configuration for Google Cloud Run - spring-boot

I was looking to externalize application configuration for containerized applications on Google Cloud Run. I know there are environment variables available for cloud run application and I want to have something as Config Server for Cloud Run.
Is there any out of the box support available on GCP?

When setting up your Cloud Run deployment, you can simply inject environment variables into your service:
Because Spring Boot comes with application.properties mechanism, you can easily override those values exactly from the environment variables. Do keep in mind, that the syntax is slightly different:
application.properties
spring.profiles.active=dev
environment variables
SPRING_PROFILES_ACTIVE=dev
Injected env variables will take precedence over the ones defined in your application.properties file.

There are two solutions to it :
If your docker file is "ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/****.jar"]" then use "-Dspring.profiles.active=dev" in the container arguments on the cloud run.
In case your docker file has "CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/***.jar"]" You can do it by setting Environment Variable as SPRING_PROFILES_ACTIVE and value as dev in "Variables & Secrets" tab on cloud run Container Configuration

Related

Environment variables for Spring Cloud Config in Docker

So, I am learning about microservices (I am a beginner) and I'm facing an issue. I've went through the Spring Cloud Config and Docker docs hoping to find a solution, but I didn't.
I have an app with 3 microservices (Spring Boot) and 1 config server (Spring Cloud Config). I'm using a private Github repository for storing config files and this is my application.properties file for config server:
spring.profiles.active=git
spring.cloud.config.server.git.uri=https://github.com/username/microservices-config.git
spring.cloud.config.server.git.clone-on-start=true
spring.cloud.config.server.git.default-label=master
spring.cloud.config.server.git.username=${GIT_USERNAME}
spring.cloud.config.server.git.password=${GIT_ACCCESS_TOKEN}
I have a Dockerfile based on which I have created a Docker image for config server (with no problems). I created a docker-compose.yml which I use to create and run containers, but it fails because of an exception in my cloud config app. The exception is:
org.eclipse.jgit.api.errors.TransportException: https://github.com/username/microservices-config.git: not authorized
Which basically means that my environment variables GIT_USERNAME and GIT_ACCCESS_TOKEN (that I set up in Intellij's "Edit configuration" and use in application.properties) are not available for the config server to use in a container.
The question is: Do I need to somehow add those environment variables to .jar or to Docker image or to Docker container? Like I'm not sure how do I make them available for the config server to use in a container.
Any help or explanation is welcomed :)

Cannot access environment variables in Docker environment

I am trying to dockerize my spring boot project and use it in EC2 instance.
In application.properties I have following lines,
spring.datasource.url=${SPRING_DATASOURCE_URL}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
and I am reading SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD from my environment.
I have following Dockerfile,
FROM openjdk:latest
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar", "-DSPRING_DATASOURCE_URL=${DATASOURCE_URL}", \
"-DSPRING_DATASOURCE_USERNAME=${DATASOURCE_USERNAME}", \
"-DSPRING_DATASOURCE_PASSWORD=${DATASOURCE_PASSWORD}", "/app.jar"]
EXPOSE 8080
When I try to run run the following command,
sudo docker run -p 80:8080 <image-repo> --env DATASOURCE_URL=<url> --env DATASOURCE_USERNAME=<username> --env DATASOURCE_PASSWORD=<password>
My application crashes because of the non-existing environment variables.
Also,
I have tried using docker-compose mentioned Spring boot app started in docker can not access environment variables link. It become much more complicated for me to debug.
TL;DR I want to achieve information hiding in my spring boot application. I want to use environment variables to hide my credentials to the database. However, my dockerized program is not having the environment variables that I want to have.
If you have any approaches other than this, I would be also happy to listen the way I can achieve information hiding. Thanks.
You need to put options like docker run --env before the image name. If they're after the image name, Docker interprets them as the command to run; with the specific setup you have here, you'll see them as the arguments to your main() function.
sudo docker run \
--env SPRING_DATASOURCE_URL=... \
image-name
# additional arguments here visible to main() function
I've spelled out SPRING_DATASOURCE_URL here. Spring already knows how to map environment variables to system properties. This means you can delete the lines from your application.properties file and the java -D options, so long as you do spell out the full Spring property name in the environment variable name.

Application.properties of Docker containerized spring boot application [duplicate]

This question already has answers here:
Externalising Spring Boot properties when deploying to Docker
(6 answers)
Closed 3 years ago.
How can we provide application.properties to spring boot app in a docker? Would normally copying the application.properties to the container work?
you can keep that file at some location and map that location to volume. It will connect the local machine to docker container's world
Refer this
I suggest you build the Image with properties included. If needed, add a startscript and provide environment variables per stage (dev, qa, prod), which symlink the needed files.
The answer to this will be widely opinionated, some folks like to mount the file as a volume while other like to substitute the required configuration by reading it from environment variables through a shell script that is run as the entrypoint of the docker container.
Although if you're using Spring, it allows externalized configuration which can be taken from multiple sources. One of the sources is the environment variables that directly override the default configuration.
The approach I take though is to provide them as command line arguments to the JVM command by making the JVM command the entrypoint and providing the arguments at the end of the docker run command

How to do Spring-boot configuration for many clients

I am wondering how to resolve problem: I have a spring-boot app on docker that connects to db and some other service.
Probably some clients will have db on other urls than the others.
I use spring.datasource.url property to connect to DB. Should I add it to args and use:
Properties properties = new Properties();
properties.put("spring.datasource.url", args[1]);
application.setDefaultProperties(properties);
And something like that will override it ? But every run will need adding DB url. Or use something else?
datasource could be read as a variable from the docker-compose file:
assume this is your docker-compose file:
version: '2'
services:
db:
image: customimage_mysql
restart: always
ports:
- "3306:3306"
application:
build: .
ports:
- "9111:9111"
depends_on:
- db
links:
- db
environment:
- database.url=jdbc:mysql://mysql-docker-container:3306/spring_app_db?
Now you have 2 options:
set different values for databse.url inside docker compose and build image for each app correspondingly
set different variables (databse1.url , databse2.url,databse3.url, ...) inside docker-compose file, and reference to them from
application.properties:
application.properties
spring.datasource.url=${database.url}
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
server.port=9111
According to the information that you have provided here, the database link should be a configuration to your application. basically you need to have a configurations file
application.properties
And when you want to change the URL, just change it in the configuration file and build.
you can find the documentation here
And moreover if you are using devops environment like kubernetes, you would have to have a config-map and your deployments will get configurations from those config-maps which are like application.properties files.
If you've got lots of deployments each with their own database then that will take some management one way or another. But you don't want it to require lots of builds of your app - you want to externalise that configuration.
Sorting boot has features for externalising configuration (https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html). The simplest for your case would be to use environment variables that override properties by relaxed binding of names (https://github.com/spring-projects/spring-boot/wiki/Relaxed-Binding-2.0). If app is started with an environment variable named SPRING_DATASOURCE_URL then this value will override what you have in your properties for spring.datasource.url. Your properties file effectively sets a default value that you can override. This is out of the box behaviour for Spring Boot and applies to other properties too (inc all the db ones, though if you've got databases of different types then you'll want to include all the relevant driver jars in your build).
Since you're using docker you can set environment variables in the container at deploy/startup time using a -e parameter. So you can override at deploy time for each deployed instance.
You might well use further layers on top of docker like docker-compose or Kubernetes. Then you might get into setting the environment variables in deployment descriptor files that describe your deployment configuration. But that configuration management question is at a different layer/stage and is no longer part of the build step once you have your config externalised.

Spring 3.1 Profile: how to set in Stackato Tomcat container

I'm using Spring 3.1.3 and the new profile feature. When I set the environment in my IDE for spring_profiles_active=NONPROD, it works fine. However, when I deploy to our aPaaS environment which is also using Tomcat, it isn't getting picked up.
Shouldn't I just be able to do the following:
env:
CATALINA_OPTS: -Dspring_profiles_active=NONPROD
If I ssh to the machine, I see this is getting set. Any ideas why Spring isn't picking this up?
Put the following lines to your manifest.yml file to get the Spring profile activated in Stackato:
env:
spring_profiles_active:
default: NONPROD
This will put spring_profiles_active into environment variable and Spring happily reads it from there. Note that you have to use underscores in the variable name, because Stackato doesn't like dots in those. The reason is that Linux environment variable names shouldn't contain dots for shell programs to work correctly with them.

Resources