前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >在 Golang 项目中使用 Spring Cloud Config Server 管理配置

在 Golang 项目中使用 Spring Cloud Config Server 管理配置

作者头像
李海彬
发布于 2018-07-26 03:08:02
发布于 2018-07-26 03:08:02
1.9K00
代码可运行
举报
文章被收录于专栏:Golang语言社区Golang语言社区
运行总次数:0
代码可运行

引言

最近用 Go 写后端写得很开心,写篇比较实用的博客总结下如何通过 Spring Cloud Config Server 管理 Go 程序中的配置。 实现并不复杂,因此也可以很轻易地推广到其他语言的程序中。

先来说说为什么要做集中配置管理。在单体应用时代配置管理并不是什么大问题, 一般配置文件就和源码一起放在代码仓库中, 要查看或者修改直接到 conf 目录里找就完事儿了。但到了微服务时代,服务的数量比过去多了几十倍,再到茫茫多的代码仓库里找配置可就没这么简单了。因此我们需要一个能够统一查看修改配置,能够对配置进行版本控制的地方,这就是配置中心了。

在 Google 上搜索 "配置中心" 能找到不少不错的开源软件,但大部分都比较重,并且需要引入特定的客户端。这对没到那么大规模的中小团队来说未免太过折腾,因此反而像 Spring Cloud Config Server 这样的轻量级配置中心比较适合,几分钟就能跑起来, 而且和配置本身相关的功能也足够丰富了。

因此我们的架构就像下面这样:

  • Git: 储存具体的配置文件, 并且负责配置版本管理
  • Spring Cloud Config Server:提供配置的查询接口
  • Go App:从配置中心载入配置并使用

简单的搜索服务

作为演示我们用 Go 写一个很简单的搜索服务,只要访问 GET /search?q=<keyword> 服务就会把搜索引擎查到的结果展示出来,用 Go 实现只要一个文件。

main.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1package main
 2
 3import ...
 4
 5func main() {
 6  http.HandleFunc("/search", func(w http.ResponseWriter, req *http.Request) {
 7    q := req.URL.Query().Get("q")
 8        fmt.Fprintf(w, `<iframe width="100%%" height="98%%" scrolling="auto" frameborder="0" src="https://cn.bing.com/search?q=%v">`, q)
 9  })
10  log.Fatal(http.ListenAndServe(":8081", nil))
11}

接着把服务跑起来:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1go run main.go

在浏览器中访问 http://localhost:8081/search?q=golang

很简单是不是?但这里的问题在于我们把 https://cn.bing.com 写死在了代码中,如果要切换搜索引擎就得重新编译程序,真的是费时费力。 这时候我们就需要将配置解耦到配置文件中了。

配置文件

我们先在本地建一个配置文件 go-app.yml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1app:
2  search_url: https://cn.bing.com/search?q=%v

然后通过 viper 这个比较流行的配置库加载这个配置。

conf/conf.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1package conf
 2
 3import ...
 4
 5func init() {
 6  viper.SetConfigName("go-app")
 7  viper.AddConfigPath(os.ExpandEnv(`$GOPATH\src\github.com\GotaX\config-server-demo`))
 8  viper.SetConfigType("yaml")
 9  if err := viper.ReadInConfig(); err != nil {
10    log.Fatal("Fail to load config", err)
11  }
12}

现在我们就把搜索引擎的地址解耦到配置文件中去了。

main.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1package main
 2
 3import ...
 4
 5func main() {
 6  http.HandleFunc("/search", func(w http.ResponseWriter, req *http.Request) {
 7    q := req.URL.Query().Get("q")
 8        src := fmt.Sprintf(viper.GetString("app.search_url"), q)
 9    fmt.Fprintf(w, `<iframe width="100%%" height="98%%" scrolling="auto" frameborder="0" src="%v">`, src)
10  })
11  log.Fatal(http.ListenAndServe(":8081", nil))
12}

转移配置到云端

接下来我们将配置文件从本地转移到 Git 中,处于方便我就直接放在当前仓库的 config 分支中了。

地址为: https://github.com/GotaX/config-server-demo/tree/config

启动配置中心

