How to containerize an environment-dependent legacy application writen in Java - java

We have a legacy application written in Java using Apache Struts 1.x and Spring 2.x that we want to containerize.
The problem we have is in the way this project is configured. It is done through Maven properties and profiles (one for each environment) that are turned into properties files. These properties, at compile time, are placed inside the WAR.
What would be the correct way to create an image of this application without modifying the project code? That is, that somehow the configuration is externalized, for example, in environment variables. Maybe it should be in a volume?
So far what we have achieved is a two-stage Dockerfile, where it first compiles with Maven with a specific profile and then copies the WARs in the second stage from a Tomcat image. But doing it this way the generated Docker image is not environment independent, which is what we want to achieve.
Thanks!

Spring Cloud Config Server provides an HTTP resource-based API for external configuration (name-value pairs or equivalent YAML content). The server is embeddable in a Spring Boot application, by using the #EnableConfigServer annotation.
So will deploy the Spring Cloud config server on one container containing all the environment configurations - https://cloud.spring.io/spring-cloud-config/multi/multi__spring_cloud_config_server.html
Once it's deployed, you can easily deploy your application docker image in different environments using a bootstrap.yml file that accepts the cloud-config server based on the profiles (dev/uat/staging/prod)
###
server:
port: 9092
spring:
application:
name: application-name
cloud:
config:
urI: REPLACE_CLOUD_CONFIG_URI (https://<spring_cloud_config_url>:8888/)
profiles:
active: REPLACE_PROFILE (dev/uat/staging/prod)
management:
endpoints:
web:
exposure:
include: refresh

Related

How to manage multiple Spring profiles with Heroku

I'm setting up a new environment for my application, we only have "prod" environment, I want to create a testing environment, for that, I configured two Spring profiles, "test" and "prod", and created a new branch called "test" where we want to have the test environment and push that branch to master like a kind of "promotion" to production.
This is a extract of our application.yml
spring:
profiles: test
{some properties...}
---
spring:
profiles: prod
{some properties...}
We are using Heroku to deploy our app and repositories from AzureDevOps, where we also have a pipeline that runs when we push commits to master, this pipeline push the AzureDevOps master branch to the Heroku repository. In Heroku we have an application created on "staging", we didn't add a "production" application yet (not sure if it's relevant but I wanted to clarify that).
This is the pipeline:
git checkout $(Build.SourceBranchName)
git remote add heroku https://heroku:$(pat)#git.heroku.com/app-hto.git
git push heroku $(Build.SourceBranchName)
To specify the profile I'm using the Procfile file in my Java project, where we have this:
web: java -Dspring.profiles.active=prod -Dserver.port=$PORT $JAVA_OPTS -jar target/api-0.0.1-SNAPSHOT.jar
As you can see I'm not a Heroku expert so I don't know how to proceed, so, my question is, how can I specify which profile use for each environment? There is a way to accomplish that using AzureDevOps pipelines?
Azure Devops might be able to accomplish that, but it would be complicated.
It will be easier to achieve this with heroku. Heroku itself provides ways to control which profile is active either by cli, dashboard,or api. for details check here
Hope i point to the right direction.

intellij spring boot run cannot load application.yml automatically

my application.yml locate
my application.yml
spring boot run server port
Intellij spring boot run configuration
Hi.
My project is Intellij spring boot 1.5.7 Gradle Project
When Intellij spring boot run cannot load application.yml automatically.
but gradle bootRun is very well run&load.
Please suggestion me.
You should specify profile configuration. From your application.yml, you have multiple configuration separated by "---", this is used for multiple profile configuration for different spring profile. Try removing "---" and specify profile as following :
Multiple configuration is used when you have different configuration for different profile, as following:

Eclipse does not pass mail properties to Spring Boot after migration

