Tìm hiểu Spring Cloud Config

1. Tổng quan về Spring Cloud Config

Trong các hệ thống phân tán, Spring Cloud Config được dùng cho mục đích externalized configurationcentralized configuration - tách biệt và tập trung các property của các ứng dụng Spring tại một nơi. Đây là các property có giá trị khác nhau trên các môi trường phát triển (dev, staging, product, ...).

Spring Cloud Config hoạt động theo mô hình kiến trúc client - server, bao gồm: Spring Cloud Config Server và Spring Cloud Config Client.

Spring Cloud Config Server

Các property của các ứng dụng Spring (được lưu trong các property source như file properties hoặc file YAML) được tập trung trên một hệ thống backend: Git repository (mặc định), File System, Vault, JDBC, Redis, ...

Nhiệm vụ của Spring Config Server là pull các property này về và dùng EnvironmentRepository để lưu trữ. EnvironmentRepository cung cấp các đối tượng Spring Environment.

Sau đó cung cấp các property cho Config Client thông qua các HTTP resource-based API (HTTP Method là GET). Chúng ta sẽ tìm hiểu về các API này ở phần sau.

Spring Cloud Config Client

Đây chính là các ứng dụng Spring đã tách biệt các property. Khi startup, Config Client sẽ đọc các property từ API của Config Server và khởi tạo đối tượng Environment với property source phù hợp.

Các API này có các path sau:

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

Trong đó:

  • {application}: map với giá trị spring.application.name trong file bootstrap.yml của Config Client. Hiểu theo một cách khác đây chính là giá trị spring.config.name của Config Client.
  • {profile}: map với giá trị spring.profiles.active trong file bootstrap.yml của Config Client. Nếu có nhiều active profile thì các active profile sẽ được ngăn cách nhau bởi dấu phẩy. Giá trị mặc định là default.
  • {label} (tùy chọn): Git label dùng để gán nhãn version. Giá trị mặc định là master.

Ví dụ:

Git repository có 2 property source là your-service.ymlyour-service-dev.yml. Như vậy:

  • your-service.yml: có {application}your-service{profile}default. Config Server sẽ cung cấp API http://localhost:8888/your-service/default để Config Client đọc được các property từ property source your-service.yml đặt trên hệ thống backend.
  • your-service-dev.yml: có {application}your-service{profile}dev. Config Server sẽ cung cấp API http://localhost:8888/your-service/dev để Config Client đọc được các property từ property source your-service-dev.yml đặt trên hệ thống backend.

Ví dụ, khi call API http://localhost:8888/your-service/default, sẽ trả về một chuỗi JSON như sau:

{
    "name": "your-service",
    "profiles": [
        "default"
    ],
    "label": null,
    "version": "dc63ead663b4acdde42c66195d29044ed08bf89e",
    "state": null,
    "propertySources": [
        {
            "name": "https://github.com/your-git-account/your-config-repository/your-service.yml",
            "source": {
              // This is properties from your-service.yml
            }
        }
    ]
}

2. Spring Cloud Config Server

2.1. Dependency

<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>

<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
  </dependency>
</dependencies>

2.2. Enable Config Server

Config Server được nhúng bên trong một ứng dụng Spring Boot. Để enable Config Server, chúng ta sử dụng annotation org.springframework.cloud.config.server.EnableConfigServer:

ConfigServer.java

@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
  public static void main(String[] args) {
    SpringApplication.run(ConfigServer.class, args);
  }
}

Giống như tất cả các ứng dụng Spring Boot, Config Server mặc định chạy trên cổng 8080. Nhưng thường chúng ta sẽ chuyển sang cổng 8888 để tiện phân biệt.

application.yml

server:
  port: 8888

2.3. Cấu hình thông tin Git Backend

application.yml

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-git-account/your-config-repository
          username: user
          password: secret
          searchPaths: foo,bar*
          timeout: 10

