1. 程式人生 > >Spring Cloud 系列之 Config 配置中心(一)

Spring Cloud 系列之 Config 配置中心(一)

## 服務配置現狀      配置檔案是我們再熟悉不過的,在微服務系統中,每個微服務不僅僅只有程式碼,還需要**連線其他資源**,例如資料庫的配置或功能性的開關 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` 的文章。