配置文件上传完毕,我们再新开一个 config-server 空分支搭建配置中心。

首先到 https://start.spring.io/ 页面新建一个 Java + Gradle 的 Spring Boot 工程,依赖项选 Config Server。

点击 "Generate Project" 将下载压缩包, 并解压。

修改 Application.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1package com.example.demo;
 2
 3import org.springframework.boot.SpringApplication;
 4import org.springframework.boot.autoconfigure.SpringBootApplication;
 5import org.springframework.cloud.config.server.EnableConfigServer;
 6
 7@EnableConfigServer  // 添加这行
 8@SpringBootApplication
 9public class DemoApplication {
10  public static void main(String[] args) {
11    SpringApplication.run(DemoApplication.class, args);
12  }
13}

修改 application.yml, 填入我们存放配置文件的仓库地址。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1spring.cloud.config.server.git.uri: https://github.com/GotaX/config-server-demo.git

在工程根目录启动 config server。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1gradle bootrun

访问 http://localhost:8080/config/go-app-default.yml 查看配置。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1app:
2  search_url: https://cn.bing.com/search?q=%v

这样我们的配置中心就启动完毕了。

在 Go 应用中读取配置

最后就是在应用中使用 Spring Cloud Config Server 中的配置了。如果是基于 Spring Boot 的应用可以直接使用 spring-cloud-config-client 加载配置。在 Go 中就需要稍微写点代码了,不过并不多。

我们先在 config.go 中添加一个 loadRemote() 函数,用来从配置中心读取配置:

conf/conf.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1// ...
 2const (
 3  kAppName       = "APP_NAME"
 4  kConfigServer  = "CONFIG_SERVER"
 5  kConfigLabel   = "CONFIG_LABEL"
 6  kConfigProfile = "CONFIG_PROFILE"
 7  kConfigType    = "CONFIG_TYPE"
 8)
 9
10func loadRemoteConfig() (err error) {
11    // 组装配置文件地址: http://localhost:8080/config/go-app-default.yaml
12  confAddr := fmt.Sprintf("%v/%v/%v-%v.yml",
13    viper.Get(kConfigServer), viper.Get(kConfigLabel),
14    viper.Get(kAppName), viper.Get(kConfigProfile))
15  resp, err := http.Get(confAddr)
16  if err != nil {
17    return
18  }
19  defer resp.Body.Close()
20
21    // 设置配置文件格式: yaml
22  viper.SetConfigType(viper.GetString(kConfigType))
23    // 载入配置文件
24  if err = viper.ReadConfig(resp.Body); err != nil {
25    return
26  }
27  log.Println("Load config from: ", confAddr)
28  return
29}

当然,我们需要知道配置中心的入口,因此还需一个 initDefault() 函数来初始化这些配置:

conf/conf.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1func initDefault() {
2  viper.SetDefault(kAppName, "go-app")
3  viper.SetDefault(kConfigServer, "http://localhost:8080")
4  viper.SetDefault(kConfigLabel, "config")
5  viper.SetDefault(kConfigProfile, "default")
6  viper.SetDefault(kConfigType, "yaml")
7}

现在我们的 init() 函数变成了这样:

conf/conf.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1func init() {
2  viper.AutomaticEnv()
3  initDefault()
4
5  if err := loadRemoteConfig(); err != nil {
6    log.Fatal("Fail to load config", err)
7  }
8}

其中的 viper.AutomaticEnv() 可以让我们通过环境变量修改任意配置,因此 initDefault()中的配置也不是写死在代码中的了。其中比较常见的用法是通过 CONFIG_PROFILE=prod 环境变量来切换 profile。

最后我们希望 viper 仅在 conf 包中出现, 而对外隐藏我们加载配置的具体实现。 因此我们将配置读到结构体中再对外提供:

conf/conf.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1var App AppConfig
 2
 3type AppConfig struct {
 4  SearchUrl string `mapstructure:"search_url"`
 5}
 6
 7func init() {
 8  // ...
 9  if err := sub("app", &App); err != nil {
10    log.Fatal("Fail to parse config", err)
11  }
12}
13
14func sub(key string, value interface{}) error {
15  sub := viper.Sub(key)
16  sub.AutomaticEnv()
17  sub.SetEnvPrefix(key)
18  return sub.Unmarshal(value)
19}

