Spring Cloud Config
Spring Cloud Config為分布式服務提供了服務側和客戶側的外部配置支持。通過Spring Cloud Config你可以有一個統一的地方來管理所有應用的外部配置。
默認服務端存儲實現用的是git,因此,它很容易支持配置環境的標簽版本,並且可以訪問各種管理內容的工具。
1. Quick Start
此小結將介紹Spring Cloud Config Server的客戶端和服務端。
首先,啟動服務端:
1 $ cd spring-cloud-config-server 2 $ ../mvnw spring-boot:run
接着試一下客戶端:
1 $ curl localhost:8888/foo/development 2 {"name":"foo","label":"master","propertySources":[ 3 {"name":"https://github.com/scratches/config-repo/foo-development.properties","source":{"bar":"spam"}}, 4 {"name":"https://github.com/scratches/config-repo/foo.properties","source":{"foo":"bar"}} 5 ]}
默認定位屬性資源的策略是使用git(spring.cloud.config.server.git.uri),並且用它來初始化一個迷你SpringApplication,這個迷你application的Environment是用來枚舉屬性資源並將它發布到一個JSON端點。
HTTP服務的格式如下:
1 /{application}/{profile}[/{label}] 2 /{application}-{profile}.yml 3 /{label}/{application}-{profile}.yml 4 /{application}-{profile}.properties 5 /{label}/{application}-{profile}.properties
其中application是是使用spring.config.name屬性注入的,profile是一個激活的配置文件(或者是以逗號分隔的屬性),label是一個可選的git標簽(默認是master)。
Spring Cloud Config Server從git倉庫為客戶端拉取配置,如下:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://github.com/spring-cloud-samples/config-repo
1.1 Client Side Usage(客戶端用法)
要在一個應用中使用這些特性,你可以構建一個Spring Boot application並且添加spring-cloud-config-client相關的依賴,最方便的方法是添加org.springframework.cloud:spring-cloud-starter-config依賴。
下面是一個典型的maven配置:
1 <parent> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-parent</artifactId> 4 <version>{spring-boot-docs-version}</version> 5 <relativePath /> <!-- lookup parent from repository --> 6 </parent> 7 8 <dependencyManagement> 9 <dependencies> 10 <dependency> 11 <groupId>org.springframework.cloud</groupId> 12 <artifactId>spring-cloud-dependencies</artifactId> 13 <version>{spring-cloud-version}</version> 14 <type>pom</type> 15 <scope>import</scope> 16 </dependency> 17 </dependencies> 18 </dependencyManagement> 19 20 <dependencies> 21 <dependency> 22 <groupId>org.springframework.cloud</groupId> 23 <artifactId>spring-cloud-starter-config</artifactId> 24 </dependency> 25 <dependency> 26 <groupId>org.springframework.boot</groupId> 27 <artifactId>spring-boot-starter-test</artifactId> 28 <scope>test</scope> 29 </dependency> 30 </dependencies> 31 32 <build> 33 <plugins> 34 <plugin> 35 <groupId>org.springframework.boot</groupId> 36 <artifactId>spring-boot-maven-plugin</artifactId> 37 </plugin> 38 </plugins> 39 </build>
現在可以創建一個標准的Spring Boot application,如下:
1 @SpringBootApplication 2 @RestController 3 public class Application { 4 5 @RequestMapping("/") 6 public String home() { 7 return "Hello World!"; 8 } 9 10 public static void main(String[] args) { 11 SpringApplication.run(Application.class, args); 12 } 13 14 }
當這個HHTP服務啟動時,它默認從本地的config server(端口8888)加載配置,可以使用bootstrap.properties配置來改變這個默認行為:
1 spring.cloud.config.uri: http://myconfigserver.com
可以使用/env端點來查看bootstrap properties配置:
1 $ curl localhost:8080/env 2 { 3 "profiles":[], 4 "configService:https://github.com/spring-cloud-samples/config-repo/bar.properties":{"foo":"bar"}, 5 "servletContextInitParams":{}, 6 "systemProperties":{...}, 7 ... 8 }
2. Spring Cloud Config Server(配置服務器的服務端)
Spring Cloud Config Server為外部配置提供一個基於資源的HTTP API。使用注解@EnableConfigServer可以在一個Spring Boot application中嵌入配置服務器。例如:
1 @SpringBootApplication 2 @EnableConfigServer 3 public class ConfigServer { 4 public static void main(String[] args) { 5 SpringApplication.run(ConfigServer.class, args); 6 } 7 }
最簡單的方法是通過屬性spring.config.name=configserver啟動,因為在config server的jar中有一個configserver.yml配置文件,它已經設置好了默認的配置倉庫。
或者你可以使用自己的配置:application.properties
1 server.port: 8888 2 spring.cloud.config.server.git.uri: file://${user.home}/config-repo
其中${user.home}/config-repo是一個包含YAML或者properties格式配置文件的git倉庫。
注意:
1)在windows上,你需要在file url前多添加一個“/”,如果是絕對路徑的話。(例如:file:///${user.home}/config-repo)
2)使用本地倉庫只是為了演示和測試使用,在正式環境中需要使用一台服務器來管理配置
3)初始化克隆配合倉庫在只有一個文件時可能比較快,但是如果存儲一個二進制文件,特別是比較大的文件時,可能在第一次請求配置時有延遲甚至可能導致服務端內存溢出。
2.1 Environment Repository
在config server中我們應該將配置存儲在什么地方?掌控這個行為的策略的就是為Environment對象服務的EnvironmentRepository。
Environment資源由一下三個變量參數化:
1){application} 對應客戶端的spring.application.name
2){profile} 對應客戶端的spring.profiles.active(以逗號分隔)
3){label} 它是服務器端功能標簽“版本化”的配置文件集
Repository的實現通常像一個spring boot application,從一個和{application}相等的spring.config.name參數和與{profiles}相等的spring.profiles.active參數指定的文件來加載配置。
優先級策略和普通spring boot 的應用一樣:Active profiles優先級比默認的高,如果有多個profiles,那么最后一個優先級最高。下面是客戶端bootstrap 配置bootstrap.yml:
1 spring: 2 application: 3 name: foo 4 profiles: 5 active: dev,mysql
(和一般Spring Boot application一樣,這些參數也可以在環境變量或者命令行參數中指定)
2.1.1 Git Backend
在config server中使用spring.cloud.config.server.git.uri來設置倉庫位置,如果uri是以file:開頭,則是本地倉庫。
但是如果要擴展config server並且高可用的話,必須使所有服務器實例指向同一個倉庫。因此需要一個共享的文件系統。在這種情況下,使用ssh協議是比較好的,這樣服務器可以克隆一份配置到本地作為緩存使用。
倉庫的實現是將HTTP路徑中的{label}映射到一個git標簽(commit id, branch name, or tag),如果一個git分支或者標簽中包含“/”斜杠,那么在HTTP url中需要用一個特殊字符(_)來替代,以免發生混淆。
比如標簽為foo/bar,則應該替換成:foo(_)bar。這個規則同樣可應用到{application}參數上。
Skipping SSL Certificate Validation(跳過ssl驗證)
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://example.com/my/repo 7 skipSslValidation: true
Setting HTTP Connection Timeout(設置HTTP連接超時時間,以秒為單位)
spring: cloud: config: server: git: uri: https://example.com/my/repo timeout: 4
Placeholders in Git URI(git URI中的占位符)
Spring Cloud Config Server支持git URI中的占位符為:{application},{profile},{label}(記住label是作為git 的標簽使用的)。通過下面的配置你可以支持每個應用一個倉庫的策略:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://github.com/myorg/{application}
Pattern Matching and Multiple Repositories(規則匹配和多倉庫)
Spring Cloud Config包含對application和profile名稱的規則匹配支持,規則格式是包含通配符的以逗號分隔的{application}/{profile}名稱。例如:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://github.com/spring-cloud-samples/config-repo 7 repos: 8 simple: https://github.com/simple/config-repo 9 special: 10 pattern: special*/dev*,*special*/dev* 11 uri: https://github.com/special/config-repo 12 local: 13 pattern: local* 14 uri: file:/home/configsvc/config-repo
如果{application}/{profile}不匹配任何一個規則,則使用spring.cloud.config.server.git.uri下面的默認URI。在上面的例子中,匹配“simple”倉庫的規則是simple/*({application}為simple,{profile}為任意值)。“local”倉庫匹配任何一個以local開頭的應用名稱,如果沒有指定{profile}規則,則會自動在規則后面添加“/*”。
由於pattern參數實際上是一個數組,所以使用YAML數組(或者在.properties文件中使用[0], [1]等后綴)來綁定多種規則。如下:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://github.com/spring-cloud-samples/config-repo 7 repos: 8 development: 9 pattern: 10 - '*/development' 11 - '*/staging' 12 uri: https://github.com/development/config-repo 13 staging: 14 pattern: 15 - '*/qa' 16 - '*/production' 17 uri: https://github.com/staging/config-repo
每個倉庫都可以在子目錄中存儲配置文件,如果要在子目錄中搜索則需要使用searchPaths配置。例如:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://github.com/spring-cloud-samples/config-repo 7 searchPaths: foo,bar*
在上面的例子中,服務器將會在頂級目錄和foo子目錄還有以bar開頭的子目錄中搜索配置文件。
默認情況下,服務器會在第一次收到配置請求時,克隆遠程倉庫。也可以在服務啟動時克隆遠程倉庫,如下:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://git/common/config-repo.git 7 repos: 8 team-a: 9 pattern: team-a-* 10 cloneOnStart: true 11 uri: http://git/team-a/config-repo.git 12 team-b: 13 pattern: team-b-* 14 cloneOnStart: false 15 uri: http://git/team-b/config-repo.git 16 team-c: 17 pattern: team-c-* 18 uri: http://git/team-a/config-repo.git
在上面的例子中只有team-a的遠程倉庫會在啟動時克隆,其他的都是在第一次接受到配置請求時才克隆。
Authentication(用戶驗證)
添加username和password屬性來使用遠程倉庫基於HTTP的驗證。例如:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://github.com/spring-cloud-samples/config-repo 7 username: trolley 8 password: strongpassword
如果不使用HTTPS和用戶憑證,也可以使用SHH,在默認目錄下存儲key(~/.ssh),並且URI指向一個SSH地址(例如:git@github.com:configuration/cloud-configuration)。
Git SSH configuration using properties(使用屬性配置GIT SSH)
SSH配置可以使用java屬性來解決,spring.cloud.config.server.git.ignoreLocalSshSettings值必須設置為true。例如:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: git@gitserver.com:team/repo1.git 7 ignoreLocalSshSettings: true 8 hostKey: someHostKey 9 hostKeyAlgorithm: ssh-rsa 10 privateKey: | 11 -----BEGIN RSA PRIVATE KEY----- 12 MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX 13 IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF 14 ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud 15 1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i 16 oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W 17 DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd 18 fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b 19 BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG 20 EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj 21 5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8 22 +AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe 23 pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG 24 ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ 25 xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW 26 dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi 27 PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX 28 VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z 29 FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R 30 gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4 31 VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV 32 cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee 33 KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N 34 CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs 35 q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J 36 69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT 37 -----END RSA PRIVATE KEY-----
其中hostKeyAlgorithm必須是ssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, or ecdsa-sha2-nistp521中的一個。
Force pull in Git Repositories
如果本地copy已經失效(即遠程倉庫有改動),則Spring Cloud Config Server會強制從從遠程庫拉取最新的配置。如下:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://github.com/spring-cloud-samples/config-repo 7 force-pull: true
如果有多個遠程倉庫的話,可以使用類似下面的配置:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://git/common/config-repo.git 7 force-pull: true 8 repos: 9 team-a: 10 pattern: team-a-* 11 uri: http://git/team-a/config-repo.git 12 force-pull: true 13 team-b: 14 pattern: team-b-* 15 uri: http://git/team-b/config-repo.git 16 force-pull: true 17 team-c: 18 pattern: team-c-* 19 uri: http://git/team-a/config-repo.git
force-pull屬性默認是false。
Deleting untracked branches in Git Repositories(刪除git倉庫中未跟蹤的分支)
因為Spring Cloud Config Server會克隆遠程倉庫到本地並且會一直保持這個分支知道下次重啟,所以有一種情況是遠程分支已經被刪除,但是本地副本還仍然可用。
為了保證本地倉庫分支和遠程同步,需要設置deleteUntrackedBranches屬性,它會使Spring Cloud Config Server強制刪除本地未跟蹤的分支。例如:
1 spring: 2 cloud: 3 config: 4 server: 5 git: 6 uri: https://github.com/spring-cloud-samples/config-repo 7 deleteUntrackedBranches: true
deleteUntrackedBranches默認值為false。
3. Spring Cloud Config Client(配置客戶端)
3.1 Config First Bootstrap(啟動時先讀取config server配合)
在classpath中存在Spring Cloud Config Client的任何應用的默認行為如下:當一個config客戶端啟動時,它綁定到Config Server(通過bootstrap的配置屬性spring.cloud.config.uri)然后使用遠程配置文件初始化spring環境。
這種行為的最終結果是所有想要到 Config Server消費的客戶端應用都需要一個配置有spring.cloud.config.uri(默認為:"http://localhost:8888")的bootstrap.yml或者環境變量。
3.2 Discovery First Bootstrap(使用服務發現尋找config server)
如果你正在使用服務發現框架例如Spring Cloud Netflix 和 Eureka Service Discovery 或者 Spring Cloud Consul,你可以把Config Server 注冊到服務注冊中心。
但是在默認的“Config First”模式下,客戶端是感知不到注冊中心中的config server服務的。如果你選擇使用服務發現來定位Config Server,那么你需要在Config server中設置spring.cloud.config.discovery.enabled=true,
默認是false。這么做的話就需要每個客戶端應用都要有一個bootstrap.yml或者環境變量來配置服務注冊中心的內容。例如在Spring Cloud Netflix中,你需要配置Eureka server地址(eureka.client.serviceUrl.defaultZone),
這么做的代價是在啟動時需要一個額外的網絡往返來定位服務注冊中心。好處是,只要注冊中心是固定的,那么config server就可以隨意改變坐標。默認的服務ID是configserver,但是可以通過spring.cloud.config.discovery.serviceId
來重新設置(但是通常是通過spring.application.name來設置一個服務ID)。
一般服務發現實現客戶端都是支持某些元數據映射的(例如在Eureka中的eureka.instance.metadataMap)。為了讓配置客戶端能正確連接到config server需要在Config Server中配一些服務注冊相關的元數據。
如果Config Server安全策略是基於HTTP的,你可以設置一些用戶憑證像username,password。另外,如果Config Server有上下文路徑,可以使用configPath設置。如下(bootstrap.yml):
1 eureka: 2 instance: 3 ... 4 metadataMap: 5 user: osufhalskjrtl 6 password: lviuhlszvaorhvlo5847 7 configPath: /config
3.3 Config Client Fail Fast(快速失敗響應)
在某些情況下,你可能希望服務在啟動時如果連接config server失敗時立刻響應失敗而停止啟動,可以設置spring.cloud.config.fail-fast=true。
3.4 Config Client Retry(配置客戶端重試機制)
如果你覺得config server在你啟動應用是不可達是暫時的或者偶然的,你需要在一次失敗后接着重新嘗試連接。第一步,設置spring.cloud.config.fail-fast=false。
接着將spring-retry和spring-boot-starter-aop加入到classpath中。默認行為是重試6次,初始間隔為1000ms,后續間隔乘以1.1。
可以通過設置spring.cloud.config.retry.*來改變默認行為。
注意:如果要完全控制重試機制,可以通過創建一個RetryOperationsInterceptor類型id為configServerRetryInterceptor的bean。
可以使用Spring Retry中的RetryInterceptorBuilder來創建。
3.5 Locating Remote Configuration Resources(定位遠程配置資源)
配置服務提供/{name}/{profile}/{label}的屬性源,其在客戶端應用的映射為:
- "name" =
${spring.application.name}
- "profile" =
${spring.profiles.active}(其實是Environment.getActiveProfiles())
- "label" = "master"
可以使用spring.cloud.config.*來覆蓋上面的默認值。
其中可以使用label屬性回滾到以前的版本。在config server的實現中,label可以是git 標簽,分支名或者commit ID。也可以是以逗號分隔的列表。在這種列表情況下,其中的元素會一個一個的被嘗試,直到有一個成功。
3.6 Specifying Multiple Urls for the Config Server(指定多個config server url)
為了保證高可用,你可能部署多個config server,在客戶端可以使用spring.cloud.config.uri,以逗號分隔指定多個URL,或者將config server的多個實例注冊到服務注冊中心,此時客戶端需要使用之前提到的Discovery-First Bootstrap
模式(spring.cloud.config.discovery.enabled=true)。
如果Config Server使用的是HTTPS協議,則可以將用戶憑證信息填寫在每個config server 的 url上。如果使用其他的安全機制,則不支持為每個config server配置驗證信息。
3.7 Configuring Read Timeouts(讀取超時)
使用spring.cloud.config.request-read-timeout配置超時時間。
3.8 Security(安全機制)
如果config server使用的是HTTPS,則需要在url上指定用戶名和密碼,或者使用單獨的username和password屬性設置。如下(bootstrap.yml)
1 spring: 2 cloud: 3 config: 4 uri: https://user:secret@myconfig.mycompany.com
1 spring: 2 cloud: 3 config: 4 uri: https://myconfig.mycompany.com 5 username: user 6 password: secret
spring.cloud.config.password
和 spring.cloud.config.username會覆蓋url中的用戶名和密碼。
好了,spring cloud config就先講到這。下一篇就是spring cloud netflix。如果文章中寫的有問題的希望各位讀者批評指出。如果覺得在我這學到了點東西的,特別希望您能動動可愛的小手給點個贊!^_^