Search code examples
springspring-bootspring-cloudproperties-filespring-cloud-config

Profile based Spring Cloud Config Server client with optional local developer properties


My Goal:

Having the Spring Cloud Config Server import active and provide a way for developers to have an optional property file on their machine.

wanted cfg prio diagram

My Config Server is up and running using org.springframework.cloud:spring-cloud-config-server:3.1.3 and @EnableConfigServer on the main class. Http requests to the concrete endpoint yield the expected result. This server should provide important environment configurations for a developer for his/her local setup.

$ curl http://localhost:8888/test-application/dev
{"name":"test-application","profiles":["dev"],"label":null,"version":null,"state":null,"propertySources":[{"name":"classpath:/cfg/test-application/application-dev.yml","source":{"server.port":1111}},{"name":"classpath:/cfg/test-application/application.yml","source":{"server.port":8000}}]}

Where localhost:8888 is my Config Server and test-application ist the name of the client application (defined via spring.application.name). The provided dev is the currently active profile on the client (The dev profile indicates a locally running software, there is no dev environment).

Clients configuration:

application.yml

spring:
  application:
    name: test-application
  config:
    import:
      - configserver:http://localhost:8888                  # <- pull the configuration from the configserver
      - optional:file:/absolute/path/to/the/project/root/   # <- if there are any additional configuration files, use them

The client uses the following dependencies:

  • org.springframework.boot:spring-boot-starter-web:2.7.0
  • org.springframework.cloud:spring-cloud-starter-bootstrap:3.1.3
  • org.springframework.cloud:spring-cloud-starter:3.1.3
  • org.springframework.cloud:spring-cloud-starter-config:3.1.3

As shown above, the "base" application.yml configured server.port=8000 where the profile specific is set to server.port=1111. When reading the documentation this behaviour is correct. But my local developer configuration contains server.port=2222. This was ignored.

Here comes the problem:

When starting the client application, i can see the following log statements:

Fetching config from server at : http://localhost:8888
Located environment: name=test-application, profiles=[default], label=null, version=null, state=null
Located property source: [BootstrapPropertySource {name='bootstrapProperties-configClient'}, BootstrapPropertySource {name='bootstrapProperties-classpath:/cfg/test-application/application-dev.yml'}, BootstrapPropertySource {name='bootstrapProperties-classpath:/cfg/test-application/application.yml'}]
The following 1 profile is active: "dev"
Tomcat initialized with port(s): 1111 (http)
Initializing Spring embedded WebApplicationContext
Tomcat started on port(s): 1111 (http) with context path ''
Started TestApplicationKt in 2.234 seconds (JVM running for 2.762)

The configuration evaluation result from spring was to choose port 1111 instead of the wanted 2222 within the application-dev.yml located in the project root (developer config).


Wrapped up:

Three config files:

  1. config server application.yml (port: 8000)
  2. config server application-dev.yml (port: 1111)
  3. project root developer config application-dev.yml (port: 2222) <- I want this file to have precedence over the other two.

When running the debugger, i see these found property sources within the injected Environment bean. The wanted developer file is within this list and the property source content is correct (server.port=2222).

Environment runtime snapshot

Does anyone have an idea how to solve this problem?

I have created a project that reproduces this exact behaviour. Link to GitHub.

Thanks in advance!


Solution

  • Is the dev profile active when application is running in dev environment or it's also active when running locally? Ideally you should have 2 different profiles for dev and local and you can enable config server only when dev profile is active. You can rename your local property file as application-local.yml and disable spring cloud config when profile local is active. You can put below code in bootstrap.yml(create new file beside application.yml) and remove config server configurations from application.yml

    ---
    spring:
      application:
        name: test-application
      config:
        activate:
          on-profile: dev
        import:
          - configserver:http://localhost:8888                  # <- pull the configuration from the configserver
          - optional:file:/absolute/path/to/the/project/root/   # <- if there are any additional configuration files, use them
    ---
    spring:
      application:
        name: test-application
      config:
        activate:
          on-profile: local
      cloud:
        config:
          enabled: false
    

    EDIT: Actual fix

    Thanks for sharing reproducible example. All you need to do is remove local application-dev.yml location reference from client application.yml and add it to configServer application.yml as shown in belolow screenshots.

    /client/src/main/resources/application.yml enter image description here

    And put it in configServer application.yml at the end of search-locations. Order matters so please make sure you put overriding location/s at the end.

    /configServer/src/main/resources/application.yml enter image description here

    Build and start both the applications and you will see client application server started on port 2222 enter image description here