在 Golang 項目中使用 Spring Cloud Config Server 管理配置

來源:互聯網
上載者:User

引言

最近用 Go 寫後端寫得很開心, 寫篇比較實用的部落格總結下如何通過 Spring Cloud Config Server 管理 Go 程式中的配置. 實現並不複雜, 因此也可以很輕易地推廣到其他語言的程式中.

先來說說為什麼要做集中組態管理. 在單體應用時代組態管理並不是什麼大問題, 一般設定檔就和源碼一起放在代碼倉庫中, 要查看或者修改直接到 conf 目錄裡找就完事兒了. 但到了微服務時代, 服務的數量比過去多了幾十倍, 再到茫茫多的代碼倉庫裡找配置可就沒這麼簡單了. 因此我們需要一個能夠統一查看修改配置, 能夠對配置進資料列版本設定的地方, 這就是配置中心了.

在 Google 上搜尋 "配置中心" 能找到不少不錯的開源軟體, 但大部分都比較重, 並且需要引入特定的用戶端. 這對沒到那麼大規模的中小團隊來說未免太過折騰. 因此反而像 Spring Cloud Config Server 這樣的輕量級配置中心比較適合, 幾分鐘就能跑起來, 而且和配置本身相關的功能也足夠豐富了.

因此我們的架構就像下面這樣:

  • Git: 儲存具體的設定檔, 並且負責配置版本管理
  • Spring Cloud Config Server: 提供配置的查詢介面
  • Go App: 從配置中心載入配置並使用

OK, 下面正式開幹吧.

簡單的搜尋服務

作為示範我們用 Go 寫一個很簡單的搜尋服務. 只要訪問 GET /search?q=<keyword> 服務就會把搜尋引擎查到的結果展示出來. 用 Go 實現只要一個檔案哦 ~

main.go

package mainimport ...func main() {  http.HandleFunc("/search", func(w http.ResponseWriter, req *http.Request) {    q := req.URL.Query().Get("q")        fmt.Fprintf(w, `<iframe width="100%%" height="98%%" scrolling="auto" frameborder="0" src="https://cn.bing.com/search?q=%v">`, q)  })  log.Fatal(http.ListenAndServe(":8081", nil))}

接著把服務跑起來:

go run main.go

在瀏覽器中訪問 http://localhost:8081/search?q=golang

很簡單是不是? 但這裡的問題在於我們把 https://cn.bing.com 寫死在了代碼中, 如果要切換搜尋引擎就得重新編譯器, 真的是費時費力. 這時候我們就需要將配置解耦到設定檔中了.

設定檔

我們先在本地建一個設定檔 go-app.yml

app:  search_url: https://cn.bing.com/search?q=%v

然後通過 viper 這個比較流行的配置庫載入這個配置

conf/conf.go

package confimport ...func init() {  viper.SetConfigName("go-app")  viper.AddConfigPath(os.ExpandEnv(`$GOPATH\src\github.com\GotaX\config-server-demo`))  viper.SetConfigType("yaml")  if err := viper.ReadInConfig(); err != nil {    log.Fatal("Fail to load config", err)  }}

現在我們就把搜尋引擎的地址解耦到設定檔中去了

main.go

package mainimport ...func main() {  http.HandleFunc("/search", func(w http.ResponseWriter, req *http.Request) {    q := req.URL.Query().Get("q")        src := fmt.Sprintf(viper.GetString("app.search_url"), q)    fmt.Fprintf(w, `<iframe width="100%%" height="98%%" scrolling="auto" frameborder="0" src="%v">`, src)  })  log.Fatal(http.ListenAndServe(":8081", nil))}

轉移配置到雲端

接下來我們將設定檔從本地轉移到 Git 中, 處於方便我就直接放在當前倉庫的 config 分支中了.

地址為: https://github.com/GotaX/config-server-demo/tree/config

啟動配置中心

設定檔上傳完畢, 我們再新開一個 config-server 空分支搭建配置中心.

首先到 https://start.spring.io/ 頁面建立一個 Java + Gradle 的 Spring Boot 工程, 依賴項選 Config Server

點擊 "Generate Project" 將下載壓縮包, 並解壓.

修改 Application.java

package com.example.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.config.server.EnableConfigServer;@EnableConfigServer  // 添加這行@SpringBootApplicationpublic class DemoApplication {  public static void main(String[] args) {    SpringApplication.run(DemoApplication.class, args);  }}

修改 application.yml, 填入我們存放設定檔的倉庫地址

spring.cloud.config.server.git.uri: https://github.com/GotaX/config-server-demo.git

在工程根目錄啟動 config server

