Spring profiles

Things to keep in mind

Is it a good idea to use “dev” as the default profile?

By default, the application should have as much restrictions as possible and default profile should not be ‘dev’ (because in dev mode you can have opened debug ports, so on, and you can just forget to disable all such debug stuff later).

How to handle profiles in deployed environments?

How is the name of the profile to be used specified for deployed environments? Without putting an entry in application.properties file like profile=default or profile=develop or profile=production?

If you don’t specify a profile specifically, spring works with the default profile. All the properties that you want to use in the local computer can go into the application-default.properties" file.

For the rest of the environments, we need to set-up environment specific property files like application-develop.properties, application-prod.properties, etc.

For deployed environments, the name of the profile must be injected while the application is being deployed and started. What is the process to do that?

It is done using the docker-entrypoint.sh file. docker-entrypoint.sh is used in Dockerfile.

Configuring profiles using docker-entrypoint.sh

 #!/bin/bash

 echo Container TIER is: "$TIER"
 echo Container AWS_REGION is: "$REGION"
 # These are injected from the pipeline

 case "$TIER" in
      "prod")
            LOG_LEVEL="WARN"
            COMPANY_ENV="prod"
      ;;
      "uat" | "qa" | "stage")
            LOG_LEVEL="INFO"
            COMPANY_ENV=$(echo "$TIER" | tr '[A-Z]' '[a-z]')
      ;;
      *)
            LOG_LEVEL="INFO"
            COMPANY_ENV="dev"
      ;;
 esac
 # end of case statement

 case "$REGION" in
 "us-east-1" | "us-east-2"
     TIMEZONE="America/New_York"
 ;;
 "us-west-1" | "us-west-2"
     TIMEZONE="America/Los_Angeles"
 ;;
 *)
     TIMEZONE="America/New_York"
 ;;
 esac
 # end of case statement

COMPANY_ENV_REGION="$COMPANY_ENV"-"$REGION"

 echo Container COMPANY_ENV_REGION is: "$COMPANY_ENV_REGION"
 echo Container TIMEZONE is: "$TIMEZONE"

 java \
   -XX:MaxRAMPercentage=75.0 \
   -XshowSettings:vm \
   -javaagent:BOOT-INF/lib/aws-opentelemetry-agent-1.17.0.jar \
   -Duser.timezone="${TIMEZONE}" \
   -Dspring.profiles.active=${COMPANY_ENV},${COMPANY_ENV_REGION} \
   -Dotel.javaagent.configuration-file=BOOT-INF/classes/application-${COMPANY-ENV}.properties \
   -Dotel.javaagent.extensions=BOOT-INF/lib/edm-opentelemetry-extension-1.4.jar \
   org.springframework.boot.loader.JarLauncher

Config for S3 based on different profiles

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;

@Configuration
public class AmazonS3ClientConfig {

     @Value("${cloud.aws.credentials.accessKey}")
     private String awsId;

     @Value("${cloud.aws.credentials.secretKey}")
     private String awsKey;

     @Value("${cloud.aws.region.static}")
     private String awsRegion;

     @Value("${proxy.host}")
     private String proxyHost;

     @Value("${proxy.port}")
     private String proxyPort;

     @Value("${proxy.username}")
     private String proxyUserName;

     @Value("${proxy.password}")
     private String proxyPassword;

     private AmazonS3 amazonS3;

     // To be used in local development workspace. Using credentials. Avoid this as much as possible.
     @Bean
     @Profile("default")
     public AmazonS3 s3client() {

             BasicAWSCredentials awsCredentials = new BasicAWSCredentials(awsId, awsKey);
             AmazonS3 amazonS3Client = AmazonS3ClientBuilder.standard().withRegion(Regions.fromName(awsRegion))
                             .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)).build();

             return amazonS3Client;
     }

     // To be used in local development workspace. Using proxy.
     @Bean
     @Profile("default")
     public AmazonS3 amazonS3() {
            amazonS3 = AmazonS3ClientBuilder
                       .standard()
                       .withClientCredentials(new ProfileCredentialsProvider("saml"))
                       .withRegion(Regions.fromName(awsRegion))
                       .withClientConfiguration(
                            PredefinedClientConfigurations.defaultConfig()
                                .withProxyHost(proxyHost)
                                .withProxyPort(Integer.parseInt(proxyPort))
                                .withProxyUsername(proxyUserName)
                                .withProxyPassword(proxyPassword)
                        )
                       .build();

             return amazonS3Client;
     }

     // To be used in deployed environments
     @Bean
     @Profile("!default")
     public AmazonS3 amazonS3() {
            amazonS3 = AmazonS3ClientBuilder
                       .standard()
                       .withRegion(Regions.fromName(awsRegion))
                       .build();

             return amazonS3Client;
     }

}

For examples about using BasicAWSCredentials, look at the internal examples.

https://github.com/explorer436/programming-playground/tree/main/java-playground/spring-cloud-examples/spring-cloud-aws-s3

Tags

Docker