基于现代服务的云原生十二要素理论,我们在采用容器化部署时,要保证同一个镜像可以满足不同环境的部署要求,而不是不同环境打包不同的景象。本文档主要介绍一种基于 spring 框架的满足不同环境配置的编译打包方案,满足同一个镜像可以在环境分组下通过启动项配置实现不同环境的部署。
我们见过最常见的配置文件管理方案,是基于 Maven 的 profile 配置来实现多环境切换的,它的弊端在于,我们将 profile 配置在 pom.xml 中,每次编译打包时,需要通过编译指令 - P 来标识当前环境配置。这样导致的问题是,我们打包的镜像具有了环境属性,不符合一个镜像多环境部署的要求。
还有一种配置方案,就是基于 Spring profile 进行配置文件管理。针对这两种方案,我接下来会进行一些分析和对比。
a. 两种 profiles 方案对比
1. Maven 的 profiles:
◦ Maven 的 profiles 是在构建时根据环境或其他条件激活不同的配置集合。可以在项目的pom.xml文件中定义多个 profile,并使用 Maven 命令行参数或其他配置来激活特定的 profile。
◦ 优势:
▪ 灵活性高,可以根据不同的构建环境或条件激活不同的 profile。
▪ 可以在构建过程中使用不同的依赖、插件配置等。
◦ 劣势:
▪ 配置相对分散,需要在 Maven 的pom.xml文件中定义和管理多个 profile。
▪ 配置与代码分离,不够直观。
2. Spring 的Application.properties的 profile 配置:
◦ Spring 的application.properties文件可以根据激活的 profile 来加载不同的配置。可以在application.properties文件中定义多个 profile 下的配置,并使用配置文件或环境变量来激活特定的 profile。
◦ 优势:
▪ 配置集中,可以在一个文件中定义多个 profile 下的配置,更易于管理和维护。
▪ 配置与代码相近,更直观易读。
◦ 劣势:
▪ 激活 profile 的方式相对有限,通常需要通过配置文件或环境变量来指定。
▪ 不适用于构建过程中的配置,主要用于应用程序的运行配置。
总的来说,Maven profiles 更适用于构建过程中的配置,可以根据构建环境或条件激活不同的 profile,而 Spring 的application.properties的 profile 配置更适用于应用程序的运行配置,可以根据不同的 profile 加载不同的配置。具体选择哪种方式取决于你的需求和偏好。
b. 在云原生和容器化的部署场景分析
在云原生和容器化的部署场景下,我更倾向使用 Spring 的application.properties的 profile 配置方式。
以下是在云原生和容器化部署场景下,使用application.properties的 profile 配置方式的优势:
综上所述,使用 Spring 的 application.properties 的 profile 配置方式更适合云原生和容器化的部署场景,因为它提供了环境无关性、配置集中化和容器友好性的优势。
以下方案以 springboot 为例,当然 springMVC 方案也是可以适配,只是需要额外配置一下,介于我们新项目基本都是基于 springboot 搭建,此处不展开 springMVC 的实线方案,如有需要,我再额外提供 mvc 的配置方案。
a. 配置文件树
如上图所示
具体行云部署里的配置如下:
b. properties 文件加载
正常情况下,properties/**/*.properties 下的配置文件是不会自动加载到启动项里的。所以需要通过额外的方式动态加载,具体方法是通过 spring 框架下的 PropertySourcesPlaceholderConfigurer 的类属性,结合环境变量,动态批量加载配置文件。(额外说明,如果是 springMVC 框架,也可以通过 xml 配置 context:property-placeholder 属性来实现。)
具体代码如下:
/**
* 配置文件环境配置
* @Author zhaoyongping
* @date 2023/7/10 15:13
* @ClassName EnvPropertiesConfig
* @Descripiton 配置文件环境配置
**/
@Configuration
public class EnvPropertiesConfig {
/**
* 加载属性配置
* @param environment 环境属性
* @return PropertySourcesPlaceholderConfigurer
* @author zhaoyongping
* @date 2023/7/10 15:13
* @description 加载属性配置
*/
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfig(Environment environment) throws IOException {
PropertySourcesPlaceholderConfigurer config = new PropertySourcesPlaceholderConfigurer();
String[] activeProfiles = environment.getActiveProfiles();
if (activeProfiles.length > 0) {
String resourceUrl = "classpath:properties/"
+ environment.getActiveProfiles()[0] + "/*.properties";
config.setLocations(
new PathMatchingResourcePatternResolver().getResources(resourceUrl));
} else {
//兜底策略
config.setLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:properties/dev/*.properties"));
}
return config;
}
}
通过以上步骤,我们可以实现编译打包镜像不需要跟环境变量绑定,而只需要在启动运行时基于不同的分组动态配置的 applicAIton.properties 文件,来实现不同环境的适配。这种可以在运行时变更配置文件的机制,更适合在云原生时代下的容器化部署方案,也利于我们的服务的可移植性。当然,以上只是笔者个人的一个实践经验,并不能代表它是最优实践方案。
作者:京东物流 赵勇萍
来源:京东云开发者社区 自猿其说 Tech 转载请注明来源