gradle bootrun

訪問 http://localhost:8080/config/go-app-default.yml 查看配置

app:  search_url: https://cn.bing.com/search?q=%v

這樣我們的配置中心就啟動完畢了

在 Go 應用中讀取配置

最後就是在應用中使用 Spring Cloud Config Server 中的配置了. 如果是基於 Spring Boot 的應用可以直接使用 spring-cloud-config-client 載入配置. 在 Go 中就需要稍微寫點代碼了, 不過並不多.

我們先在 config.go 中添加一個 loadRemote() 函數, 用來從配置中心讀取配置

conf/conf.go

// ...const (  kAppName       = "APP_NAME"  kConfigServer  = "CONFIG_SERVER"  kConfigLabel   = "CONFIG_LABEL"  kConfigProfile = "CONFIG_PROFILE"  kConfigType    = "CONFIG_TYPE")func loadRemoteConfig() (err error) {    // 組裝設定檔地址: http://localhost:8080/config/go-app-default.yaml  confAddr := fmt.Sprintf("%v/%v/%v-%v.yml",    viper.Get(kConfigServer), viper.Get(kConfigLabel),    viper.Get(kAppName), viper.Get(kConfigProfile))  resp, err := http.Get(confAddr)  if err != nil {    return  }  defer resp.Body.Close()    // 設定設定檔格式: yaml  viper.SetConfigType(viper.GetString(kConfigType))    // 載入設定檔  if err = viper.ReadConfig(resp.Body); err != nil {    return  }  log.Println("Load config from: ", confAddr)  return}

當然, 我們需要知道配置中心的入口, 因此還需要一個 initDefault() 函數來初始化這些配置

conf/conf.go

func initDefault() {  viper.SetDefault(kAppName, "go-app")  viper.SetDefault(kConfigServer, "http://localhost:8080")  viper.SetDefault(kConfigLabel, "config")  viper.SetDefault(kConfigProfile, "default")  viper.SetDefault(kConfigType, "yaml")}

現在我們的 init() 函數變成了這樣

conf/conf.go

func init() {  viper.AutomaticEnv()  initDefault()  if err := loadRemoteConfig(); err != nil {    log.Fatal("Fail to load config", err)  }}

其中的 viper.AutomaticEnv() 可以讓我們通過環境變數修改任意配置, 因此 initDefault() 中的配置也不是寫死在代碼中的了. 其中比較常見的用法是通過 CONFIG_PROFILE=prod 環境變數來切換 profile

最後我們希望 viper 僅在 conf 包中出現, 而對外隱藏我們載入配置的具體實現. 因此我們將配置讀到結構體中再對外提供.

conf/conf.go

var App AppConfigtype AppConfig struct {  SearchUrl string `mapstructure:"search_url"`}func init() {  // ...  if err := sub("app", &App); err != nil {    log.Fatal("Fail to parse config", err)  }}func sub(key string, value interface{}) error {  sub := viper.Sub(key)  sub.AutomaticEnv()  sub.SetEnvPrefix(key)  return sub.Unmarshal(value)}

這時我們就可以從 main.go 中去掉 viper.Get() 調用了

main.go

import ...func main() {  http.HandleFunc("/search", func(w http.ResponseWriter, req *http.Request) {    q := req.URL.Query().Get("q")    src := fmt.Sprintf(conf.App.SearchUrl, q)    fmt.Fprintf(w, `<iframe width="100%%" height="98%%" scrolling="auto" frameborder="0" src="%v">`, src)  })  log.Fatal(http.ListenAndServe(":8081", nil))}

總結

我們通過 Git + Spring Could Config Server + Viper + 少量 Go 代碼, 實現了基於配置中心的組態管理及使用

我們甚至可以在 Go 中使用類似於 Spring Boot 的 Profile 管理, 對比下:

  • http://localhost:8080/config/go-app-default.yml
  • http://localhost:8080/config/go-app-prod.yml

完整的代碼可以參考 https://github.com/GotaX/config-server-demo 下的 3 個分支:

  • config: 設定檔
  • config-server: 配置中心
  • app: Go 應用

當然, 目前這種使用方式還比較簡陋, 還有很多可以改進的地方, 比如:

  • 結合 Spring Cloud Bus 實現配置的即時推送
  • 結合 Spring Cloud Eureka 實現設定管理員的高可用
  • 監聽 SIGINT 和 SIGTERM 實現 Go 應用優雅退出

有機會的話下次再寫, 或者也可以直接參考 Spring Cloud Config Server 的官方文檔

如果你有疑問或者更好的想法, 實踐, 歡迎留言討論

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.