Spring Cloud第十篇 | 分佈式配置中心Config

本文是Spring Cloud專欄的第十篇文章,瞭解前九篇文章內容有助於更好的理解本文:html

  1. Spring Cloud第一篇 | Spring Cloud前言及其經常使用組件介紹概覽git

  2. Spring Cloud第二篇 | 使用並認識Eureka註冊中心spring

  3. Spring Cloud第三篇 | 搭建高可用Eureka註冊中心數據庫

  4. Spring Cloud第四篇 | 客戶端負載均衡Ribbonbootstrap

  5. Spring Cloud第五篇 | 服務熔斷Hystrix瀏覽器

  6. Spring Cloud第六篇 | Hystrix儀表盤監控Hystrix Dashboard安全

  7. Spring Cloud第七篇 | 聲明式服務調用Feign服務器

  8. Spring Cloud第八篇 | Hystrix集羣監控Turbin網絡

  9. Spring Cloud第九篇 | 分佈式服務跟蹤Sleuth架構

1、介紹

    Spring Cloud Config是Spring Cloud團隊建立的一個全新項目,用來爲分佈式系統中的基礎設施和微服務應用提供集中化的外部配置支持,它分爲服務端(config server)與客戶端(config client)兩個部分。其中服務端也稱爲分佈式配置中心,它是一個獨立的微服務應用,用來鏈接配置倉庫併爲客戶端提供獲取配置信息、加密/解密信息等訪問接口,而客戶端則是微服務架構中的各個微服務應用或基礎設施,它們經過指定的配置中心來管理應用資源與業務相關的配置內容, 並在啓動的時候從配置中心獲取和加載配置信息。Spring Cloud Config實現了對服務端和客戶端中環境變量和屬性配置的抽象映射,因此它除了適用於Spring構建的應用程序以外, 也能夠在任何其餘語言運行的應用程序中使用。因爲Spring Cloud Config實現的配置中心默認採用Git來存儲配置信息,因此使用Spring Cloud Config構建的配置服務器,自然就支持對微服務應用配置信息的版本管理,而且能夠經過Git客戶端工具來方便地管理和訪問配置內容。固然它也提供了對其餘存儲方式的支持,好比SVN倉庫、本地化文件系統。 

2、構建Config Server

一、添加依賴

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

二、在啓動類上添加註解@EnableConfigServer

三、在application.yml文件中添加配置

spring:
  application:
    name: springcloud-config-server
  cloud:
    config:
      server:
        git:
          #配置git倉庫地址
          uri: https://gitee.com/coding-farmer/config-center
          #配置倉庫路徑
          search-paths: "{profile}"
          #訪問git倉庫的用戶名
          username:
          #訪問git倉庫的密碼
          password:
          #配置中心經過git從遠程git庫,有時本地的拷貝被污染,
          #這時配置中心沒法從遠程庫更新本地配置,設置force-pull=true,則強制從遠程庫中更新本地庫
          force-pull: true
          #默認從git倉庫克隆下載的在C:/Users/<當前用戶>/AppData/Local/Temp
          #basedir:

server:
  port: 8888

    若是Git倉庫爲公開倉庫,能夠不填寫用戶名和密碼,若是是私有倉庫須要填寫,本案例使用的是碼雲公開倉庫。

四、配置中心倉庫目錄結構爲:按環境拆分

    遠程碼雲倉庫https://gitee.com/coding-farmer/config-center中有3個文件夾,分別是dev,prod,test,裏面存放着相應環境的配置文件

五、測試返回數據

http請求地址和資源文件映射以下:

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

    此時啓動咱們的配置中心,經過/{application}/{profile}/[{label}]就能訪問到咱們的配置文件了,其中application表示配置文件的名字,對應咱們上面的配置文件就是config;profile表示環境,咱們有dev、test、prod還有默認,label表示分支,默認咱們都是放在master分支上

訪問:http://localhost:8888/configclient/dev,默認分支爲master分支

