微服务配置:Spring Cloud Config Server教程


【编者的话】本文我们使用Spring构建了一个微服务应用程序,并为其创建了一个配置服务器。

配置微服务:挑战

在传统单体式应用中管理配置很直接,配置文件基本位于应用所在服务器上。如果需要更新配置文件,只需要修改属性文件并重启应用就可以。但是对于微服务来说,事情稍微有些复杂。

微服务由很多小的匿名服务构成,每个都有其配置文件,分布在不同的多个服务器的多个服务中。在生产环境,每个服务都可能有多个实例,配置管理更是很复杂的任务。

云应用会更加复杂,云环境倾向于规模不确定的扩展式应用,这种不确定性给升级和确保正确配置带来挑战。

集中管理配置

顾名思义,每个实例运行时从配置集中管理库中获得其配置文件。

Spring通过Spring Cloud的子项目Spring Cloud Config完成这一任务。可以通过它创建通过REST API提供服务的Spring Boot应用。服务通过REST API获得应用配置文件,此文件是保存在Git库中,因此可以进行版本控制。Spring Cloud Config可以选择本地库或者远程库。生产环境中,最好通过访问Git私有库。

示例

本篇文章将会配置一个可以从GitHub上拉配置的服务,将演示一个银行账号服务如何使用其它服务提供的配置。参考如下架构图,源代码可以从GitHub上获得。
1.png

创建Cloud Config Service

我们将从为Config Service创建一个简单的Spring Boot应用开始。在主应用程序类内部,@EnableConfigServer用于启动配置服务器功能。
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
    SpringApplication.run(ConfigServerApplication.class, args);
}


配置POM

为了使所需的Spring Cloud依赖关系可用,你需要将以下依赖关系添加到POM。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0                         http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.briansjavablog.microservices</groupId>
<artifactId>config-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>config-server</name>
<description>Demo config server provides centralised configuration for various micro services</description>
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.3.RELEASE</version>
</parent>
<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <java.version>1.8</java.version>
  <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
  <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-config-server</artifactId>
  </dependency>
  <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-devtools</artifactId>
     <scope>runtime</scope>
  </dependency>
</dependencies>
<dependencyManagement>
  <dependencies>
     <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
     </dependency>
  </dependencies>
</dependencyManagement>
<build>
  <plugins>
     <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
     </plugin>
  </plugins>
</build>
</project>-

对Config Service进行配置

接下来,需要通过application.properties文件配置配置服务。
spring.application.name=config-server
server.port=8888
# URI of GIT repo containing properties
spring.cloud.config.server.git.uri=https://github.com/briansjavablog/micro-services-spring-cloud-config
# path to properties from root of repo 
spring.cloud.config.server.git.searchPaths: configuration
logging.level.org.springframework.web=INFO

  • 第一行,spring.application.name指定应用名。尽管不是必须的,但是最佳实践建议通过这一步定义出现在endpoint上的名字。
  • 第二行,server.port指定admin应用运行在哪个端口上
  • 第五行,spring.cloud.config.server.git.uri指定包含配置文件的路径。
  • 第八航,spring.cloud.config.server.git.seachPaths指定配置文件的绝对路径。


运行Cloud Config Service

现在可以运行一个测试,可以在Eclipse或者命令行启动应用,并在端口8888上看到它。
2.png

测试

你可以通过调用http://localhost:8888/bank-account-service/default来测试服务。该GET请求包含名称的名称和我们要加载的属性的配置文件。在这种情况下,我们正在寻找属于bank-account-service的属性,并且希望这些属性与默认配置文件相关联。

收到请求后,Config Service将使用application.properties文件中的GIT URI 来执行远程存储库的git clone。下面的屏幕快照显示了正在克隆到本地temp目录的存储库,并包括以下行。

添加属性源:file:/C:/Users/BRIANS~1/AppData/Local/Temp/config-repo-6545303057095204707/configuration/bank-account-service.properties
3.png

然后,Config Service读取bank-account-service.properties中的属性,并以JSON形式返回给客户端,如下所示。

Config Service Response