I am migrating my Spring Boot application from version 1.5.7 to 2.0.0 and I noticed that it no longer takes mail properties from ENV variables for some reason.
I am using java.mail.Sender and have the following propeties in my application.properties file:
spring.mail.host=smtp.example.com
spring.mail.username=username
spring.mail.password=password
spring.mail.port=587
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.defaultEncoding=UTF-8
This is there just to mock the mail properties in tests. I am injecting the real ones using the same keys as ENV variables: spring.mail.host=smtp.google.com, etc.
But when I try to send the email, I see that it is still using smtp.example.com. I thought that ENV variables had higher priority than values from application.properties. Did something change? Everything worked fine in Spring Boot 1.5.7.
EDIT:
The following command works so it is definitely some problem with Eclipse:
SPRING_PROFILES_ACTIVE=development SPRING_MAIL_HOST=smtp.gmail.com SPRING_MAIL_USERNAME=xxx SPRING_MAIL_PASSWORD=xxx ./gradlew clean bootRun
What I don't understand is why the exact same configuration works, when I switch back to 1.5.7. It is also strange that when passign env variables via Eclipse run configuration, it works for profile. So some env variables are applied and some not...
I was able to recreate this issue. Created a Spring boot App with 1.5.X and injected Environment variables from Eclipse. Now, when I migrate to 2.X release, the environment variables are not getting injected.
On further analysis, found out this interesting thread
One of the Spring-boot developers made this comment
Hence my conclusion is when we are using 2.X release, there is one of the component within Spring-boot-parent which is making the spring boot maven plugin to fork it and run in a separate JVM. Thus, the environment variable is not getting passed.
That answers the question why profile value is picked-up from the environment section. Profile flag is always passed as an argument irrespective of whether the app runs in the maven JVM or a new one
To confirm this, you can add the config entries to the JVM argument tab like the one below
You will now be able to see the new values passed to spring boot
I don't know much about your configurations, but if the project structure is okay with correct dependencies and the application.properties exit under src/main/resources and your startup class annotated with #SpringBootApplication, it should work fine.
you can test if the application reads your properties file by injecting a variable String with annotation #Value inside any class and log or print it.
#Value("${spring.mail.host}")
private String host;
first Make sure your IDE is running on Java 8 or later version .
With Spring Boot 2.0, many configuration properties were renamed/removed and developers need to update their application.properties/application.yml accordingly. To help you with that, Spring Boot ships a new spring-boot-properties-migrator module. Once added as a dependency to your project, this will not only analyze your application’s environment and print diagnostics at startup, but also temporarily migrate properties at runtime for you. This is a must have during your application migration:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
runtime("org.springframework.boot:spring-boot-properties-migrator")
Note Once you’re done with the migration, please make sure to remove this module from your project’s dependencies.
For more information follow this link
Spring Boot 2.X migration guide

Build Managment With Maven and HK2

So far, I have created a web application using JAX-RS (Jersey) and Maven as build and dependency managment, but for this question, I'm not sure it matters. I'm using h2k as DI framework. It works fine and I can package the application as a WAR which can be deployed to a tomcat server (both locally and remote).
The application is configured using jersey's ResourceConfig, where I also configure my AbstractBinder (for h2k) to bind my #Inject to concrete instances. So far so good. Now I want to use Jetty (or grizzly) as an embedded server for local development (by mvn jetty:run), and automate the build of the war for remote deployment. I want to use different classes (injected by hk2) depending on the environment (eg. fake email sender, on test server), and this is where I'm stuck. How do I specify which environment I'm running in and how do I specify which classes to use for each environment?
Maybe my problem is in my understanding of how all this works (Examples of actual build setups would be warmly welcomed). Normally I just use AbstractFactory, which I inject into my main method. My guess on how this should be done:
I should create a properties / xml file for each environment, where I specify which implementations and properties should be used.
When running or building, I should specify which environment I'm running in (for instance mvn build -ENVIRONMENT)

Spring Boot + Gradle - where to put environment configuration?

I was working on a simple application in Spring Boot. It was developed locally (and it works) with:
Gradle,
H2 database with connection properties set in application.properties placed on project's root
Maven folders structure (src/main/groovy, src/main/resources, etc.)
Now it's the time when I'd like to deploy it to the Openshift, so I need to create an additional, production configuration with a MySQL settings, but I don't know where to put it and how to use it.
So my questions are:
What should I do to have two different configurations (development and production)?
Where to put the configuration files?
Do I have to change something in the build.gradle?
How to build the app with a development or production config?
How to run the app with a development or production config?
What are the best practices for creating multiple environment configurations?
I'm rather a frontend dev and all these backend stuff are not obvious for me, so please consider it in your answers.
This is the content of my current build.gradle
plugins {
id 'org.springframework.boot' version '1.5.3.RELEASE'
id 'java'
id 'groovy'
}
jar {
baseName = 'myproject'
version = '0.0.1-SNAPSHOT'
}
repositories {
jcenter()
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile("org.springframework.boot:spring-boot-starter-test")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile 'mysql:mysql-connector-java'
compile("com.h2database:h2")
compile("org.springframework.boot:spring-boot-starter-security")
compile('io.jsonwebtoken:jjwt:0.7.0')
compile localGroovy()
}
What should I do to have two different configurations (development and production)?
In your case, you can use a profiles to achieve it. You can read about it here. For each profile you can have specific application properties file (named application-%PROFILE_NAME%.properties, like application-prod.properties, the same is true for .yml configuration files) And you have to specify what profile yo use then you are starting your app via command line switch for example like so:
--spring.profiles.active=prod
Where to put the configuration files?
Just in the same place as your application.properties file.
Do I have to change something in the build.gradle?
No, you don't need to modify your build script. Since all specific configurations are needed for running your application, not for building.
How to build the app with a development or production config?
You don't need to build it with some specific configuration, just run it with it.
How to run the app with a development or production config?
As it was said earlier - just specify what profile to use when starting the application.
What are the best practices for creating multiple environment configurations?
As for me, if you use a spring - to use profiles and profile specific configuration and bean-definitions.
Create a separate application-dev.properties along side your existing application.properties files as outlined here to contain your h2 config https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties and then activate this when running in dev by passing in the following argument when starting the app --spring.profiles.active=dev you could do the same for production i.e. application-prod.properties and keep the common configuration in application.properties.

Categories