Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Profiles are not active when the environment is prepared with an AOT-optimized application #41562

Closed
klopfdreh opened this issue Jul 19, 2024 · 8 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@klopfdreh
Copy link

I am not sure whether to file the issue here or to Spring Cloud Config directly because I don't know at which part the issue occurs.

I want to port an application to Spring Boot Native with Spring Cloud Config. We followed the documentation of

Spring Boot Native here: https://docs.spring.io/spring-boot/reference/packaging/native-image/index.html and

Spring Cloud Config Native here: https://docs.spring.io/spring-cloud-config/docs/current/reference/html/#_aot_and_native_image_support_2

I created a repository to demonstrate the issue: https://github.com/klopfdreh/native-cloud-config-test and provided 9 steps in the README.md to reproduce it.

Short summary: Spring AOT processes the application with the profile native_runtime which the running application logs as active on startup. From the config server how ever the definition of the profile is not fetched - only default.

What we wanted is that the native image is running with no profile active and only the default configuration is used.

The logging that a profile is active and not fetched from the config server is somehow confusing.

Comparison:

Java Application with native_runtime profile activated:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.1)

2024-07-19T13:48:10.853+02:00  INFO 8811 --- [Config Client Application] [           main] n.c.c.t.client.ConfigClientApplication   : Starting ConfigClientApplication using Java 18.0.1 with PID 8811 (/Users/klopfdreh/Documents/Projects/native-cloud-config-test/client/target/classes started by klopfdreh in /Users/klopfdreh/Documents/Projects/native-cloud-config-test)
2024-07-19T13:48:10.855+02:00  INFO 8811 --- [Config Client Application] [           main] n.c.c.t.client.ConfigClientApplication   : The following 1 profile is active: "native_runtime"
2024-07-19T13:48:10.871+02:00  INFO 8811 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Fetching config from server at : http://127.0.0.1:8888
2024-07-19T13:48:10.871+02:00  INFO 8811 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Located environment: name=application, profiles=[default], label=null, version=null, state=null
2024-07-19T13:48:10.871+02:00  INFO 8811 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Fetching config from server at : http://127.0.0.1:8888
2024-07-19T13:48:10.871+02:00  INFO 8811 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Located environment: name=Config Client Application, profiles=[native_runtime], label=null, version=null, state=null
2024-07-19T13:48:10.871+02:00  INFO 8811 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Fetching config from server at : http://127.0.0.1:8888
2024-07-19T13:48:10.871+02:00  INFO 8811 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Located environment: name=Config Client Application, profiles=[default], label=null, version=null, state=null
2024-07-19T13:48:11.043+02:00  INFO 8811 --- [Config Client Application] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.

Native Application:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.1)

