Using Spring Cloud Config Server to manage configuration in a Golang project

Source: Internet
Author: User
Tags key string

Introduction

Recently with Go write back end write very happy, write a more useful blog summary under How to manage the Go program configuration through Spring Cloud Config Server. The implementation is not complex, so it can be easily extended to programs in other languages.

First of all, why do you want to do centralized configuration management? In the era of single application configuration management is not a big problem, the general configuration file and the source code in the repository together, to view or modify directly to the conf directory to find the finished. But to the micro-service era, the number of services more than in the past dozens of times times, and then to the vast number of code warehouse to find configuration can not be so simple . So we need a unified view of the configuration, the configuration can be version control of the place, this is the configuration center.

Searching for "Configuration Center" on Google can find a lot of good open source software, but most of them are heavier and need to be introduced to specific clients. This is too much for small and medium-sized teams who are not so large. So instead of a lightweight configuration center like Spring Cloud Config Server, it's a good fit to run in minutes, and it's rich enough to be relevant to the configuration itself.

So our architecture is like this:

    • Git: Store specific configuration files and be responsible for configuring version management
    • Spring Cloud Config Server: Provides a configured query interface
    • Go App: Load configuration from configuration center and use

OK, let's do it officially.

A simple search service

As a demonstration we use Go to write a very simple search service. As long as GET /search?q=<keyword> the access to the service will be found in search engine results. With Go implementation as long as a file Oh ~

Main.go

package mainimport ...func main() {  http.HandleFunc("/search", func(w http.ResponseWriter, req *http.Request) {    q := req.URL.Query().Get("q")        fmt.Fprintf(w, `<iframe width="100%%" height="98%%" scrolling="auto" frameborder="0" src="https://cn.bing.com/search?q=%v">`, q)  })  log.Fatal(http.ListenAndServe(":8081", nil))}

Then run the service up:

go run main.go

accessing in the browserhttp://localhost:8081/search?q=golang

It's simple, isn't it? But the problem here is that we put the https://cn.bing.com write dead in the code, if you want to switch the search engine will have to recompile the program, it is really time-consuming and laborious. This is where we need to decouple the configuration from the configuration file.

Configuration file

Let's start with a local configuration file.go-app.yml

app:  search_url: https://cn.bing.com/search?q=%v

This configuration is then loaded via Viper, the more popular configuration library

Conf/conf.go

package confimport ...func init() {  viper.SetConfigName("go-app")  viper.AddConfigPath(os.ExpandEnv(`$GOPATH\src\github.com\GotaX\config-server-demo`))  viper.SetConfigType("yaml")  if err := viper.ReadInConfig(); err != nil {    log.Fatal("Fail to load config", err)  }}

Now we're going to decouple the search engine's address into the config file.

Main.go

package mainimport ...func main() {  http.HandleFunc("/search", func(w http.ResponseWriter, req *http.Request) {    q := req.URL.Query().Get("q")        src := fmt.Sprintf(viper.GetString("app.search_url"), q)    fmt.Fprintf(w, `<iframe width="100%%" height="98%%" scrolling="auto" frameborder="0" src="%v">`, src)  })  log.Fatal(http.ListenAndServe(":8081", nil))}

Transfer configuration to the cloud

Next we move the config file from local to Git, and it's convenient for me to put it directly in the Config branch of the current repository.

Address: Https://github.com/GotaX/config-server-demo/tree/config

Start the Configuration Center

After the configuration file has been uploaded, we will open a new config-server empty branch to build the configuration center.

First, create a new Java + Gradle Spring Boot project to the https://start.spring.io/page, and the dependency selection Config Server

Click "Generate Project" to download the compressed package and unzip it.

Modify Application.java

package com.example.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.config.server.EnableConfigServer;@EnableConfigServer  // 添加这行@SpringBootApplicationpublic class DemoApplication {  public static void main(String[] args) {    SpringApplication.run(DemoApplication.class, args);  }}

Modify APPLICATION.YML, fill in the warehouse address where we store the configuration file

spring.cloud.config.server.git.uri: https://github.com/GotaX/config-server-demo.git

Starting config server in the project root directory

gradle bootrun