以下圖則證實配置服務中心能夠從遠程程序獲取配置信息:

    從瀏覽器上能夠看到咱們放在倉庫中的配置文件信息。JSON中的name表示配置文件名application的部分,profiles表示環境部分,label表示分支,多了一個version,實際上就是咱們碼雲上提交信息時產生的版本號,當咱們訪問成功後,咱們還能夠看到控制檯打印了以下日誌:

INFO 6600 --- [nio-8888-exec-1] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5c4fca8a: startup date [Thu Aug 15 15:12:07 CST 2019]; root of context hierarchy
INFO 6600 --- [nio-8888-exec-1] o.s.c.c.s.e.NativeEnvironmentRepository  : Adding property source: file:/C:/Users/Administrator/AppData/Local/Temp/config-repo-6372945341655107732/dev/configclient-dev.yml
INFO 6600 --- [nio-8888-exec-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5c4fca8a: startup date [Thu Aug 15 15:12:07 CST 2019]; root of context hierarchy

    其實是配置中心經過git clone命令將配置文件在本地保存了一份,這樣能夠確保在git倉庫掛掉的時候咱們的應用還能夠繼續運行,當微服務A/B嘗試去從Config Server中加載配置信息的時候,Config Server會先經過git clone命令克隆一份配置文件保存到本地,此時咱們斷掉網絡,再訪問http://localhost:8888/configclient/dev同樣還能夠拿到數據,此時的數據就是從本地獲取的。

    若是有兩個前綴名相同文件,例如一個configclient.yml,一個configclient-dev.yml。那麼在訪問相同前綴的文件時,config-server會對這兩個文件進行一個合併。例如configclient.yml有一段配置是configclient-dev.yml沒有的,理應訪問configclient-dev.yml的時候是沒有那段配置的,但最終的訪問的結果倒是它倆合併以後的內容,即configclient-dev.yml會擁有configclient.yml裏所配置的內容。

    到此config server構建完成。

3、構建Config Client

    Config Client也就是你的微服務應用例如(springcloud-service-consumer、springcloud-service-feign、springcloud-service-provider等等,這些模塊相對於Config Server來講都是Config Client),可是爲了保持其餘案例模塊的純潔乾淨,這裏就單獨構建一個Config Client命名爲:springcloud-config-client

一、引入依賴

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

二、新建bootstrap.yml

    不瞭解bootstrap.yml能夠參考,SpringCloud入門之經常使用的配置文件application.yml和 bootstrap.yml區別:https://www.cnblogs.com/BlogNetSpace/p/8469033.html

spring:
  application:
    name: springcloud-config-client
  cloud:
    config:
      #uri則表示配置中心的地址
      uri: http://localhost:8888
      #注:config 客戶端在沒有 spring.cloud.config.name屬性的時候,服務端{application} 獲取的是客戶端
      #spring.application.name的值,不然,獲取的是 spring.cloud.config.name的值。
      #1)、當沒有spring.cloud.config.name時,客戶端獲取的是spring.application.name 所對應的git庫中的文件,而且只能獲取一個文件
      #2)、當一個項目中有需求要獲取多個文件時,就須要用到spring.cloud.config.name這個屬性,以逗號分割
      name: configclient
      profile: dev
      #label對應了label部分
      label: master
server:
  port: 8881

三、編寫Controller

@RestController
public class MyController {

    //配置中內心面配置的env屬性
    @Value("${env}")
    private String env;

    @RequestMapping("/index")
    public String env(){
        return env;
    }
}

四、訪問http://localhost:8881/index

4、安全保護

    開發環境中咱們的配置中心確定是不能隨隨便便被人訪問的,咱們能夠加上適當的保護機制,因爲微服務是構建在Spring Boot之上,因此整合Spring Security是最方便的方式。

一、添加依賴

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

二、默認狀況下,咱們能夠得到一個名爲user的用戶,而且在配置中心啓動的時候,在日誌中打印出該用戶的隨機密碼

Using generated security password: 9ca37d4c-c786-44be-8919-1825a0baaadb

    大多數狀況下,咱們並不會使用隨機生成密碼的機制,咱們能夠在配置中心服務端application.yml文件中指定用戶名密碼

spring:
  security:
    user:
      name: coding-farmer
      password: 123456

    當再次訪問http://localhost:8888/configclient/dev配置中心服務端的時候須要輸入密碼,顯示以下圖

三、因爲咱們已經爲config server設置了安全保護,若是咱們這個時候鏈接到配置中心的客戶端中沒有設置響應對應的安全信息,在獲取配置信息時會返回401錯誤,因此須要經過配置的方式在客戶端中加入安全信息來經過校驗,好比:

spring:
  cloud:
    config:
      username: coding-farmer
      password: 123456

5、加密解密

一、對稱加密

    在微服務架構中,咱們一般會採用DevOps的組織方式來下降因團隊間溝通形成的巨大成本,以加速微服務應用的交付能力。這就使得本來由運維團隊控制的線上信息將交由微服務所屬組織的成員自行維護,其中將會包括大量的敏感信息,好比數據庫的帳戶與密碼等。顯然,若是咱們直接將敏感信息以明文的方式存儲於微服務應用的配置文件中是很是危險的。針對這個問題, Spring Cloud Config提供了對屬性進行加密解密的功能,以保護配置文件中的信息安全。好比下面的例子

spring.datasource.username=root
spring.datasource.password={cipher}22fedb745505ffcd1dec962bee3c1f0f3af8a3e6b6930eee9afb8659b16a0c630fd256a181319704b806df90f38e7371

    在Spring Cloud Config中經過在屬性值前使用{cipher)前綴來標註該內容是一個加密值,當微服務客戶端加載配置時,配置中心會自動爲帶有{cipher}前綴的值進行解密。經過該機制的實現,運維團隊就能夠放心地將線上信息的加密資源給到微服務團隊,而不用擔憂這些敏感信息遭到泄漏的風險。

1-一、使用前提

    在使用 Spring Cloud Config的加密解密功能時,有一個必要的前提須要咱們注意。爲了啓用該功能,咱們須要在配置中心的運行環境中安裝不限長度的JCE版本(Unlimited Strength Java Cryptography Extension)。雖然,JCE功能在JRE中自帶,可是默認使用的是有長度限制的版本。咱們能夠從 Oracle的官方網站下載到它,它是一個壓縮包,解壓後能夠看到下面三個文件:

    咱們須要將local_policy.jar和US_export_policy.jar兩個文件複製到%JAVA_HOME%\jre\lib\security目錄下,覆蓋原來的默認內容。注意:我這裏使用的是JDK8,應該下載對應版本的JCE

1-二、相關端點

    在完成了JCE的安裝後,能夠嘗試啓動配置中心。在控制檯中,將會輸出一些配置中心特有的端點,主要包括以下幾個

  • /encrypt/status:查看加密功能狀態的端點。

  • /key:查看密鑰的端點。

  • /encrypt:對請求的body內容進行加密的端點。

  • /decrypt:對請求的body內容進行解密的端點。

能夠嘗試經過GET請求訪問/encrypt/status端點,咱們將獲得以下內容

    該返回信息說明當前配置中心的加密功能還不能使用,由於沒有爲加密服務配置對應的密鑰。

1-三、配置祕鑰

    咱們能夠經過encrypt.key屬性在bootstrap.yml(爲何要寫bootstrap.yml文件裏查看,關於spring cloud config加密EncryptionTooWeakException異常說明:https://www.iteye.com/blog/357029540-2433259)配置文件中直接指定密鑰信息(對稱性密鑰),好比:

encrypt:
  key: coding-farmer

加入上述配置信息後,重啓配置中心,再訪問/encrypt/status端點,咱們將獲得 以下內容:

    此時,咱們配置中心的加密解密功能就已經可使用了,不妨嘗試訪問一下/encrypt 和/decrypt端點來使用加密和解密的功能。注意,這兩個端點都是POST請求,加密和解密信息須要經過請求體來發送。

1-四、使用postman進行加密:http://localhost:8888/encrypt

 

1-五、使用postman解密:http://localhost:8888/decrypt

 

1-六、把加密的內容複製到你的配置文件中,提交到倉庫便可

    以下圖,加密內容前面要有{cipher}開頭表示該值是一個加密字符,配置中心config-server在獲取到這個值以後會先對值進行解密,解密以後纔會返回給客戶端使用,若是是yml文件key=value,value值要加單引號

1-七、訪問:http://localhost:8888/configclient/dev,顯示以下則加密成功

二、非對稱加密

    Spring Cloud Config的配置中心不只可使用對稱性加密,也可使用非對稱性加密 (好比RSA密鑰對)。雖然非對稱性加密的密鑰生成與配置相對複雜一些,可是它具備更高的安全性。下面,咱們來具體介紹一下如何使用非對稱加密

    首先,須要經過keytool工具來生成密鑰對。keytool是JDK中的一個密鑰和證書管理工具。它使用戶可以管理本身的公鑰/私鑰對及相關證書,用於(經過數字簽名)自我認證(用戶向其餘用戶/服務認證本身)或數據完整性以及認證服務。在JDK1.4之後的版本中都包含了這一工具,它的位置在%JAVA_HOME%\bin\keytool.exe。

    生成密鑰的具體命令以下所示,在DOS窗口輸入:

keytool -genkeypair -alias config-server -keyalg RSA -keystore config-server.keystore
C:\Program Files\Java\jdk1.8.0_101\bin>keytool -genkeypair -alias config-server -keyalg RSA -keystore config-server.keystore
輸入密鑰庫口令: 123456
再次輸入新口令: 123456
您的名字與姓氏是什麼?
  [Unknown]:  coding-farmer
您的組織單位名稱是什麼?
  [Unknown]:  company
您的組織名稱是什麼?
  [Unknown]:  organization
您所在的城市或區域名稱是什麼?
  [Unknown]:  city
您所在的省/市/自治區名稱是什麼?
  [Unknown]:  province
該單位的雙字母國家/地區代碼是什麼?
  [Unknown]:  china
CN=coding-farmer, OU=company, O=organization, L=city, ST=province, C=china是否正確?
  [否]:  y

輸入 <config-server> 的密鑰口令
        (若是和密鑰庫口令相同, 按回車): 456789
再次輸入新口令: 456789

    另外,若是不想逐步輸入那些提示信息,可使用-dname來直接指定,而祕鑰庫口令可以使用-storepass和-keypass來直接指定。因此,咱們能夠經過下面命令直接建立與上述命令同樣的祕鑰庫。

keytool -genkeypair -alias config-server -keyalg RSA \
 -dname "CN=coding-farmer, OU=company, O=organization, L=city, ST=province,C=china" \
 -storepass 123456 \
 -keystore config-server.keystore \
 -keypass 456789 \

    默認狀況下,使用上述命令創鍵的祕鑰只有90天有效期,若是想要調整它的有效期,能夠經過增長-validity參數來實現,好比咱們能夠經過下面的命令,讓祕鑰的有效期延長到一年:

 keytool -genkeypair -alias config-server -keyalg RSA \
 -dname "CN=coding-farmer, OU=company, O=organization, L=city, ST=province, C=china" \
 -storepass 123456 \
 -keystore config-server.keystore \
 -keypass 456789 \
 -validity 365 \

    上述的三種命令生成方式,最終都會在命令的當前執行目錄下生成一個config-server. keystore文件。下面,咱們須要將它保存在配置中心的文件系統中的某個位置, 好比將該文件拷貝到config-server的src\main\resources目錄下,而後在配置中心中加入相關的配置信息

encrypt:
  key-store:
    location: config-server.keystore
    alias: config-server
    password: 123456
    secret: 456789

非對稱加密的配置信息也能夠經過環境變量的方式進行配置,它們對應的具體變量名以下:

ENCRYPT_KEY_STORE_LOCATION
ENCRYPT_KEY_STORE_ALIAS
ENCRYPT_KEY_STORE_PASSWORD
ENCRYPT_KEY_STORE_SECRET

測試方式和對稱加密的測試方式一致

 

詳細參考案例源碼:https://gitee.com/coding-farmer/spirngcloud-learn

 

相關文章
相關標籤/搜索