2024-07-19T11:22:17.919Z  INFO 1 --- [Config Client Application] [           main] n.c.c.t.client.ConfigClientApplication   : Starting AOT-processed ConfigClientApplication using Java 17.0.10 with PID 1 (/native-image/config-client-application started by ? in /native-image-build)
2024-07-19T11:22:17.919Z  INFO 1 --- [Config Client Application] [           main] n.c.c.t.client.ConfigClientApplication   : The following 1 profile is active: "native_runtime"
2024-07-19T11:22:17.919Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Fetching config from server at : http://host.docker.internal:8888
2024-07-19T11:22:17.919Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Located environment: name=application, profiles=[default], label=null, version=null, state=null
2024-07-19T11:22:17.919Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Fetching config from server at : http://host.docker.internal:8888
2024-07-19T11:22:17.919Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Located environment: name=Config Client Application, profiles=[default], label=null, version=null, state=null
2024-07-19T11:22:17.931Z  INFO 1 --- [Config Client Application] [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2024-07-19T11:22:17.932Z  INFO 1 --- [Config Client Application] [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.5.2.Final
2024-07-19T11:22:17.933Z  INFO 1 --- [Config Client Application] [           main] o.h.c.internal.RegionFactoryInitiator    : HHH000026: Second-level cache disabled

Native Application with env var SPRING_PROFILES_ACTIVE=native_runtime activated:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.1)

2024-07-19T11:54:13.945Z  INFO 1 --- [Config Client Application] [           main] n.c.c.t.client.ConfigClientApplication   : Starting AOT-processed ConfigClientApplication using Java 17.0.10 with PID 1 (/native-image/config-client-application started by ? in /native-image-build)
2024-07-19T11:54:13.945Z  INFO 1 --- [Config Client Application] [           main] n.c.c.t.client.ConfigClientApplication   : The following 1 profile is active: "native_runtime"
2024-07-19T11:54:13.945Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Fetching config from server at : http://host.docker.internal:8888
2024-07-19T11:54:13.945Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Located environment: name=application, profiles=[default], label=null, version=null, state=null
2024-07-19T11:54:13.945Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Fetching config from server at : http://host.docker.internal:8888
2024-07-19T11:54:13.945Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Located environment: name=Config Client Application, profiles=[native_runtime], label=null, version=null, state=null
2024-07-19T11:54:13.945Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Fetching config from server at : http://host.docker.internal:8888
2024-07-19T11:54:13.945Z  INFO 1 --- [Config Client Application] [           main] o.s.c.c.c.ConfigServerConfigDataLoader   : Located environment: name=Config Client Application, profiles=[default], label=null, version=null, state=null
2024-07-19T11:54:13.970Z  INFO 1 --- [Config Client Application] [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2024-07-19T11:54:13.974Z  INFO 1 --- [Config Client Application] [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.5.2.Final
2024-07-19T11:54:13.976Z  INFO 1 --- [Config Client Application] [           main] o.h.c.internal.RegionFactoryInitiator    : HHH000026: Second-level cache disabled
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 19, 2024
@wilkinsona
Copy link
Member

It is to be expected that the native_runtime profile is active at runtime if it was active at build time:

When AOT optimizations are included, some decisions that have been taken at build-time are hard-coded in the application setup. For instance, profiles that have been enabled at build-time are automatically enabled at runtime as well.

The profile's set in the initialiser that's generated by Spring Framework. For your client application, that initialiser looks like this:

@Generated
public class ConfigClientApplication__ApplicationContextInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
  @Override
  public void initialize(GenericApplicationContext applicationContext) {
    DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
    beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
    beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
    applicationContext.getEnvironment().addActiveProfile("native_runtime");
    addImportAwareBeanPostProcessors(beanFactory);
    new ConfigClientApplication__BeanFactoryRegistrations().registerBeanDefinitions(beanFactory);
    new ConfigClientApplication__BeanFactoryRegistrations().registerAliases(beanFactory);
  }

  /**
   * Add ImportAwareBeanPostProcessor to support ImportAware beans.
   */
  private void addImportAwareBeanPostProcessors(DefaultListableBeanFactory beanFactory) {
    Map<String, String> mappings = new HashMap<>();
    mappings.put("org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration", "org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration$CglibAutoProxyConfiguration");
    RootBeanDefinition beanDefinition = new RootBeanDefinition(ImportAwareAotBeanPostProcessor.class);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    beanDefinition.setInstanceSupplier(() -> new ImportAwareAotBeanPostProcessor(mappings));
    beanFactory.registerBeanDefinition("org.springframework.context.annotation.internalImportAwareAotProcessor", beanDefinition);
  }
}

The call to add native_runtime as an active profile is happening too late to influence the loading of config data but early enough to influence the log message that lists the active profiles. I agree that this is confusing and we'll have to see if we can improve the situation. In the meantime, please run the native application with the native_runtime profile explicitly activated.

@klopfdreh
Copy link
Author

klopfdreh commented Jul 19, 2024

Hey @wilkinsona - thanks a lot for the fast feedback. It would be great to see this fix soon as we need to adjust our build / runtime environment to add an additional profile which overrides the properties set by the aot-process.

Example:

  1. Build process uses profile native_build and h2 database definitions to initialize the corresponding beans during aot-process
  2. Runtime uses native_build from aot-process and overrides it with native_runtime which overrides the database definitions with postgresql, so that the native application connects to the real database

This way you can easily see that the build profile is merged with the runtime profile. The load hierarchy would be default > native_build > native_runtime

Can you label this ticket correspondingly?

@wilkinsona
Copy link
Member

Can you explain why there's some urgency for a fix? If we do something here, I think it will be to ensure that native_build is "fully" active so that it affects the loading of config data. You can achieve the same yourself by explicitly setting the native_build profile as active when running the native image. You can then also set native_runtime active as well if needs be.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Jul 19, 2024
@klopfdreh
Copy link
Author

klopfdreh commented Jul 19, 2024

The issue is not to fully enable native_build but to ensure that all profiles are enabled in the correct order and the configuration are acquired correctly as we rely on heavy configured spring cloud task applications.

Because of aot-process I guess there is no way to change the profile order, is there?

native_runtime should override all properties of native_build

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jul 19, 2024
@snicoll
Copy link
Member

snicoll commented Jul 19, 2024

The issue is not to fully enable native_build but to ensure that all profiles are enabled in the correct order

Just specify the active profiles as they should be loaded as Andy already explained. The AOT processed code will enable the profile only if it hasn't been enabled previously.

@klopfdreh
Copy link
Author

So basically this way: SPRING_PROFILES_ACTIVE=native_build,native_runtime?

If yes there is indeed no urgency. 👍

@klopfdreh
Copy link
Author

Hey @snicoll and @wilkinsona - again thanks a lot for the help! 🎉

As mentioned in the comment: #41562 (comment) - just to summarize: We are going to separate the YML file into 3 profiles:

  1. default - defines all properties valid for build and runtime
  2. native_build - defines all properties for the aot-process like h2 in memory database to not perform any kind of db connections
  3. runtime - defines all properties for the actual runtime in any environment

Changes: klopfdreh/native-cloud-config-test@38c9379

To run the image we are going to use: docker run --rm -e SPRING_JPA_DATASOURCE_HOST=host.docker.internal -e SPRING_PROFILES_ACTIVE=native_build,runtime <image_id> so that all profiles are activated in the correct order. (Also native_build which is needed due to the late initialization to influence the the loading of config data)

@philwebb philwebb added the for: team-meeting An issue we'd like to discuss as a team to make progress label Jul 22, 2024
@wilkinsona wilkinsona added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged status: feedback-provided Feedback has been provided for: team-meeting An issue we'd like to discuss as a team to make progress labels Aug 19, 2024
@wilkinsona wilkinsona added this to the 3.4.x milestone Aug 19, 2024
@snicoll snicoll self-assigned this Sep 30, 2024
@snicoll snicoll changed the title Spring Boot profiles not respected when fetching configuration files from Spring Cloud Config after native build Profiles are not active when the environment is prepared with an AOT-optimized application Oct 2, 2024
@snicoll snicoll modified the milestones: 3.4.x, 3.4.0-RC1 Oct 2, 2024
@snicoll snicoll closed this as completed in 6b216f1 Oct 2, 2024
@klopfdreh
Copy link
Author

Thanks a lot for fixing this. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants