半熟前端

軟體工程師 / 台灣人 / 在前端的路上一邊探索其他領域的可能性

幫專案設定環境變數 - VIPER

大概在好幾個月前,我寫了一篇關於如何在 golang 設定環境變數的文章,怎麼優雅地設定環境變數是一件相當重要的事情,因此我寫了一個簡單的函式來做這件事。

當初的考量很簡單,如果有提供對應的 config 檔,就把裡頭的 key/value 用 os.Setenv 設定。之後在整個 App 當中,就可以直接使用 os.Getenv 來取值。

不過一旦要正式部署,難免會發現幾個問題:

  • 設定檔不一定是用 yaml,也可能是用其他格式
  • 有時希望透過外部服務(consul, etcd 等等)來注入環境變數,但目前的寫法是用 os.Getenv
  • 可以從不同的路徑讀取設定檔
  • 可以透過 command line 設定變數
  • 更多意想不到的問題

在小型專案中,這樣其實解決了我的問題,但一旦需要更彈性的設定方式,光是這樣還不夠。

而以上這些問題其實在 golang 已經有一套成熟的解決方案,叫做 Viper

VIPER

VIPER 是一個功能相當強大的環境變數設定套件。它支援了下列功能:

  • 預設值
  • 支援不同格式的設定檔(json, toml, yaml
  • 可以監聽設定檔的變化(這樣就不用重開 server 了!)
  • 可以從遠端伺服器拿取變數(例如 consuletcd
  • 可以使用 flag 來獲取變數
  • 可以從 reader 來獲取變數,這代表你可以用不同的來源來設定變數。

基本使用

首先先用 go get 或 mod 下載 VIPER。

go get github.com/spf13/viper

func main() {
  viper.SetDefault("AWS_ACCESS_TOKEN", "AWS123456789") // 設定預設值
	viper.SetConfigName("config") // 指定 config 的檔名
	viper.AddConfigPath("./config")
	viper.ReadInConfig()
	viper.AutomaticEnv()
}
  • SetDefault(key, value):設定預設值
  • SetConfigName(name): 設定 config 的檔名,例如我們的設定檔叫做 config.yml 就叫做 config,為什麼不用指定 type 呢?viper 會自動幫我們處理。
  • AddConfigPath:可以設定多個資料夾
  • ReadInConfig:要記得呼叫,才會真的讀取設定
  • AutomaticEnv:可以自動將 ENV 的變數同步到 viper 當中

viper 還有提供許多函數方便設定。

取用變數

設定完變數後,我們可以用 viper.Get 來讀取。Get 回傳的是一個 interface{},但 viper 也提供許多型別轉換,例如 viper.GetStringviper.GetDurationviper.GetStringMap 等等。

func main() {
	fmt.Println(viper.GetString("AWS_ACCESS_TOKEN"))
  fmt.Println(viper.GetUint32("YOUR_INT"))
  fmt.Println(viper.GetTime("YOUR_TIME"))
}

總結

變數設定說難不難,說簡單不簡單,要考慮的事情比想像中的還多,而 VIPER 幫我們處理掉了很多常見的使用情景。

另外要特別提醒的一點是,在設定像是 access token 或是 secret key 的時候,一定要記得用 .gitignore 掉,避免 commit 時意外推送到 github 上,造成遺憾。