nacos configuration center docker deployment, configuration and goLang integration use

Why a configuration center is needed

Usually when we write a demo, or a single application, there will be a configuration file, whether it is a json file or a yaml file, which contains redis, mysql, es and other information. If we modify the configuration file, we often A restart is required. In order to avoid restarting, viper was later introduced to enable hot updates. But not all projects support viper. If it is a distributed system, it must be supported by many service modules, and the services are scalable. There may be dozens or hundreds of services. If each service module has its own configuration file, then if mysql updates the port number, the operation and maintenance personnel will have to change the files one by one. And it’s possible to accidentally make a mistake.

So to sum up, there are probably three pain points for service configuration:

  • After modifying the configuration items, the service needs to be restarted, which is unacceptable for a production environment.
  • Operation and maintenance personnel need to modify the configuration files under each project. Inefficient and unsafe.
  • Generally, companies have development environments, test environments, pre-production environments and production environments. How to isolate configurations in different environments?

In order to solve the above problems, the configuration center came into being. So what is a configuration center?

Configuration Center

  • Unified configuration management: The modification and editing of configuration items are unified on the configuration center page. It also includes unified configuration version management, environment isolation, grayscale release and hot release, so that the modified configuration can take effect without restarting the application.
  • Unified permission control mainly controls the read permission and modification permission of its configuration, and improves operation and maintenance efficiency through unified permission management.
  • Unified operation audit records the historical information of user operation modification configuration, so that when problems occur, review can be performed and operations audited at the same time.

Selection of configuration center

At present, the most mainstream distributed configuration centers mainly include spring cloud config apollo and nacos. Spring cloud belongs to the spring system of java, so we will consider apollo and nacos. Apollo and nacos are two configuration centers that are currently popular and actively maintained. Apollo is an open source coroutine, and nacos is an open source from Alibaba.

  • apollo is large, comprehensive and fully functional. nacos is small and comprehensive, and can be compared to the difference between diango and flask
  • Deploying nacos is easier.
  • nacos not only supports the configuration center but also supports service registration and discovery.
  • Both support various languages, but apollo is supported by a third party, and nacos officially supports various languages, so we also choose nacos as the configuration center.

Nacos

  • Installation For convenience, we directly use docker to start the Nacos service
docker run -d --name nacos -p 8848:8848 --privileged=true -e JVM_XMS=256m -e JVM_XMX=256m -e MODE=standalone nacos/nacos-server:latest

  • -d starts in background
  • –name specifies a name for the container
  • -p specifies the port number
  • –privileged=true: Expand the permissions in the container and change the permissions in the container to root permissions
  • -e JVM_XMS=256m: memory allocated for jvm startup
  • -e JVM_XMX=256m: The maximum memory allocated for the jvm during operation
  • -e MODE=standalone: Use standalone mode (stand-alone mode), MODE value has two types: cluster (cluster) mode/standalone mode, MODE must be capitalized

Control Panel

  • After startup, visit http://127.0.0.1:8848/nacos/

Group Configuration Set Namespace

Let’s create a new configuration and take a look

Namespace

  • We can distinguish different microservices through namespaces

Group

  • We can achieve service isolation through namespaces, but how do we also isolate the configuration of development, testing and production environments. This uses groups

dataid

  • Generally speaking, a configuration file corresponds to a dataid. This does not mean that the dataid must be unique. We only need to ensure that the Namespace + Group + DataId combination is unique.

Access nacos through api

Related references

  • As a configuration center, nacos uses the following functions the most:

  • Here we give an example to obtain the user’s dev configuration file, where dataId corresponds to dataId, group is the group, and tenant is the id of the namespace.
$ curl -X GET 'http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=user-dev & amp;group=dev & amp;tenant=311387f1-790b-4045- 8787-571addb6c9fd'
database:
  driver: mysql
  host: 192.168.2.251
  port: 13309
  username: test
  dbname: cnk_user
  password:user

  • update file
 $ curl -X POST 'http://127.0.0.1:8848/nacos/v1/cs/configs' -d 'dataId=user-dev & amp;group=dev & amp;tenant=311387f1 -790b-4045-8787-571addb6c9fd &content=test'
true

Insert image description here

Integration in Go

  • How do we use it in go? Let’s take a look at the simple code
