이번 게시글에서는 viper를 사용하여 go 애플리케이션 profile을 설정하는 방법에 대해 정리합니다.
1. profile이란?
애플리케이션을 개발하다 보면 애플리케이션의 설정을 유동적으로 관리 하는 경우가 있습니다.
예를 들면 로컬환경, 테스트용 베타서버, 운영서버는 DB, log setting 등이 다릅니다.
모든것을 환경변수로 관리하고 컨테이너 환경의 환경변수를 관리하는 파일을 따로 만드는 경우도 있지만
profile파일을 도입하면 보다 편리하게 설정을 관리할 수 있습니다.
2. 프로젝트 구조(https://github.com/jaeho310/golang-profile-viper)
.
|-- configuration
| `-- config_model.go
|-- go.mod
|-- go.sum
|-- local.yaml
|-- main.go
`-- prod.yaml
3. local.yaml, prod.yaml
local.yaml
datasource:
dbType: "sqlite3"
url: "./local.db"
server:
port: 8080
prod.yaml
datasource:
dbType: "mariadb"
url: "211.211.70.70:3306"
userName: "test"
password: "test"
server:
port: 8395
local 환경에서는 sqlite3를 운영환경에서는 mariadb를 사용한다고 가정하였습니다.
해당 설정들을 모두 환경변수로 관리하지않고
환경변수로는 프로필이 local과 prod인지만 확인하고 모든설정을 yaml파일에 작성하도록 합니다.
4. configuration/config_model.go
package configuration
var RuntimeConf = RuntimeConfig{}
type RuntimeConfig struct {
Datasource Datasource `yaml:"datasource"`
Server Server `yaml:"server"`
}
type Datasource struct {
DbType string `yaml:"dbType"`
Url string `yaml:"url"`
UserName string `yaml:"userName"`
Password string `yaml:"password"`
}
type Server struct {
Port int `yaml:"port"`
}
yaml파일로 저장되어있는 cnofig를 담을 구조체 입니다.
RuntimeConfig변수를 만들어 어디서든 접근할 수 있도록 하였습니다.
5. main.go
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"os"
"time"
"viper-tut/configuration"
)
// main 패키지에 init() 메서드를 만들어놓으면
// main문이 실행되기전에 먼저 실행됩니다.
func init() {
profile := initProfile()
setRuntimeConfig(profile)
}
// PROFILE을 기반으로 config파일을 읽고 전역변수에 언마샬링 해줍니다.
func setRuntimeConfig(profile string) {
viper.AddConfigPath(".")
// 환경변수에서 읽어온 profile이름의 yaml파일을 configPath로 설정합니다.
viper.SetConfigName(profile)
viper.SetConfigType("yaml")
err := viper.ReadInConfig()
if err != nil {
panic(err)
}
// viper는 읽어온 설정파일의 정보를 가지고있으니, 전역변수에 언마샬링해
// 애플리케이션의 원하는곳에서 사용하도록 합니다.
err = viper.Unmarshal(&configuration.RuntimeConf)
if err != nil {
panic(err)
}
// 일반적인 프로필 설정은 이 위까지 적용하시면 됩니다.
// viper는 설정파일이 변경된 이벤트를 핸들링할수 있습니다.
// 설정파일이 변경되면 다시 언마샬링해줍니다.
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
var err error
err = viper.ReadInConfig()
if err != nil {
fmt.Println(err)
return
}
err = viper.Unmarshal(&configuration.RuntimeConf)
if err != nil {
fmt.Println(err)
return
}
})
viper.WatchConfig()
}
// 환경변수는 PROFILE을 확인하기 위해 하나만 설정합니다.
func initProfile() string {
var profile string
profile = os.Getenv("GO_PROFILE")
if len(profile) <= 0 {
profile = "local"
}
fmt.Println("GOLANG_PROFILE: " + profile)
return profile
}
func main() {
// RuntimeConf변수는 어디서든 가져다 쓸 수 있습니다.
fmt.Println("db type: ", configuration.RuntimeConf.Datasource.DbType)
for {
<-time.After(time.Second * 3)
fmt.Println("db type: ", configuration.RuntimeConf.Datasource.DbType)
}
}
환경변수로 PROFILE하나만 설정하면 config 파일을 읽어 runtime에서의 config를 적용시켜줍니다.
golang은 main문이 실행되기 이전 init() 메서드가 호출되니 해당메서드에 yaml파일을 읽는 로직을 담아줍니다.
viper는 단순한 yaml reader와 다르게 여러가지 유틸을 제공합니다.(아래는 공식문서)
예시로는 config 파일이 변경되면 다시 읽어와 적용시켜주는 유틸을 사용하였지만
아래의 공식문서에서 필요한 유틸을 가져다 사용하시면 될것 같습니다.
'golang' 카테고리의 다른 글
[golang] vue와 golang echo framework 연동하기 (0) | 2022.01.24 |
---|---|
[golang] go context, go-cache를 활용한 캐시 서버 만들기 (0) | 2022.01.13 |
[golang] go-redis, redis-mock 사용법 및 예제(suite 사용법) (0) | 2021.12.13 |
[golang] go context의 활용2(go context사용법 및 예제2) (0) | 2021.12.09 |
[golang] go context의 활용1(go context사용법 및 예제1) (0) | 2021.12.07 |
댓글