这时我们就可以从 main.go 中去掉 viper.Get() 调用了:

main.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1import ...
 2
 3func main() {
 4  http.HandleFunc("/search", func(w http.ResponseWriter, req *http.Request) {
 5    q := req.URL.Query().Get("q")
 6    src := fmt.Sprintf(conf.App.SearchUrl, q)
 7    fmt.Fprintf(w, `<iframe width="100%%" height="98%%" scrolling="auto" frameborder="0" src="%v">`, src)
 8  })
 9  log.Fatal(http.ListenAndServe(":8081", nil))
10}

总结

我们通过 Git + Spring Could Config Server + Viper + 少量 Go 代码, 实现了基于配置中心的配置管理及使用

我们甚至可以在 Go 中使用类似于 Spring Boot 的 Profile 管理, 对比下:

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

完整的代码可以参考 https://github.com/GotaX/config-server-demo 下的 3 个分支:

  • config: 配置文件
  • config-server: 配置中心
  • app: Go 应用

当然, 目前这种使用方式还比较简陋, 还有很多可以改进的地方, 比如:

  • 结合 Spring Cloud Bus 实现配置的实时推送
  • 结合 Spring Cloud Eureka 实现配置服务器的高可用
  • 监听 SIGINT 和 SIGTERM 实现 Go 应用优雅退出

