Spring 微服务技巧:使用环境变量抽象数据库主机名

为任何微服务安全地管理数据库连接字符串至关重要。通常,我们会使用环境变量来保护用户名和密码,却从未考虑过隐藏或掩码数据库主机名。在读写数据库实例中,有些组织会要求不得泄露主机名,并在应用程序启动时通过环境变量在运行时传递主机名。

本文讨论了如何在属性文件中通过环境变量配置主机名。

通过环境变量进行数据库配置

我们通常会以以下方式为 Spring 微服务配置默认连接字符串,数据库用户名和密码作为环境变量传递。

properties 复制代码
server.port=8081
server.servlet.context-path=/api/e-sign/v1
spring.esign.datasource.jdbc-url=jdbc:mysql://localhost:3306/e-sign?allowPublicKeyRetrieval=true&useSSL=false
spring.esign.datasource.username=${DB_USER_NAME}
spring.esign.datasource.password=${DB_USER_PASSWORD}
spring.esign.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.esign.datasource.minimumIdle=5
spring.esign.datasource.maxLifetime=120000

如果我们的微服务连接到一个访问受限的安全数据库,并且数据库管理员或基础设施团队不希望你提供数据库主机名,那么我们就遇到了问题。通常,生产环境下数据库主机名可能如下所示:

properties 复制代码
spring.esign.datasource.jdbc-url=jdbc:mysql://prod-db.fabrikam.com:3306/e-sign?allowPublicKeyRetrieval=true&useSSL=false
spring.esign.datasource.username=${DB_USER_NAME}
spring.esign.datasource.password=${DB_USER_PASSWORD}

使用 @Configuration 类

在这种情况下,管理员或云基础设施团队希望在容器启动时在运行时将主机名作为环境变量提供。其中一个选项是在配置类中构建并拼接连接字符串,如下所示:

java 复制代码
@Configuration
public class DatabaseConfig {

    private final Environment environment;

    public DatabaseConfig(Environment environment) {
        this.environment = environment;
    }

    @Bean
    public DataSource databaseDataSource() {
        String hostForDatabase = environment.getProperty("ESIGN_DB_HOST", "localhost:3306");
        String dbUserName = environment.getProperty("DB_USER_NAME", "user-name");
        String dbUserPassword = environment.getProperty("DB_USER_PASSWORD", "user-password");
        String url = String.format("jdbc:mysql://%s/e-sign?allowPublicKeyRetrieval=true&useSSL=false", hostForDatabase);

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl(url);
        dataSource.setUsername(dbUserName); // 替换为你的实际用户名
        dataSource.setPassword(dbUserPassword); // 替换为你的实际密码
        return dataSource;
    }
}

上述方法可以工作,但我更倾向于使用 application.properties 的方法,这种方法易于使用且相当灵活。属性文件允许你以集中方式整合所有配置,使其更易于更新和管理。它还通过将配置与代码分离来提高可读性。DevOps 团队可以在不更改代码的情况下更新环境变量的值。

通常,我们使用环境变量来设置数据库用户名和密码,并在 application.properties 文件中使用相应的表达式占位符 ${}

properties 复制代码
spring.esign.datasource.username=${DB_USER_NAME}
spring.esign.datasource.password=${DB_USER_PASSWORD}

然而,对于数据库 URL,我们只需要在环境变量中使用主机名,而不是连接字符串,因为不同微服务的每个连接字符串都会有不同的参数。因此,为了解决这个问题,Spring 允许你在连接字符串中使用占位符表达式,如下所示;这提供了灵活性,并且能够继续使用 application.properties 文件的方法,而不是通过数据库配置类来实现。

properties 复制代码
spring.esign.datasource.jdbc-url=jdbc:mysql://${ESIGN_DB_HOST}:3306/e-sign?allowPublicKeyRetrieval=true&useSSL=false

一旦我们决定了上述方法,并且如果出于某种原因需要在较低环境中排查问题,我们就可以使用 ApplicationListener 接口来查看解析后的 URL:

java 复制代码
@Component
public class ApplicationReadyLogger implements ApplicationListener<ApplicationReadyEvent> {

    private final Environment environment;

    public ApplicationReadyLogger(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        String jdbcUrl = environment.getProperty("spring.esign.datasource.jdbc-url");
        System.out.println("Resolved JDBC URL: " + jdbcUrl);
    }
}

如果主机名配置存在问题,它将在应用程序启动时显示为错误。然而,在应用程序启动后,多亏了上述 ApplicationReadyLogger 实现,我们可以在应用程序日志中看到数据库 URL。请注意,我们不应在生产环境中这样做,因为基础设施团队希望对数据库写入主机名保密。

通过上述步骤,我们可以在 application.properties 文件的连接字符串中将数据库主机名配置为环境变量。

总结

使用环境变量为连接数据敏感数据库的主机名可以增强安全性和灵活性,并赋予云基础设施和 DevOps 团队更多权力。使用占位符表达式可以确保我们的配置保持清晰且易于维护。

相关推荐
AskHarries11 分钟前
使用 acme.sh 自动更新 SSL 证书的指南
后端
Chandler2435 分钟前
Go:反射
开发语言·后端·golang
pwzs42 分钟前
深入浅出 MVCC:MySQL 并发背后的多版本世界
数据库·后端·mysql
盒子691042 分钟前
go for 闭环问题【踩坑记录】
开发语言·后端·golang
刘大猫262 小时前
Arthas monitor(方法执行监控)
人工智能·后端·监控
追逐时光者2 小时前
MongoDB从入门到实战之MongoDB简介
后端·mongodb
Huazie3 小时前
在WSL2 Ubuntu中部署FastDFS服务的完整指南
服务器·后端·ubuntu
行者无疆xcc3 小时前
【Django】设置让局域网内的人访问
后端·python·django
嘵奇4 小时前
基于Spring Boot实现文件秒传的完整方案
java·spring boot·后端
Value_Think_Power4 小时前
azure 一个 pod 内有多个 container ,这些container 可以 共享一块磁盘吗
后端