{
"name": "bank-account-service",
"profiles": ["default"],
"label": null,
"version": "7b0732778b442726f8dd0bf7d1a36fc00f15c5b8",
"state": null,
"propertySources": [{
  "name": "https://github.com/briansjavablog/micro-services-spring-cloud-config/configuration/bank-account-service.properties",
  "source": {
      "bank-account-service.minBalance": "99",
      "bank-account-service.maxBalance": "200"
  }
}]


name属性包含我们请求的属性名称。在这种情况下,我们要求提供bank-account-service。请注意,这与GitHub中默认属性文件的名称匹配。

profiles属性是请求中指定的Spring概要文件。 在这种情况下,我们使用了默认配置文件,但是我们可以在此处指定所需的任何有效配置文件。 如果查看GitHub上的属性文件,你将看到三个文件:
  • bank-account-service.properties:此文件包含默认属性,并且在请求上指定默认配置文件时,它将用作属性源。
  • bank-account-service-dev.properties:此文件具有'-dev'后缀,并且包含在请求中指定开发配置文件时返回的属性。
  • bank-account-service-uat.properties:此文件带有'-uat'后缀,并包含在请求中指定了uat配置文件时返回的属性。


如果我们指定dev或uat作为配置文件,则Config Service将从与该配置文件匹配的文件中返回属性。

该version属性是要返回的属性的当前提交状态。如果你选中GitHub,则它将与最新提交的提交方式匹配。最后,该propertySources属性包含要返回的属性的GitHub源URI以及实际属性值。

创建Bank Account Service

现在创建一个bank account service调用以上属性。Bank Account Service有两个服务,一个是创建账号,一个是接受账号。
@RestController
@Slf4j
public class BankAccountController {
@Autowired
public BankAccountService bankAccountService;
@PostMapping("/bank-account")
public ResponseEntity << ? > createBankAccount(@RequestBody BankAccount bankAccount, HttpServletRequest request) throws URISyntaxException {
bankAccountService.createBankAccount(bankAccount);
log.info("created bank account {}", bankAccount);
URI uri = new URI(request.getRequestURL() + "bank-account/" + bankAccount.getAccountId());
return ResponseEntity.created(uri).build();
}
@GetMapping("/bank-account/{accountId}")
public ResponseEntity<BankAccount> getBankAccount(@PathVariable("accountId") String accountId) {
BankAccount account = bankAccountService.retrieveBankAccount(accountId);
log.info("retrieved bank account {}", account);
return ResponseEntity.ok(account);
}


REST控制器使用简单的BankAccountService创建和检索银行帐户详细信息。生成一个新账号时,服务会通过一系列最大最小值检查账号是否有结余。
/**
* Add account to cache

* @param account
*/
public void createBankAccount(BankAccount account) {
/* check balance is within allowed limits */
if(account.getAccountBlance().doubleValue() >= config.getMinBalance() &&
  account.getAccountBlance().doubleValue() <= config.getMaxBalance()) {
log.info("Account balance [{}] is is greater than lower bound [{}] and less than upper bound [{}]",
    account.getAccountBlance(), config.getMinBalance(), config.getMaxBalance());
accountCache.put(account.getAccountId(), account);
}
else {
log.info("Account balance [{}] is outside of lower bound [{}] and upper bound [{}]",
    account.getAccountBlance(), config.getMinBalance(), config.getMaxBalance());
throw new InvalidAccountBalanceException("Bank Account Balance is outside of allowed thresholds");
}


Bank Account Service Config

最大最小值可以配置,并从输入的Configuration对象读入。
@Service
@Slf4j
public class BankAccountService {
@Autowired
private Configuration config;

Configuration对象的定义如下:
@Component
@ConfigurationProperties(prefix="bank-account-service")
public class Configuration {
@Setter
@Getter
private Double minBalance;
@Setter
@Getter
private Double maxBalance;


有两个注意点:
  • @ConfigurationProperties前缀与GitHub中属性文件的名称匹配
  • 属性文件中每个属性的键是<fileName>。<propertyName>,其中属性名称与@Configuration类中的实例变量名称相同。。


GitHub的截屏显示@Configuration类中的名字和属性值。
4.png

Bank Account Service本地配置

使用Bank Account Service配置之前, 还是有一些需要本地配置的地方:
spring.application.name=bank-account-service
server.port=8080
spring.config.cloud.uri=htp://localhost:8888
spring.cloud.config.profile=uat
management.endpoints.web.exposure.include=*

第1行和第2行是标准的引导配置,定义了应用程序名称和端口。第3行定义了Config Service的URL。这是Bank Account Service在启动时将调用的URL,以检索minBalance和maxBalance属性。第4行定义了用于调用Config Service的配置文件。因此,根据上述配置,将为bank-account-service和UAT配置文件调用配置服务,如下所示:
http://localhost:8888/bank-account-service/uat.

测试Bank Account Service

在命令行或Eclipse中启动Bank Account Service。在日志中,你应该使用application.properties中配置的uat配置文件在http://localhost:8888上看到对Config Service的调用。
5.png

现在,我们可以测试应用程序,并确认从Config Service中检索了uat配置。运行以下cURL命令以创建一个新的bank account。
curl -i -H "Content-Type: application/json" -X POST -d '{"accountId":"B12345","accountName":"Joe Bloggs","accountType":"CURRENT_ACCOUNT","accountBlance":1250.38}' localhost:8080/bank-account

注意现在的账号余额是1250.38英镑,处在UAT定义账户操作范围之内。
6.png

下面的日志摘录显示一个帐户对象已成功创建,最小值和最大值分别为501.0和15002.0。 这些值与GitHub中UAT属性中定义的值匹配。
7.png

更新服务配置

通过Git上传配置,并且能够在客户端启动时候自动获得最新配置信息。但是如果运行中,如何更新配置信息呢?幸运的是Spring Boot提供了一个机制可以在运行实例中更新配置的机制。
curl localhost:8080/actuator/refresh -d {} -H "Content-Type: application/json

从截屏可以看到,/refresh被调用,可以通过UAT来接收最新属性。
8.png

自动更新服务

将配置更改推送到GitHub后,如果我们不得不获取每个服务的IP并手动调用其/refresh端点,那将很麻烦。 我们可以轻松地创建一个脚本来轮询属性存储库中的更改,然后使用某种服务发现机制来获取所有已注册的服务实例并调用其/refresh端点。 与集中式Config Service一起使用的一些简单脚本可以使你以最小的努力在整个微服务中推送配置更改。

总结

本篇文章中使用Spring Cloud Config创建一个基于Github的集中配置管理机制。也介绍了管理不同环境下属性的方法。 这篇文章的完整源代码可在GitHub上找到。有任何问题,可以和本博主联系。

原文链接:Microservice Configuration: Spring Cloud Config Server Tutorial(翻译:杨峰)

0 个评论

要回复文章请先登录注册