Spring Cloud Config 是用來集中管理應用設定的利器,但預設用 Git backend,在開發時有時候有點麻煩。我就來介紹怎麼用本地檔案模式搞定開發環境的設定管理。
為什麼要用本地檔案模式?
預設的 Config Server 是用 Git repository 當後端,這對生產環境來說很棒,但開發時有點費事:
- 要維護一個 Git repo
- 改設定要 push、pull
- 不方便快速迭代
用本地檔案模式就簡單多了,直接在電腦上改檔案,重新整理一下就行。
Config Server 的設定
首先建立一個 Spring Boot application 當 Config Server。
1. 加依賴
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
|
2. 啟動類別標注 @EnableConfigServer
1 2 3 4 5 6 7
| @SpringBootApplication @EnableConfigServer public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }
|
3. application.yml 設定
這是重點。用 native profile 來啟用本地檔案模式:
1 2 3 4 5 6 7 8
| spring: profiles: active: native cloud: config: server: native: searchLocations: file:///Users/cheng/config/
|
或者用環境變數:
1 2 3 4 5 6 7 8
| spring: profiles: active: native cloud: config: server: native: searchLocations: file://${user.home}/config/
|
幾個重點
file:/// 是本地檔案路徑(三個 slash)
- 路徑最後要加
/
- 可以指定多個路徑,用逗號分隔:
file:///path1/,file:///path2/
如果你想要更簡潔的設定,也可以這樣:
1 2 3 4 5 6 7 8 9 10
| spring: profiles: active: native config: import: configserver: cloud: config: server: native: searchLocations: classpath:/config/
|
用 classpath:/ 的話設定檔會放在 JAR 裡面(通常是 src/main/resources/config/)。
設定檔的命名和組織
Config Server 預期的設定檔名稱有特定格式。假設 client 端的 application name 是 user-service,profiles 是 dev,那麼 Config Server 會依序查找:
user-service-dev.yml 或 user-service-dev.properties
user-service.yml 或 user-service.properties
所以假設你的設定檔目錄結構是這樣:
1 2 3 4 5 6 7
| config/ ├── user-service-dev.yml ├── user-service-prod.yml ├── user-service.yml ├── order-service-dev.yml ├── order-service-prod.yml └── order-service.yml
|
然後你有個檔案在 /Users/cheng/config/user-service-dev.yml:
1 2 3 4 5 6 7 8
| server: port: 8001
app: database: url: jdbc:mysql://localhost:3306/user_db_dev username: root password: password
|
Config Server 的 Endpoint
Config Server 提供了一些 REST endpoint 來取得設定。格式是:
1
| /{application}/{profile}[/{label}]
|
比如:
1 2 3 4 5 6 7 8 9
| # 取得 user-service 在 dev profile 的設定 GET http://localhost:8888/user-service/dev
# 取得 user-service 預設 profile 的設定 GET http://localhost:8888/user-service/default
# 如果用 Git backend,{label} 就是 branch 名稱 # 本地模式通常不用 {label} GET http://localhost:8888/user-service/dev/master
|
實際運作
假設 Config Server 跑在 http://localhost:8888,我們用 curl 試試:
1
| curl http://localhost:8888/user-service/dev
|
會回傳類似這樣的 JSON:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { "name": "user-service", "profiles": ["dev"], "label": null, "version": null, "state": null, "propertySources": [ { "name": "file:///Users/cheng/config/user-service-dev.yml", "source": { "server.port": 8001, "app.database.url": "jdbc:mysql://localhost:3306/user_db_dev", "app.database.username": "root", "app.database.password": "password" } } ] }
|
Client 端的設定
現在來設定 Config Client。假設你的應用叫 user-service,想要讀 dev 的設定。
在 bootstrap.yml 裡面設定(不是 application.yml!重要):
1 2 3 4 5 6 7 8
| spring: application: name: user-service profiles: active: dev cloud: config: uri: http://localhost:8888
|
然後在 application.yml 就可以這樣用:
1 2 3 4 5 6
| server: port: 8080
app: version: 1.0.0
|
用 @Value 取得設定
在程式裡面用 @Value 取得設定值:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Service public class UserService { @Value("${app.database.url}") private String databaseUrl; @Value("${app.database.username}") private String username; public void connect() { System.out.println("Connecting to: " + databaseUrl); } }
|
或者用 @ConfigurationProperties 綁定整個設定物件(這個我在另外一篇文章講過了)。
本地模式的限制
要注意本地模式有些限制:
- 沒有版本控制 - native 模式不支援 Git 的 label(branch)概念
- 不適合生產 - 生產環境還是要用 Git backend,確保可追蹤和回滾
- 熱重載有限制 - Config Server 本身改了設定檔,client 端要呼叫 refresh endpoint 才能更新
從 Git 轉到本地模式
開發時用本地模式,生產時切回 Git,可以這樣設定:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| spring: profiles: active: ${CONFIG_PROFILE:native} cloud: config: server: native: searchLocations: file://${CONFIG_PATH:~/config}/ git: uri: https://github.com/myorg/config-repo searchPaths: "config/{application}"
|
然後用環境變數決定用哪個:
1 2 3 4 5 6
| export CONFIG_PROFILE=native export CONFIG_PATH=/Users/cheng/config/
export CONFIG_PROFILE=git
|
完整例子
一個完整的開發設定流程:
- 建立設定檔目錄
/Users/cheng/config/
- 建立
user-service-dev.yml
- Config Server 的
application.yml:
1 2 3 4 5 6 7 8 9 10 11
| server: port: 8888
spring: profiles: active: native cloud: config: server: native: searchLocations: file:///Users/cheng/config/
|
- Client 的
bootstrap.yml:
1 2 3 4 5 6 7 8
| spring: application: name: user-service profiles: active: dev cloud: config: uri: http://localhost:8888
|
- 啟動 Config Server,然後啟動 client 應用
- Client 應用會自動從 Config Server 拉設定
重點整理
- 開發用 native profile + 本地檔案很方便
- 設定檔命名:
{application}-{profile}.yml
- 設定要在
bootstrap.yml,不是 application.yml
- Config Server endpoint 是
/{application}/{profile}
- 生產環境還是建議用 Git backend
- native 模式沒有版本控制,只適合開發
下次要快速調整開發設定,就用本地檔案模式,爽度直接升天。
你的鼓勵將被轉換為我明天繼續加班的動力(真的)。 ❤️