Spring Cloud 系列之 Config 配置中心(一)
阿新 • • 發佈:2020-05-11
## 服務配置現狀
配置檔案是我們再熟悉不過的,在微服務系統中,每個微服務不僅僅只有程式碼,還需要**連線其他資源**,例如資料庫的配置或功能性的開關 MySQL、Redis 、Security 等相關的配置。除了專案執行的基礎配置之外,還有一些配置是與我們業務有關係的,比如說七牛儲存、簡訊和郵件相關,或者一些業務上的開關。
但是隨著微服務系統的不斷迭代,整個微服務系統可能會成為一個**網狀結構**,這個時候就要考慮整個微服務系統的**擴充套件性、伸縮性、耦合性**等等。其中一個很重要的環節就是**配置管理**的問題。
## 常規配置管理解決方案缺點
- 硬編碼(需要修改程式碼、繁瑣、風險大)
- properties 或者 yml(叢集環境下需要替換和重啟)
- xml(重新打包和重啟)
## 為什麼使用 Spring Cloud Config
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/config2.jpg)
由於常規配置管理有很大的缺點,所以採用 Spring Cloud Config **集中式**的配置中心來管理**每個服務**的配置資訊。
Spring Cloud Config 在微服務分散式系統中,採用 **Server 服務端**和 **Client 客戶端**的方式來提供可擴充套件的配置服務。服務端提供配置檔案的儲存,以介面的形式將配置檔案的內容提供出去;客戶端通過介面獲取資料、並依據此資料初始化自己的應用。
配置中心負責**管理所有服務**的各種環境配置檔案。
配置中心預設採用 `Git` 的方式儲存配置檔案,因此我們可以很容易的部署和修改,有助於環境配置進行版本管理。
## Spring Cloud Config 解決了什麼問題
Spring Cloud Config 解決了微服務配置的**中心化、版本控制、平臺獨立、語言獨立**等問題。其特性如下:
- 提供服務端和客戶端支援(Spring Cloud Config Server 和 Spring Cloud Config Client)
- 集中式管理分散式環境下的應用部署
- 屬性值的加密和解密(對稱加密和非對稱加密)
- 基於 Spring 環境,無縫與 Spring 應用整合
- 可用於任何語言開發的程式
- 預設實現基於 Git ,可以進行版本管理
接下來,我們主要從以下幾塊來講一下 Config 的使用。
1. 基礎版的配置中心(不整合 Eureka)
2. 整合 Eureka 版的高可用配置中心
3. 基於 Actuator 實現配置的自動重新整理
4. 配置中心屬性值的加密和解密(對稱加密和非對稱加密)
5. 基於 Spring Cloud Bus 實現配置的自動重新整理
6. 配置中心使用者安全認證
## 環境準備
### 專案
`config-demo` 聚合工程。`SpringBoot 2.2.4.RELEASE`、`Spring Cloud Hoxton.SR1`。
- `eureka-server`:註冊中心(用於整合 Eureka 版的配置中心)
- `eureka-server02`:註冊中心(用於整合 Eureka 版的配置中心)
- `order-service`:訂單服務(用於整合 Eureka 版的配置中心)
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/image-20200321000948032.png)
### 倉庫
`config-repo` 倉庫。
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/image-20200320183136998.png)
- `Repository name`:倉庫名稱
- `Description(可選)`:倉庫描述介紹
- `Public,Private`:倉庫許可權(公開共享,私有或指定合作者)
- `Initialize this repository with a README`:新增一個 README.md
- `Add .gitignore`:不需要進行版本管理的檔案型別,生成對應檔案 `.gitignore`
- `Add a license`:證書型別,生成對應檔案 `LICENSE`
### 配置檔案
不同環境的配置檔案,上傳至 `config-repo` 倉庫。
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/image-20200320233145761.png)
> 配置檔案的名稱不是亂起的,例如 `config-client-dev.yml` 和 `config-client-prod.yml` 這兩個檔案是同一個專案的不同環境,專案名稱為 `config-client`, 一個對應開發環境,一個對應正式環境。`test` 表示測試環境。
config-client.yml
```yml
server:
port: 7777 # 埠
spring:
application:
name: config-client # 應用名稱
# 自定義配置
name: config-client-default
```
config-client-dev.yml
```yml
server:
port: 7778 # 埠
spring:
application:
name: config-client # 應用名稱
# 自定義配置
name: config-client-dev
```
config-client-test.yml
```yml
server:
port: 7779 # 埠
spring:
application:
name: config-client # 應用名稱
# 自定義配置
name: config-client-test
```
config-client-prod.yml
```yml
server:
port: 7780 # 埠
spring:
application:
name: config-client # 應用名稱
# 自定義配置
name: config-client-prod
```
## 入門案例
入門案例講解:基礎版的配置中心(不整合 Eureka)
官方文件:https://cloud.spring.io/spring-cloud-static/spring-cloud-config/2.2.2.RELEASE/reference/html/
### 建立服務端
點選連結觀看:Config 入門案例建立服務端視訊(獲取更多請關注公眾號「哈嘍沃德先生」)
在 `config-demo` 父工程下建立子專案 `config-server`。
#### 新增依賴
新增 `spring-cloud-config-server` 依賴,完整 `pom.xml` 檔案如下:
```xml
4.0.0
com.example
config-server
1.0-SNAPSHOT
com.example
config-demo
1.0-SNAPSHOT
org.springframework.cloud
spring-cloud-config-server
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
```
#### 配置檔案
```yml
server:
port: 8888 # 埠
spring:
application:
name: config-server # 應用名稱
cloud:
config:
server:
git:
uri: https://github.com/imrhelloworld/config-repo # 配置檔案所在倉庫地址
#username: # Github 等產品的登入賬號
#password: # Github 等產品的登入密碼
#default-label: master # 配置檔案分支
#search-paths: # 配置檔案所在根目錄
```
#### 啟動類
啟動類新增 `@EnableConfigServer` 註解。
```java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
// 配置中心服務端註解
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
```
#### 訪問規則
Spring Cloud Config 有一套訪問規則,我們通過這套規則在瀏覽器上直接訪問即可。
```tex
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
```
- `{application}`:應用名稱(目標服務名稱)
- `{profile}`:獲取指定環境配置,專案有開發環境、測試環境、生產環境,對應到配置檔案就是以 application-{profile}.yml 加以區分,例如 application-dev.yml、application-test.yml、application-prod.yml。預設值為 default。
- `{label}`:表示 git 分支,預設是 master 分支,如果專案是以分支做區分也是可以的,那就可以通過不同的 label 來控制訪問不同的配置檔案。
**測試**
http://localhost:8888/config-client/default
http://localhost:8888/config-client/dev/master
http://localhost:8888/config-client-test.yml
http://localhost:8888/master/config-client-prod.yml
訪問以上地址,如果可以正常返回資料,說明配置中心服務端一切正常。
### 建立客戶端
點選連結觀看:Config 入門案例建立客戶端視訊(獲取更多請關注公眾號「哈嘍沃德先生」)
在 `config-demo` 父工程下建立子專案 `config-client`。
#### 新增依賴
新增 `spring-cloud-starter-config` 依賴,完整 `pom.xml` 檔案如下:
```xml
4.0.0
com.example
config-client
1.0-SNAPSHOT
com.example
config-demo
1.0-SNAPSHOT
org.springframework.cloud
spring-cloud-starter-config
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
```
#### 配置檔案
客戶端配置檔名稱必須叫 `bootstrap.yml`
```yml
spring:
cloud:
config:
name: config-client # 配置檔名稱,對應 git 倉庫中配置檔案前半部分
uri: http://localhost:8888 # config-server 服務端地址
label: master # git 分支
profile: default # 指定環境
```
#### 控制層
新增一個 RestController 用於測試獲取配置檔案資訊。
```java
package com.example.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigController {
@Value("${name}")
private String name;
@GetMapping("/name")
public String getName() {
return name;
}
}
```
#### 啟動類
```java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
}
```
#### 測試
訪問:http://localhost:7777/name 結果如下:
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/image-20200320235404919.png)
修改配置檔案為 `dev` 環境:
```yml
spring:
cloud:
config:
name: config-client # 應用名稱,對應 git 倉庫中配置檔案前半部分
uri: http://localhost:8888 # config-server 服務端地址
label: master # git 分支
profile: dev # 指定環境
```
訪問:http://localhost:7778/name 結果如下:
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/image-20200320235458201.png)
## Spring Cloud Config 高可用
以上講了 Spring Cloud Config 最基礎的用法,如果我們的專案中使用了 Eureka 作為服務註冊發現中心,那麼 Spring Cloud Config 也應該註冊到 Eureka,方便其他服務使用,並且可以註冊多個配置中心服務端,實現高可用。
接下來就整合 Spring Cloud Config 到 Eureka。關於 Eureka 的相關知識大家可翻閱我的歷史文章進行學習。
### 新增配置檔案
在 Github 倉庫中增加配置檔案。
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/image-20200321001915082.png)
order-service-dev.yml
```yml
server:
port: 9090 # 埠
spring:
application:
name: order-service # 應用名稱
# 配置 Eureka Server 註冊中心
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 設定服務註冊中心地址
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
# 自定義配置
name: order-service-dev
```
order-service-prod.yml
```yml
server:
port: 9091 # 埠
spring:
application:
name: order-service # 應用名稱
# 配置 Eureka Server 註冊中心
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 設定服務註冊中心地址
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
# 自定義配置
name: order-service-prod
```
### 整合註冊中心
案例已經給大家準備好了,無需建立註冊中心直接使用即可,為了清楚,把依賴和配置資訊給大家貼出來。
#### 依賴
`eureka-server` 和 `eureka-server02` 核心依賴部分一致。
```xml
4.0.0
com.example
eureka-server
1.0-SNAPSHOT
com.example
config-demo
1.0-SNAPSHOT
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
```
#### 配置檔案
`eureka-server` 的 application.yml
```yml
server:
port: 8761 # 埠
spring:
application:
name: eureka-server # 應用名稱(叢集下相同)
# 配置 Eureka Server 註冊中心
eureka:
instance:
hostname: eureka01 # 主機名,不配置的時候將根據作業系統的主機名來獲取
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
# 設定服務註冊中心地址,指向另一個註冊中心
service-url: # 註冊中心對外暴露的註冊地址
defaultZone: http://localhost:8762/eureka/
```
`eureka-server02` 的 application.yml
```yml
server:
port: 8762 # 埠
spring:
application:
name: eureka-server # 應用名稱(叢集下相同)
# 配置 Eureka Server 註冊中心
eureka:
instance:
hostname: eureka02 # 主機名,不配置的時候將根據作業系統的主機名來獲取
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
# 設定服務註冊中心地址,指向另一個註冊中心
service-url: # 註冊中心對外暴露的註冊地址
defaultZone: http://localhost:8761/eureka/
```
#### 啟動類
`eureka-server` 和 `eureka-server02` 啟動類核心程式碼一致。
```java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
// 開啟 EurekaServer 註解
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
```
### Spring Cloud Config 服務端
服務端和基礎版的配置中心相比多了 Eureka 的配置,其他地方都是一樣的。
`config-server` 服務端構建完成以後再復刻一個 `config-server02` 實現高可用。
#### 依賴
`config-server` 和 `config-server02` 核心依賴部分一致。注意是 `spring-cloud-config-server` 依賴。
```xml
4.0.0
com.example
config-server
1.0-SNAPSHOT
com.example
config-demo
1.0-SNAPSHOT
org.springframework.cloud
spring-cloud-config-server
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
```
#### 配置檔案
`config-server` 的 application.yml
```yml
server:
port: 8888 # 埠
spring:
application:
name: config-server # 應用名稱
cloud:
config:
server:
git:
uri: https://github.com/imrhelloworld/config-repo # 配置檔案所在倉庫地址
#username: # Github 等產品的登入賬號
#password: # Github 等產品的登入密碼
#default-label: master # 配置檔案分支
#search-paths: # 配置檔案所在根目錄
# 配置 Eureka Server 註冊中心
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 設定服務註冊中心地址
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
```
`config-server02` 的 application.yml
```yml
server:
port: 8889 # 埠
spring:
application:
name: config-server # 應用名稱
cloud:
config:
server:
git:
uri: https://github.com/imrhelloworld/config-repo # 配置檔案所在倉庫地址
#username: # Github 等產品的登入賬號
#password: # Github 等產品的登入密碼
#default-label: master # 配置檔案分支
#search-paths: # 配置檔案所在根目錄
# 配置 Eureka Server 註冊中心
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 設定服務註冊中心地址
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
```
#### 啟動類
`config-server` 和 `config-server02` 啟動類核心程式碼一致。
```java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
// 開啟 EurekaClient 註解,當前版本如果配置了 Eureka 註冊中心,預設會開啟該註解
//@EnableEurekaClient
// 配置中心服務端註解
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
```
### Spring Cloud Config 客戶端
客戶端加入 Eureka 以後,就不用直接和配置中心服務端打交道了,而是通過 Eureka 來訪問。
#### 依賴
`order-service` 的 pom.xml。注意是 `spring-cloud-starter-config` 依賴。
```xml
4.0.0
com.example
order-service
1.0-SNAPSHOT
com.example
config-demo
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-config
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
```
#### 配置檔案
`order-service` 的 `bootstrap.yml`
```yml
spring:
cloud:
config:
name: order-service # 配置檔名稱,對應 git 倉庫中配置檔案前半部分
label: master # git 分支
profile: dev # 指定環境
discovery:
enabled: true # 開啟
service-id: config-server # 指定配置中心服務端的 service-id
```
#### 控制層
新增一個 RestController 用於測試獲取配置檔案資訊。
```java
package com.example.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigController {
@Value("${name}")
private String name;
@GetMapping("/name")
public String getName() {
return name;
}
}
```
#### 啟動類
```java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 開啟 EurekaClient 註解,當前版本如果配置了 Eureka 註冊中心,預設會開啟該註解
//@EnableEurekaClient
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
```
#### 測試
啟動註冊中心 `eureka-server` 和 `eureka-server02`。
啟動配置中心服務端 `config-server`。
啟動配置中心客戶端 `order-service`。
當前環境在 `Eureka UI` 介面中如下:
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/image-20200321102359564.png)
訪問:http://localhost:9090/name 結果如下:
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/image-20200321101127523.png)
## 配置中心工作原理
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/u=469036600,3274459632&fm=26&gp=0.jpg)
開發人員將配置檔案儲存至 Git 遠端倉庫,或後期對 Git 遠端倉庫的檔案進行修改。如果遠端倉庫發生了版本改變,Config Server 會將 Git 遠端倉庫中的檔案同步至本地倉庫中。大家仔細觀察 Config Server 的控制檯可以看到類似如下資訊。
```shell
[nio-8888-exec-1] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/C:/Users/MRHELL~1/AppData/Local/Temp/config-repo-17506367621853740906/order-service-dev.yml
```
根據控制檯資訊開啟對應的本地目錄,會發現 Git 遠端倉庫中的檔案已同步至本地倉庫中。
![](https://mrhelloworld.com/resources/articles/spring/spring-cloud/config/image-20200321104201689.png)
為什麼要這麼做呢?因為我們要考慮網路波動的情況下,無法訪問遠端倉庫的問題。
> 下一篇我們講解 Config 如何實現配置中心自動重新整理,記得關注噢~
![](https://user-gold-cdn.xitu.io/2020/5/1/171cf87f564bc82e?w=433&h=133&f=gif&s=333013)
本文采用 `知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議`。
大家可以通過 `分類` 檢視更多關於 `Spring Cloud` 的文章。