This is the 19th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021

introduce

As a complete example, the Echo framework differentiates configuration files by environment. That is, how to read different configuration files in test, online, etc.

We will use RK-boot to start the Echo framework microservice.

Please visit the following address for the full tutorial:

  • rkdocs.netlify.app/cn

The installation

go get github.com/rookie-ninja/rk-boot
Copy the code

Quick start

Yaml config/ Shanghai. Yaml config/default.yaml config/default.yaml config/ Beijing. yaml config/ Shanghai.

Rk-boot uses REALM, REGION, AZ, and DOMAIN environment variables to distinguish between different environments. This is also our recommended cloud native environment resolution method. For example, REALM=” your business “, REGION=” Beijing “, AZ=” Beijing 1 “, DOMAIN=” test environment “.

Rk-boot integrates viper to process configuration files.

1. Create a configuration file

  • config/beijing.yaml
---
region: beijing
Copy the code
  • config/shanghai.yaml
---
region: shanghai
Copy the code
  • config/default.yaml
---
region: default
Copy the code

2. Create the boot. Yaml

The boot.yaml file tells RK-boot how to start the Echo service.

We use config as the entry point for configuration files in boot.yaml, and multiple config file paths can be provided.

Locale stands for the environment of Config, and we use locale to distinguish between different Configs.

Why is config.name used with the same name?

We want to use the same set of code, but read different files, and we want the names of the files to be different. So you use locale to differentiate between files. We’ll talk more about the logic of locales later.

config:
  # the default
  - name: my-config
    locale: * : : : : : : "*"
    path: config/default.yaml
  If the environment variable REGION= Beijing, read this file
  - 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
echo:
  - name: greeter
    port: 8080
    enabled: true
Copy the code

3. Create a 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(a) {
	// 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())
}
Copy the code

4. Folder structure

$tree. ├ ─ ─ the boot. Yaml ├ ─ ─ the config │ ├ ─ ─ Beijing. The yaml │ ├ ─ ─ the default. The yaml │ └ ─ ─ Shanghai. The yaml ├ ─ ─. Mod ├ ─ ─. Sum └ ─ ─ main.goCopy the code

5. Verify

$ go run main.go
Copy the code

We get the following output:

beijing
Copy the code

6. No matching environment variable is found

If REGION=”not-matched”, that is, no matching environment variable is found, the default configuration file (config/default.yaml) will be read. The locale attribute of config/default.yaml is *::*::*: *

// Application entrance.
func main(a) {
    // 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"))... }Copy the code
default
Copy the code

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(a){...// Load config which is config/beijing.yaml
	fmt.Println(boot.GetConfigEntry("my-config").GetViper().GetString("region"))... }Copy the code
default
Copy the code

concept

Rk-boot uses four environment variables to distinguish configuration files: REALM, REGION, AZ, and DOMAIN.

These four environment variables can be arbitrary values.

Best practices

For example, we have a cloud photo album business. If the IP address of MySQL used by this service is different in different environments, you can perform this configuration.

architecture

Suppose that our business has servers in [Beijing] and [Shanghai], and in order to improve service availability, we have opened two districts in [Beijing] and [Shanghai] respectively.

In this case, you can configure the following environment variables on the machine, which can be set in batches using tools like Ansible.

The environment Corresponding environment variables
Beijing, District 1, 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, Sector two, test REALM=”cloud-album”, REGION=”bj”, AZ=” BJ-2 “, DOMAIN=”test”
Beijing, District 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, Sector two, test REALM=”cloud-album”, REGION=”sh”, AZ=”sh-2″, DOMAIN=”test”
Shanghai, Area 2, online REALM=”cloud-album”, REGION=”sh”, AZ=”sh-2″, DOMAIN=”prod”

In the meantime, if we do not use services like ETCD, Consul to remotely pull the configuration file, we can directly add the following files to the machine. Each file has a different MySQL IP address.

Folder structure

. ├ ─ ─ the boot. Yaml ├ ─ ─ the 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 │ └ ─ ─ the default. The yaml ├ ─ ─. Mod ├ ─ ─. Sum └ ─ ─ main. GoCopy the code

boot.yaml

Next, we add the following config entry to boot.yaml.

config:
  # default entry
  - name: my-config
    locale: * : : : : : : "*"
    path: config/default.yaml
  # Beijing, Zone 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, District 2, Online environment
  - name: my-config
    locale: "cloud-album::bj::bj-2::prod"
    path: config/bj-2-prod.yaml
  # Shanghai, Zone 1, Test environment
  - name: my-config
    locale: "cloud-album::sh::sh-1::test"
    path: config/sh-1-test.yaml
  # Shanghai, District 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, District 2, Online environment
  - name: my-config
    locale: "cloud-album::sh::sh-2::prod"
    path: config/sh-2-prod.yaml
echo:
  - name: greeter
    port: 8080
    enabled: true
Copy the code

Go to read the configuration file.

Because all Config is named my-config, we can use my-config to get ConfigEntry when reading from main.go.

package main

import (
	"context"
	"fmt"
	"github.com/rookie-ninja/rk-boot"
	"os"
)

// Application entrance.
func main(a) {
	// 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())
}
Copy the code