package main

import (
 "fmt"
 "github.com/nacos-group/nacos-sdk-go/clients"
 "github.com/nacos-group/nacos-sdk-go/common/constant"
 "github.com/nacos-group/nacos-sdk-go/vo"
)

func main() {
 ch:=make(chan int)
 ch<-1
}

func init() {
 sc := []constant.ServerConfig{<!-- -->{
  IpAddr: "127.0.0.1",
  Port: 8848,
 }}

 cc := constant.ClientConfig{
  NamespaceId: "311387f1-790b-4045-8787-571addb6c9fd", // If we need to support multiple namespaces, we can scenario multiple clients, which have different NamespaceIds. When namespace is public, fill in the blank string here.
  TimeoutMs: 5000,
  NotLoadCacheAtStart: true,
  LogDir: "log",
  CacheDir: "cache",
  LogLevel: "debug",
 }

 configClient, err := clients.CreateConfigClient(map[string]interface{}{
  "serverConfigs": sc,
  "clientConfig": cc,
 })
 if err != nil {
  fmt.Println(err.Error())
 }

 content, err := configClient.GetConfig(vo.ConfigParam{
  DataId: "user-dev",
  Group: "dev",
 })

 if err != nil {
  fmt.Println(err.Error())
 }
 fmt.Println(content) //String - yaml
 err = configClient.ListenConfig(vo.ConfigParam{
  DataId: "user-dev",
  Group: "dev",
  OnChange: func(namespace, group, dataId, data string) {
   fmt.Println("The configuration file has changed...")
   fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
  },
 })
}

  • We modify the configuration file through the API
$ curl -X POST 'http://127.0.0.1:8848/nacos/v1/cs/configs' -d 'dataId=user-dev & amp;group=dev & amp;tenant=311387f1 -790b-4045-8787-571addb6c9fd &content=test1111'
true
  • See that the modified files have been monitored

  • So how do we parse and modify yaml files? For example, we now have a configuration like this

  • We first parse it into a structure and then parse it
package main

import (
 "fmt"
 "github.com/nacos-group/nacos-sdk-go/clients"
 "github.com/nacos-group/nacos-sdk-go/common/constant"
 "github.com/nacos-group/nacos-sdk-go/vo"
 "gopkg.in/yaml.v2"
)

func main() {
 ch := make(chan int)
 ch<-1
}

type DatabaseNew struct {
 Driver string `yaml:"driver"`
 Host string `yaml:"host"`
 Port int `yaml:"port"`
 Username string `yaml:"username"`
 Dbname string `yaml:"dbname"`
 Password string `yaml:"password"`
}
type ConfigNew struct {
 Database DatabaseNew//Database configuration
}

varGlobalConfigConfigNew

func init() {
 sc := []constant.ServerConfig{<!-- -->{
  IpAddr: "127.0.0.1",
  Port: 8848,
 }}

 cc := constant.ClientConfig{
  NamespaceId: "311387f1-790b-4045-8787-571addb6c9fd", // If we need to support multiple namespaces, we can scenario multiple clients, which have different NamespaceIds. When namespace is public, fill in the blank string here.
  TimeoutMs: 5000,
  NotLoadCacheAtStart: true,
  LogDir: "log",
  CacheDir: "cache",
  LogLevel: "debug",
 }

 configClient, err := clients.CreateConfigClient(map[string]interface{}{
  "serverConfigs": sc,
  "clientConfig": cc,
 })
 if err != nil {
  fmt.Println(err.Error())
 }

 content, err := configClient.GetConfig(vo.ConfigParam{
  DataId: "user",
  Group: "prod",
 })
 SetConfig(content)

 if err != nil {
  fmt.Println(err.Error())
 }
 err = configClient.ListenConfig(vo.ConfigParam{
  DataId: "user",
  Group: "prod",
  OnChange: func(namespace, group, dataId, data string) {
   fmt.Println("The configuration file has changed...")
   fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
   SetConfig(data)
  },
 })
}

func SetConfig(content string) {
 fmt.Println(content)
 err := yaml.Unmarshal([]byte(content), & &GlobalConfig)
 if err != nil {
  fmt.Println(err)
 }
 fmt.Printf("% + v", GlobalConfig)
}

We modify the configuration through the console panel