如何使用 YAML 文件根据环境设置 Golang 应用程序的配置?

huangapple go评论76阅读模式
英文:

How to setup a golang app config according to the environment using yaml file

问题

我正在尝试设置一个配置结构体,以在我的应用程序中使用。

目前,我加载一个yaml文件并将其解码到我的配置结构体中。

config.yml
  database_url: postgres://postgres:@localhost:5432/database_dev
config.go
import (
  "os"
  "gopkg.in/yaml.v2"
)

type AppConfig struct {
  DatabaseUrl      string `yaml:"database_url"`
}

func LoadConfig() *AppConfig {
  appConfig := &AppConfig{}
  file, _ := os.Open("config.yml")
  defer f.Close()
  decoder := yaml.NewDecoder(file)
  decoder.Decode(config)
  return appConfig
}

它运行得非常好,但现在我需要根据环境(测试、本地、生产等)设置不同的配置。

我想使用嵌套的yaml文件来声明环境变量。

config.yml
dev:
  database_url: postgres://postgres:@localhost:5432/database_dev
test:
  database_url: postgres://postgres:@localhost:5432/database_test

我希望在我的LoadConfig函数中接收环境作为参数,并获取正确的配置。但我不知道如何做。

config.go

type configFile struct {
  Dev struct { AppConfig }`yaml:"dev"`
  Test struct { AppConfig }`yaml:"test"` 
}

func LoadConfig(env string) *AppConfig {
  appConfig := &AppConfig{}
  configFile := &configFile{}
  file, _ := os.Open("config.yml")
  defer f.Close()
  decoder := yaml.NewDecoder(file)
  decoder.Decode(configFile)
  
  // 在这里如何获取正确的结构体?
  // config = configFile["env"]
  // 它不起作用
  // invalid operation: cannot index configFile (variable of type *configFile)


  return appConfig
}

欢迎任何建议。

英文:

Im trying to setup a config struct to use through my application.

Currently I load a yaml file and decode it in my config struct.

config.yml
  database_url: postgres://postgres:@localhost:5432/database_dev
config.go
import (
  "os"
  "gopkg.in/yaml.v2"
)

type AppConfig struct {
  DatabaseUrl      string `yaml:"database_url"`
}

func LoadConfig() *AppConfig {
  appConfig := &AppConfig{}
  file, _ := os.Open("config.yml")
  defer f.Close()
  decoder := yaml.NewDecoder(file)
  decoder.Decode(config)
  return appConfig
}

It works really fine, but now I need to setup different configuration according with the environment (test, local, production, etc.).

I thought that I could use a nested yaml file to declare the environments variables.

config.yml
dev:
  database_url: postgres://postgres:@localhost:5432/database_dev
test:
  database_url: postgres://postgres:@localhost:5432/database_test

I would like to receive the environment as a parameter in my LoadConfig function, and get the correct configuration.
But I have no idea how to.

config.go

type configFile struct {
  Dev struct { AppConfig }`yaml:"dev"`
  Test struct { AppConfig }`yaml:"test"` 
}

func LoadConfig(env string) *AppConfig {
  appConfig := &AppConfig{}
  configFile := &configFile{}
  file, _ := os.Open("config.yml")
  defer f.Close()
  decoder := yaml.NewDecoder(file)
  decoder.Decode(configFile)
  
  // How to get the correct struct here ?
  // config = configFile["env"]
  // It doesn't works 
  // invalid operation: cannot index configFile (variable of type *configFile)


  return appConfig
}

Any suggestion is welcome.

答案1

得分: 0

如果环境列表是任意的,那么你不需要在顶层使用struct,而是需要使用map[string]AppConfig。代码如下所示:

package main

import (
	"fmt"
	"os"

	"gopkg.in/yaml.v2"
)

type (
	AppConfig struct {
		DatabaseUrl string `yaml:"database_url"`
	}

	ConfigFile map[string]*AppConfig
)

func LoadConfig(env string) (*AppConfig, error) {
	configFile := ConfigFile{}
	file, _ := os.Open("config.yml")
	defer file.Close()
	decoder := yaml.NewDecoder(file)

	// 总是检查错误!
	if err := decoder.Decode(&configFile); err != nil {
		return nil, err
	}

	appConfig, ok := configFile[env]
	if !ok {
		return nil, fmt.Errorf("no such environment: %s", env)
	}

	return appConfig, nil
}

func main() {
	appConfig, err := LoadConfig(os.Args[1])
	if err != nil {
		panic(err)
	}
	fmt.Printf("config: %+v\n", appConfig)
}

假设我们有你问题中提到的config.yml文件,我们可以使用不同的环境运行上述示例,并查看所需的输出:

$ ./example test
config: &{DatabaseUrl:postgres://postgres:@localhost:5432/database_test}
$ ./example dev
config: &{DatabaseUrl:postgres://postgres:@localhost:5432/database_dev}
英文:

If the list of environments is arbitrary, then you don't want a struct for the top level; you want a map[string]AppConfig. That would look something like this:

package main

import (
  "fmt"
  "os"

  "gopkg.in/yaml.v2"
)

type (
  AppConfig struct {
    DatabaseUrl string `yaml:"database_url"`
  }

  ConfigFile map[string]*AppConfig
)

func LoadConfig(env string) (*AppConfig, error) {
  configFile := ConfigFile{}
  file, _ := os.Open("config.yml")
  defer file.Close()
  decoder := yaml.NewDecoder(file)

  // Always check for errors!
  if err := decoder.Decode(&configFile); err != nil {
    return nil, err
  }

  appConfig, ok := configFile[env]
  if !ok {
    return nil, fmt.Errorf("no such environment: %s", env)
  }

  return appConfig, nil
}

func main() {
  appConfig, err := LoadConfig(os.Args[1])
  if err != nil {
    panic(err)
  }
  fmt.Printf("config: %+v\n", appConfig)
}

Assuming we have the config.yml from your question, we can run the above example with different environments and see the desired output:

$ ./example test
config: &{DatabaseUrl:postgres://postgres:@localhost:5432/database_test}
$ ./example dev
config: &{DatabaseUrl:postgres://postgres:@localhost:5432/database_dev}

答案2

得分: 0

我认为除了设置一个配置文件之外,你还应该创建一个YML文件,并将服务器端口放在其中...
不幸的是,我经验不足,所以可能没有给出正确的答案。

英文:

I think furthermore setting up a config file ,you should create a YML file and put this the server port...
Unfortunately I am inexperienced Therefore, I may not have given the correct answer.

答案3

得分: 0

我认为一种方法是我们可以为不同的环境使用不同的配置文件。例如,在开发环境中,我们有config_dev.yaml,在生产环境中,我们有config_prod.yaml

然后我们在引导脚本中指定环境变量。例如,我们通过export MyEnv=dev && ./my_app来运行应用程序。在代码中,我们检查MyEnv来决定使用哪个配置文件。在这种情况下,我们发现MyEnvdev,所以我们使用config_dev.yaml

英文:

I think one way is that we can different config files for different environments. For example, in dev environment we have config_dev.yaml, in production, we have config_prod.yaml.

Then we specify environment variable in the bootstrap scripts. For example we run the app by export MyEnv=dev && ./my_app. In the code, we check MyEnv to decide which config file we would use. In this case, we found MyEnv is dev so we use config_dev.yaml.

huangapple
  • 本文由 发表于 2023年1月28日 05:06:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/75263364.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定