Tech Blog

Designing Spring Boot Active Profile Switching Between docker-compose and ECS

by y104
Spring Boot Docker AWS ECS

Introduction

When running a Spring Boot app across multiple environments, it’s crucial to precisely understand which application.yml is being applied.

  • Local development: application-local.yml
  • Docker Compose: application-docker.yml
  • AWS ECS (production): application-prod.yml

This article documents the profile switching design and how to pass configuration on ECS.


Spring Boot Profile Basics

When you create a file named application-{profile}.yml, it is loaded only when that profile is active.

src/main/resources/
  application.yml          ← common to all environments
  application-local.yml    ← for local development
  application-docker.yml   ← for Docker Compose
  application-prod.yml     ← for production (ECS)

How to specify a profile:

# Specify at startup
java -jar app.jar --spring.profiles.active=prod

# Specify via environment variable (Docker-friendly)
SPRING_PROFILES_ACTIVE=prod java -jar app.jar

Configuration Files per Environment

application.yml (common to all environments)

spring:
  application:
    name: dvd-rental-customer-backend
  datasource:
    driver-class-name: org.postgresql.Driver
  jpa:
    open-in-view: false

server:
  port: 8082

application-local.yml

spring:
  datasource:
    url: jdbc:postgresql://localhost:15433/dvdrental
    username: postgres
    password: postgres
  
  thymeleaf:
    cache: false

logging:
  level:
    com.example: DEBUG

application-docker.yml

spring:
  datasource:
    # Connect to DB using Docker Compose service name
    url: jdbc:postgresql://postgres:5432/dvdrental
    username: postgres
    password: postgres

application-prod.yml

spring:
  datasource:
    # Production DB URL obtained from environment variables
    url: ${DATABASE_URL}
    username: ${DATABASE_USERNAME}
    password: ${DATABASE_PASSWORD}

logging:
  level:
    root: WARN
    com.example: INFO

Important: Do not hard-code sensitive production information in yaml. Always pass it via environment variables.


Specifying Profile in Docker Compose

# compose.yml
services:
  app:
    image: dvd-rental-customer-backend:latest
    environment:
      SPRING_PROFILES_ACTIVE: docker  # ← specify here
      TZ: Asia/Tokyo
    ports:
      - "8082:8082"
    depends_on:
      postgres:
        condition: service_healthy
  
  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: dvdrental
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

Specifying Profile on ECS (AWS Fargate)

Set container environment variables in the ECS task definition.

CDK Configuration Example

// cdk/lib/app-stack.ts
const taskDefinition = new ecs.FargateTaskDefinition(this, 'AppTask', {
  memoryLimitMiB: 512,
  cpu: 256,
});

const container = taskDefinition.addContainer('AppContainer', {
  image: ecs.ContainerImage.fromEcrRepository(ecrRepo, 'latest'),
  
  environment: {
    // Environment variables (plain text)
    SPRING_PROFILES_ACTIVE: 'prod',
    TZ: 'Asia/Tokyo',
  },
  
  secrets: {
    // Sensitive info obtained from SSM Parameter Store
    DATABASE_URL: ecs.Secret.fromSsmParameter(
      ssm.StringParameter.fromStringParameterName(this, 'DbUrl', '/dvd-rental/db-url')
    ),
    DATABASE_USERNAME: ecs.Secret.fromSsmParameter(
      ssm.StringParameter.fromStringParameterName(this, 'DbUser', '/dvd-rental/db-username')
    ),
    DATABASE_PASSWORD: ecs.Secret.fromSsmParameter(
      ssm.StringParameter.fromStringParameterName(this, 'DbPassword', '/dvd-rental/db-password')
    ),
  },
  
  logging: ecs.LogDrivers.awsLogs({
    streamPrefix: 'dvd-rental',
    logGroup: logGroup,
  }),
});

How to Verify Profile on ECS

After deployment, verify the correct profile is applied via CloudWatch Logs.

Spring Boot outputs the active profile to logs at startup:

INFO  o.s.b.SpringApplication - The following 1 profile is active: "prod"
INFO  o.s.b.w.embedded.tomcat.TomcatWebServer - Tomcat initialized with port 8082 (http)

Confirm it shows "prod" before considering the deployment complete.

# Verify profile in CloudWatch Logs
aws logs filter-log-events \
    --log-group-name /dvd-rental/app \
    --filter-pattern "profiles is active" \
    --region ap-northeast-1

Common Mistakes

① Forgetting to specify a profile in Docker Compose

Without specifying a profile, the default profile is used.
Even if application-docker.yml exists, it won’t be read.

# NG (no profile specified)
services:
  app:
    environment:
      TZ: Asia/Tokyo

# OK
services:
  app:
    environment:
      SPRING_PROFILES_ACTIVE: docker  # ← required
      TZ: Asia/Tokyo

② Including local application-local.yml in the Docker image

If the production image contains local connection info like localhost:15433, it may be referenced unintentionally.

# Exclude in .dockerignore
src/main/resources/application-local.yml

③ Getting uppercase/lowercase wrong for environment variables

Spring Boot accepts both SPRING_PROFILES_ACTIVE (all caps, underscore-separated) and spring.profiles.active (dot-separated).
For Docker environment variables, use the all-caps underscore format.


Summary

EnvironmentProfileHow to Set
Local developmentlocalIDE Run config or JVM args
Docker Composedockerenvironment: SPRING_PROFILES_ACTIVE: docker
ECS (production)prodTask definition environment
  • Do not hard-code sensitive info in application-prod.yml; pass it via environment variables or SSM
  • After deployment, always verify “active profile” in CloudWatch Logs
  • Keep profile names simple — around three types: local, Docker, and production — rather than creating one per environment

Article Map for This Series

Building a DVD Rental App for End Users — Overall Vue 3 + Spring Boot Structure with Admin App and Article Map
Building a DVD Rental Admin App with Spring Boot + Thymeleaf Based on the dvdrental Sample DB

Feel free to send a message

Please send a message if you have any technical questions, feedback, or inquiries.