版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Go每日一库之6:viper
上一篇文章介绍 cobra 的时候提到了 viper,今天我们就来介绍一下这个库。
luckpunk
2023/09/13
3510
viper 源码分析
Viper是Go应用程序的完整配置解决方案,包括12-Factor应用程序。它旨在在应用程序中工作,并可以处理所有类型的配置需求和格式。它支持:
golangLeetcode
2022/08/02
1K0
Go viper 配置文件读取工具
viper 提供默认 Viper对象, 可直接使用。 也通过 New 方法创建自定义Viper
copy_left
2020/08/11
1.8K0
基于 Go 语言开发在线论坛增补篇:通过 Viper 读取配置文件并实现热加载
之前我们在论坛项目中使用了单例模式全局加载配置文件,这样做有一个弊端,就是不支持热加载,每次修改配置文件,需要重启应用,不太灵活,所以这篇教程我们引入 Viper 重构配置读取逻辑,并支持配置文件的热加载(所谓热加载指的是配置文件修改后无需重启应用即可生效)。
学院君
2020/05/07
2K0
go库介绍:Golang中的Viper库
在Golang(Go)的开发中,配置管理是一个不可或缺的部分。一个优雅的配置管理方案不仅能够简化应用程序的配置处理流程,还能提高应用程序的灵活性和可维护性。在这方面,Viper库无疑是Go生态系统中的一颗璀璨明珠。本文将详细介绍Viper库及其使用场景,并通过具体示例展示其强大功能。
每周聚焦
2024/11/08
4220
go库介绍:Golang中的Viper库
go语言中的配置管理神器 --viper 一
Viper 是 Go 应用程序的完整配置解决方案,包括 12-Factor 应用程序。它旨在在应用程序中工作,并可以处理所有类型的配置需求和格式。它支持:
onenewcode
2024/02/02
3510
Go语言WEB框架之Gin
文档:https://gin-gonic.com/zh-cn/docs/quickstart/
码客说
2022/10/05
1.2K0
每日一库:使用Viper处理Go应用程序的配置
在开发Go应用程序时,处理配置是一个常见的需求。配置可能来自于配置文件、环境变量、命令行参数等等。Viper是一个强大的库,可以帮助我们处理这些配置。
孟斯特
2023/10/19
3060
每日一库:使用Viper处理Go应用程序的配置
Golang 语言怎么使用 Viper 管理配置信息?
Viper 是适用于 Go 应用程序(包括 Twelve-Factor App)的完整配置解决方案。它被设计为在应用程序中工作,并且可以处理所有类型的配置需求和格式。它支持:
frank.
2021/01/08
6.4K0
Golang生态:使用viper管理配置
通过配置,我们可以动态地改变程序的行为,常用的方式包括配置文件,命令行参数,环境变量等。我原来一直很欣赏ssh的配置管理方式:
王录华
2019/11/19
5K1
使用Viper处理Go应用程序的配置
在开发Go应用程序时,处理配置是一个常见的需求。配置可能来自于配置文件、环境变量、命令行参数等等。Viper是一个强大的库,可以帮助我们处理这些配置。
孟斯特
2023/09/24
2730
使用Viper处理Go应用程序的配置
Go之Viper
Viper是适用于Go应用程序的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式;
iginkgo18
2021/04/23
6.5K1
Go语言微服务框架 - 2.实现加载静态配置文件
首先,我们要正确地认识到配置文件的重要性:在程序交付后,变更代码的成本很大;相对而言,变更配置文件的成本就比较小。但有的同学又走了另一个极端,也就是将大量的逻辑放入到配置文件中,导致配置文件膨胀,本质上就是将部分本应在代码中维护的内容转移到了配置文件,导致配置文件也很难维护。
junedayday
2021/09/24
1.3K0
知识分享之Golang——和我一起搭建一个快速开发框架(二)
知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。
cn華少
2021/12/28
3220
知识分享之Golang——和我一起搭建一个快速开发框架(二)
Go:配置文件解析库 spf13/viper简介(Go应用程序的完整配置解决方案)
在我们开发过程中,像数据库信息、邮件配置和其他的第三方服务密钥等这些固定的信息都会写在配置文件中,而配置文件又有多种表现形式和格式,有 JSON, TOML, YAML各种格式,而且测试环境,开发环境和生产环境用的配置文件也不是同一份。
Freedom123
2024/03/29
6080
gin 读取配置文件
需求:对于配置文件不要直接在代码中进行定义和使用,而是单独放到配置文件的目录中,以便区分环境使用不同的配置。 分离前代码: database, err := sqlx.Open("mysql", "root:XXXX@tcp(127.0.0.1:3306)/test") 修改为读取配置文件 创建文件 config/main.toml app_name = "awesome web" # possible values: DEBUG, INFO, WARNING, ERROR, FATAL log_l
句小芒
2022/12/29
1K0
Viper,一个Go语言配置管理神器!
文章链接:https://cloud.tencent.com/developer/article/2466037
南山竹
2024/11/16
990
Viper,一个Go语言配置管理神器!
Golang依赖注入提升开发效率!
导语 | 依赖注入并不是java独有的,也不是web框架独有的,本文用通俗易懂的语言讲解什么是依赖注入,为什么需要依赖注入,以及go语言如何使用依赖注入来提升开发效率。 一、什么依赖注入 依赖注入(Dependency Injection)也叫DI是软件工程的一种设计模式。 二、为什么需要依赖注入 比如我们使用go要开发一个http api服务,这个服务启动需要 读取命令行 读取配置 连接数据库 连接redis 设置回调函数 监听端口 这个服务关闭需要 关闭端口 关闭redis 关闭mysql 你的
腾讯云开发者
2022/08/26
1.2K0
Golang依赖注入提升开发效率!
Go中级之手把手教你开发一个简易的个人博客网站(二)项目配置独立化
此文是个人学习归纳的记录,腾讯云独家发布,未经允许,严禁转载,如有不对, 还望斧正, 感谢!
言志志
2023/12/24
8661
Go中级之手把手教你开发一个简易的个人博客网站(二)项目配置独立化
【Go API 开发实战 7】基础 3:记录和管理 API 日志
apiserver 所采用的日志包 lexkong/log 是笔者根据开发经验,并调研 GitHub 上的 开源log 包后封装的一个日志包,也是笔者所在项目使用的日志包。它参考华为 paas-lager,做了一些便捷性的改动,功能完全一样,只不过更为便捷。相较于 Go 的其他日志包,该日志包有如下特点:
腾讯技术工程官方号
2019/05/16
1.4K0
【Go API 开发实战 7】基础 3:记录和管理 API 日志
相关推荐
Go每日一库之6:viper
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验