Access http://localhost:8080/config/go-app-default.yml View Configuration

app:  search_url: https://cn.bing.com/search?q=%v

So our configuration center is up and ready.

Read the configuration in the Go app

Finally, the configuration in Spring Cloud Config Server is used in the application. If you are a Spring Boot-based app, you can use the spring-cloud-config-client load configuration directly. In go you need to write a little bit of code, but not much.

Let's first add a function to the Config.go loadRemote() to read the configuration from the configuration center

Conf/conf.go

// ...const (  kAppName       = "APP_NAME"  kConfigServer  = "CONFIG_SERVER"  kConfigLabel   = "CONFIG_LABEL"  kConfigProfile = "CONFIG_PROFILE"  kConfigType    = "CONFIG_TYPE")func loadRemoteConfig() (err error) {    // 组装配置文件地址: http://localhost:8080/config/go-app-default.yaml  confAddr := fmt.Sprintf("%v/%v/%v-%v.yml",    viper.Get(kConfigServer), viper.Get(kConfigLabel),    viper.Get(kAppName), viper.Get(kConfigProfile))  resp, err := http.Get(confAddr)  if err != nil {    return  }  defer resp.Body.Close()    // 设置配置文件格式: yaml  viper.SetConfigType(viper.GetString(kConfigType))    // 载入配置文件  if err = viper.ReadConfig(resp.Body); err != nil {    return  }  log.Println("Load config from: ", confAddr)  return}

Of course, we need to know the portal of the configuration center, so we also need a initDefault() function to initialize these configurations

Conf/conf.go

func initDefault() {  viper.SetDefault(kAppName, "go-app")  viper.SetDefault(kConfigServer, "http://localhost:8080")  viper.SetDefault(kConfigLabel, "config")  viper.SetDefault(kConfigProfile, "default")  viper.SetDefault(kConfigType, "yaml")}

And now our init() function becomes this.

Conf/conf.go

func init() {  viper.AutomaticEnv()  initDefault()  if err := loadRemoteConfig(); err != nil {    log.Fatal("Fail to load config", err)  }}

This allows viper.AutomaticEnv() us to modify any configuration with environment variables, so initDefault() the configuration is not written dead in the code. The more common use is CONFIG_PROFILE=prod to switch profile by environment variable

Finally we want Viper to appear only in the Conf package, while hiding the concrete implementation of our load configuration. So we read the configuration into the struct and provide it externally.

Conf/conf.go

var App AppConfigtype AppConfig struct {  SearchUrl string `mapstructure:"search_url"`}func init() {  // ...  if err := sub("app", &App); err != nil {    log.Fatal("Fail to parse config", err)  }}func sub(key string, value interface{}) error {  sub := viper.Sub(key)  sub.AutomaticEnv()  sub.SetEnvPrefix(key)  return sub.Unmarshal(value)}

Then we can remove the call from the Main.go viper.Get() .

Main.go

import ...func main() {  http.HandleFunc("/search", func(w http.ResponseWriter, req *http.Request) {    q := req.URL.Query().Get("q")    src := fmt.Sprintf(conf.App.SearchUrl, q)    fmt.Fprintf(w, `<iframe width="100%%" height="98%%" scrolling="auto" frameborder="0" src="%v">`, src)  })  log.Fatal(http.ListenAndServe(":8081", nil))}

Summarize

We implemented configuration center-based configuration management and usage with Git + Spring Could Config Server + Viper + small Go code

We can even use Spring Boot-like profile management in Go, in contrast:

    • Http://localhost:8080/config/go-app-default.yml
    • Http://localhost:8080/config/go-app-prod.yml

The complete code can refer to the 3 branches under Https://github.com/GotaX/config-server-demo:

    • Config: Configuration file
    • Config-server: Configuration Center
    • App:go applications

Of course, the use of this method is relatively simple, there are many improvements can be, such as:

    • Real-time push with Spring Cloud Bus for configuration
    • High availability with Spring Cloud Eureka for configuration servers
    • Monitor SIGINT and SIGTERM for Go app graceful exit

Write next time if you have a chance, or you can refer to the official documentation of Spring Cloud Config Server directly

If you have questions or better ideas, practice, welcome message Discussion

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.