Trong đó:

  • spring.cloud.config.server.git.uri: URI của Git repository.
  • spring.cloud.config.server.git.username: username của Git account.
  • spring.cloud.config.server.git.password: password của Git account.
  • spring.cloud.config.server.git.timeout: timeout (đơn vị là giây) kết nối Git repository. Giá trị mặc định là 5 giây.
  • spring.cloud.config.server.git.searchPaths: các property source có thể đặt bên trong các thư mục con của Git repository.
    • foo: Config Server sẽ pull tất cả các property source bên trong thư mục foo.
    • bar*: Config Server sẽ pull tất cả các property source bên trong các thư mục có tên bắt đầu bằng bar.

3. Spring Cloud Config Client

3.1. Dependency

<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>

<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
  </dependency>
</dependencies>

3.2. Cấu hình thông tin Config Server

bootstrap.yml

spring:
  application:
    name: foo
  profiles:
    active: dev,mysql
  cloud:
    config:
      uri: http://localhost:8888
      username: user
      password: secret
      request-read-timeout: 10

Trong đó:

  • spring.cloud.config.uri: URI của Config Server.
  • spring.cloud.config.username: username để xác thực nếu Config Server thiết lập HTTP Basic security.
  • spring.cloud.config.password: password để xác thực nếu Config Server thiết lập HTTP Basic security.
  • spring.cloud.config.request-read-timeout: timeout (đơn vị là giây) khi chờ đọc dữ liệu từ Config Server API. Giá trị mặc định là 0.

3.3. @RefreshScope

Mặc định, các property sẽ chỉ được đọc một lần duy nhất khi Config Client startup. Tuy nhiên, với các bean cần cập nhật giá trị mới nhất từ Config Server, chúng ta có thể khai báo thêm annotation @RefreshScope.

@RefreshScope
@RestController
class MessageRestController {

    @Value("${message:Hello default}")
    private String message;

    @RequestMapping("/message")
    String getMessage() {
        return this.message;
    }
}

4. Nhúng Config Server trong ứng dụng khác

Trong một số trường hợp, chúng ta cần nhúng trực tiếp Config Server bên trong ứng dụng khác, thay vì để ứng dụng đó gọi trực tiếp đến một standalone Config Server. Ví dụ như nhúng Config Server vào trong Eureka Server

Các bước để thực hiện điều này là:

Bước 1:

Chúng ta chỉ cần dependency của Config Server mà thôi:

pom.xml

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-config-server</artifactId>
</dependency>

Bước 2:

Enable Config Server thông qua annotation @EnableConfigServer.

Bước 3:

Trong bootstrap.yml, chúng ta cấu hình như sau:

spring:
  cloud:
    config:
      server:
        bootstrap: true
        git:
          uri: https://github.com/your-git-account/your-config-repository
          username: user
          password: secret
          searchPaths: foo,bar*
          timeout: 10
        prefix: config

Trong đó:

  • spring.cloud.config.server.bootrap=true => xác nhận ứng dụng tự nó cấu hình là Config Server. Việc này có thể làm chậm quá trình startup ứng dụng.
  • Để tránh conflict với context path hoặc server path của ứng dụng (có thể gây ra lỗi thiếu file CSS chẳng hạn), chúng ta sẽ bổ sung giá trị spring.cloud.config.server.prefix (mặc định là rỗng): đây là prefix của các API của Config Server. Ví dụ: Nếu spring.cloud.config.server.prefix=config, thì API http://localhost:8888/your-service/default sẽ được chuyển thành http://localhost:8761/config/your-service/default. Trong đó localhost:8761 là host và port của Eureka Server.

Bước 4:

Xóa các cấu hình liên quan đến Config Server trong file application.yml vì các cấu hình này là không cần thiết.


Tài liệu tham khảo

  1. https://spring.io/guides/gs/centralized-configuration/

  2. https://cloud.spring.io/spring-cloud-config/spring-cloud-config.html