introduce
Using a complete example, in the Gin framework, profiles are distinguished based on the environment. That is, how to read different profiles in environments such as Testing and Online.
We will use rk-boot To start the Gin Framework microservice.
Visit the following address for the complete tutorial:
install
go get github.com/rookie-ninja/rk-boot
Quick Start
We will create three config files, config/beijing.yaml, config/shanghai.yaml, config/default.yaml, and then read different files based on different environment variables.
rk-boot uses REALM, REGION, AZ, DOMAIN environment variables to distinguish between different environments. This is also the recommended method for cloud native environment resolution.
For example, REALM="Your Business", "REGION="Beijing","AZ="Beijing Area", "DOMAIN="Test Environment".
rk-boot integration viper To process the configuration file.
1. Create a configuration file
- config/beijing.yaml
--- region: beijing
- config/shanghai.yaml
--- region: shanghai
- config/default.yaml
--- region: default
2. Create boot.yaml
The boot.yaml file tells rk-boot how to start the Gin service.
Using config as the entry to the configuration file in boot.yaml, we can provide multiple config file paths.
Locale represents the Config environment, and we use locale to distinguish between different Configs.
Why does config.name use the same name?
We want to use the same set of code, but read different files, and we want different names for the files. So use locale to distinguish between different files. The logic of locale is detailed later.
config: # default - name: my-config locale: "*::*::*::*" path: config/default.yaml # Read this file if the environment variable REGION=beijing - name: my-config locale: "*::beijing::*::*" path: config/beijing.yaml # If the environment variable REGION=shanghai, read this file - name: my-config locale: "*::shanghai::*::*" path: config/shanghai.yaml gin: - name: greeter port: 8080 enabled: true
3. Create main.go
Set the environment variable: REGION="beijing", then read the configuration file, config/beijing.yaml will be read.
package main import ( "context" "fmt" "github.com/rookie-ninja/rk-boot" "os" ) // Application entrance. func main() { // Set REGION=beijing os.Setenv("REGION", "beijing") // Create a new boot instance. boot := rkboot.NewBoot() // Load config which is config/beijing.yaml fmt.Println(boot.GetConfigEntry("my-config").GetViper().GetString("region")) // Bootstrap boot.Bootstrap(context.Background()) // Wait for shutdown sig boot.WaitForShutdownSig(context.Background()) }
4. Folder structure
$ tree . ├── boot.yaml ├── config │ ├── beijing.yaml │ ├── default.yaml │ └── shanghai.yaml ├── go.mod ├── go.sum └── main.go
5. Validation
$ go run main.go
We will get the following output:
beijing
6. No matching environment variable found
If REGION="not-matched", that is, no matching environment variable is found, the default configuration file (config/default.yaml) is read. Because the locale property of config/default.yaml is *:*:*:*:*
// Application entrance. func main() { // Set REGION=not-matched os.Setenv("REGION", "not-matched") ... // Load config which is config/beijing.yaml fmt.Println(boot.GetConfigEntry("my-config").GetViper().GetString("region")) ... }
default
7. Environment variables are not configured
If we do not configure the REGION environment variable, the config/default.yaml file is read.
// Application entrance. func main() { ... // Load config which is config/beijing.yaml fmt.Println(boot.GetConfigEntry("my-config").GetViper().GetString("region")) ... }
default
concept
rk-boot uses four environment variables, REALM, REGION, AZ, DOMAIN, to distinguish profiles.
These four environment variables can be any value.
Best Practices
For example, we have a Cloud Album business. This can be configured if the business uses MySQL with different IP addresses in different environments.
Framework
Assume that our business has servers in both Beijing and Shanghai, and there are two zones in Beijing and Shanghai to improve service availability.
At this point, we can configure the following environment variables on the machine, which can be set in batches using tools such as Ansible.
Environmental Science | Corresponding environment variables |
---|---|
Beijing, District One, Test | REALM="cloud-album",REGION="bj",AZ="bj-1",DOMAIN="test" |
Beijing, District 1, Online | REALM="cloud-album",REGION="bj",AZ="bj-1",DOMAIN="prod" |
Beijing, Zone 2, Test | REALM="cloud-album",REGION="bj",AZ="bj-2",DOMAIN="test" |
Beijing, Zone 2, Online | REALM="cloud-album",REGION="bj",AZ="bj-2",DOMAIN="prod" |
Shanghai, District 1, Test | REALM="cloud-album",REGION="sh",AZ="sh-1",DOMAIN="test" |
Shanghai, District 1, Online | REALM="cloud-album",REGION="sh",AZ="sh-1",DOMAIN="prod" |
Shanghai, Zone 2, Test | REALM="cloud-album",REGION="sh",AZ="sh-2",DOMAIN="test" |
Shanghai, Zone 2, Online | REALM="cloud-album",REGION="sh",AZ="sh-2",DOMAIN="prod" |
At the same time, if we do not use services like ETCD, Consul to remotely pull configuration files, we can add the following files directly to the machine. Each file has a different MySQL IP address.
Folder structure
. ├── boot.yaml ├── config │ ├── bj-1-test.yaml │ ├── bj-1-prod.yaml │ ├── bj-2-test.yaml │ ├── bj-2-prod.yaml │ ├── sh-1-test.yaml │ ├── sh-1-prod.yaml │ ├── sh-2-test.yaml │ ├── sh-2-prod.yaml │ └── default.yaml ├── go.mod ├── go.sum └── main.go
boot.yaml
Next, we add the following config entry in boot.yaml.
config: # Default Entry - name: my-config locale: "*::*::*::*" path: config/default.yaml # BEIJING, DISTRICT 1, TEST ENVIRONMENT - name: my-config locale: "cloud-album::bj::bj-1::test" path: config/bj-1-test.yaml # Beijing, District 1, Online Environment - name: my-config locale: "cloud-album::bj::bj-1::prod" path: config/bj-1-prod.yaml # Beijing, Zone 2, Test Environment - name: my-config locale: "cloud-album::bj::bj-2::test" path: config/bj-2-test.yaml # Beijing, Zone 2, Online Environment - name: my-config locale: "cloud-album::bj::bj-2::prod" path: config/bj-2-prod.yaml # Shanghai, Area 1, Test Environment - name: my-config locale: "cloud-album::sh::sh-1::test" path: config/sh-1-test.yaml # Shanghai, Area 1, Online Environment - name: my-config locale: "cloud-album::sh::sh-1::prod" path: config/sh-1-prod.yaml # Shanghai, Zone 2, Test Environment - name: my-config locale: "cloud-album::sh::sh-2::test" path: config/sh-2-test.yaml # Shanghai, Zone 2, Online Environment - name: my-config locale: "cloud-album::sh::sh-2::prod" path: config/sh-2-prod.yaml gin: - name: greeter port: 8080 enabled: true
main.go reads the configuration file.
Because all Configs are named my-config, we can use my-config to get ConfigEntry while reading from main.go.
package main import ( "context" "fmt" "github.com/rookie-ninja/rk-boot" "os" ) // Application entrance. func main() { // Create a new boot instance. boot := rkboot.NewBoot() // Get viper instance based on environment variable boot.GetConfigEntry("my-config").GetViper() // Bootstrap boot.Bootstrap(context.Background()) // Wait for shutdown sig boot.WaitForShutdownSig(context.Background()) }