本文是Spring Cloud專欄的第十篇文章,瞭解前九篇文章內容有助於更好的理解本文:html
Spring Cloud第四篇 | 客戶端負載均衡Ribbonbootstrap
Spring Cloud Config是Spring Cloud團隊建立的一個全新項目,用來爲分佈式系統中的基礎設施和微服務應用提供集中化的外部配置支持,它分爲服務端(config server)與客戶端(config client)兩個部分。其中服務端也稱爲分佈式配置中心,它是一個獨立的微服務應用,用來鏈接配置倉庫併爲客戶端提供獲取配置信息、加密/解密信息等訪問接口,而客戶端則是微服務架構中的各個微服務應用或基礎設施,它們經過指定的配置中心來管理應用資源與業務相關的配置內容, 並在啓動的時候從配置中心獲取和加載配置信息。Spring Cloud Config實現了對服務端和客戶端中環境變量和屬性配置的抽象映射,因此它除了適用於Spring構建的應用程序以外, 也能夠在任何其餘語言運行的應用程序中使用。因爲Spring Cloud Config實現的配置中心默認採用Git來存儲配置信息,因此使用Spring Cloud Config構建的配置服務器,自然就支持對微服務應用配置信息的版本管理,而且能夠經過Git客戶端工具來方便地管理和訪問配置內容。固然它也提供了對其餘存儲方式的支持,好比SVN倉庫、本地化文件系統。
一、添加依賴
<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構建完成。
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
開發環境中咱們的配置中心確定是不能隨隨便便被人訪問的,咱們能夠加上適當的保護機制,因爲微服務是構建在Spring Boot之上,因此整合Spring Security是最方便的方式。
一、添加依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
二、默認狀況下,咱們能夠得到一個名爲user的用戶,而且在配置中心啓動的時候,在日誌中打印出該用戶的隨機密碼
大多數狀況下,咱們並不會使用隨機生成密碼的機制,咱們能夠在配置中心服務端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
一、對稱加密
在微服務架構中,咱們一般會採用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窗口輸入:
另外,若是不想逐步輸入那些提示信息,可使用-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