Docker-compose for Spring Boot adaptation for different environements

Viewed 435

I have a Spring boot application running using docker, it works perfectly for my development in local but I want to deploy my app on a dev server using the same docker.

The problem is that I have different application.yaml depending on the environment, like application-local.yaml and application-dev.yaml

This is my docker-compose.yml:

version: "3"

services:
  backend:
    network_mode: "host"
    container_name: hebergement-backend
    build:
      context: .
    restart: unless-stopped
    volumes:
      - /var/lib/hebergement/data:/var/lib/hebergement/data

And the dockerfile:

FROM maven:3.6.3-openjdk-11 AS MAVEN_BUILD
COPY pom.xml /build/
COPY api /build/api/
COPY commons /build/commons/
WORKDIR /build/
RUN mvn package

FROM openjdk:11-jdk-slim
COPY --from=MAVEN_BUILD /build/api/target/*.jar app.jar
COPY --from=MAVEN_BUILD /build/commons/target/*.jar commons.jar
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=local","/app.jar"]

In the Dockerfile, I have my local profile set. Is there a way to change the active profile without editing the Dockerfile, like using a parameter or an env variable?

3 Answers

You can set the active Spring profile(s) using the Spring spring.profiles.active property.

In general, you can set arbitrary Spring properties with environment variables. That means you can set a SPRING_PROFILES_ACTIVE environment variable at deployment time to pick a different profile. In Compose:

version: '3.8'
services:
  backend:
    build: .
    restart: unless-stopped
    volumes:
      - /var/lib/hebergement/data:/var/lib/hebergement/data
    environment:
      - SPRING_ACTIVE_PROFILES=dev
    # (do not need network_mode: or container_name: in normal use)

Since you can set any individual property this way, this also means you can set specific things without putting them in an application.yml file. For container deployments, I've found this approach to be much more flexible than Spring profile files: you can change the property setting at deployment time, without needing to find the properties file in your source tree and rebuild the jar and image.

For example, let's say your application needs a database. In development, you might set up application.yml to point to a database on localhost, but in pre-deployment testing, you might want to run everything in a single Compose setup. You can configure the Spring JDBC properties directly in the docker-compose.yml file:

version: '3.8'
services:
  db:
    image: postgres:13
    environment:
      - POSTGRES_DB=dbname
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=passw0rd
  backend:
    ...
    environment:
      # This URL will not work with network_mode: host
      - SPRING_DATASOURCE_URL=jdbc:postgres://db/dbname
      - SPRING_DATASOURCE_USERNAME=user
      - SPRING_DATASOURCE_PASSWORD=passw0rd
      # Probably don't need an alternate profile

In Dockerfile, define the variable representing the environment passed to the jar:

ARG ENVIRONMENT
...
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=$ENVIRONMENT","/app.jar"]

Now use the build command for docker-compose and pass the variable using `--build-arg:

docker-compose build --build-arg ENVIRONMENT=local

Another way is using the environment file, read more at Environment variables in Compose

Create an entrypoint.sh script file:

#!/usr/bin/env bash

java -jar -Dspring.profiles.active=$PROFILE /app.jar

Dockerfile:

ENV PROFILE local
COPY entrypoint.sh /entrypoint.sh
RUN chmod a+rx /entrypoint.sh

ENTRYPOINT ["./entrypoint.sh"]

docker-compose.yml:

services:
  backend:
    network_mode: "host"
    container_name: hebergement-backend
    build:
      context: .
    environment:
      PROFILE: "local"
    restart: unless-stopped
    volumes:
      - /var/lib/hebergement/data:/var/lib/hebergement/data
Related