【Go API 开发实战 6】基础 2:配置文件读取
配置文件读取
本节核心内容
介绍 apiserver 所采用的配置解决方案
介绍如何配置 apiserver 并读取其配置,以及配置的高级用法
本小节源码下载路径:demo02
可先下载源码到本地,结合源码理解后续内容,边学边练。
本小节的代码是基于 demo01 来开发的。
Viper 简介
Viper 是国外大神 spf13 编写的开源配置解决方案,具有如下特性:
设置默认值
可以读取如下格式的配置文件:JSON、TOML、YAML、HCL
监控配置文件改动,并热加载配置文件
从环境变量读取配置
从远程配置中心读取配置(etcd/consul),并监控变动
从命令行 flag 读取配置
从缓存中读取配置
支持直接设置配置项的值
Viper 配置读取顺序:
viper.Set()
所设置的值命令行 flag
环境变量
配置文件
配置中心:etcd/consul
默认值
从上面这些特性来看,Viper 毫无疑问是非常强大的,而且 Viper 用起来也很方便,在初始化配置文件后,读取配置只需要调用viper.GetString()
、viper.GetInt()
和 viper.GetBool()
等函数即可。
Viper 也可以非常方便地读取多个层级的配置,比如这样一个 YAML 格式的配置:
common: database: name: test host: 127.0.0.1
如果要读取 host 配置,执行viper.GetString("common.database.host")
即可。
apiserver 采用 YAML 格式的配置文件,采用 YAML 格式,是因为 YAML 表达的格式更丰富,可读性更强。
初始化配置
主函数中增加配置初始化入口
package mainimport ( "errors"
"log"
"net/http"
"time"
"apiserver/config"
... "github.com/spf13/pflag")var (
cfg = pflag.StringP("config", "c", "", "apiserver config file path.")
)func main() {
pflag.Parse() // init config
if err := config.Init(*cfg); err != nil { panic(err)
} // Create the Gin engine.
g := gin.New()
...
}
在main
函数中增加了config.Init(*cfg)
调用,用来初始化配置,cfg
变量值从命令行 flag 传入,可以传值,比如./apiserver -c config.yaml
,也可以为空,如果为空会默认读取conf/config.yaml
。
解析配置
main
函数通过 config.Init 函数来解析并 watch 配置文件(函数路径:config/config.go),config.go 源码为:
package configimport ( "log""strings"
"github.com/fsnotify/fsnotify""github.com/spf13/viper")type Config struct { Name string}func Init(cfg string) error { c := Config { Name: cfg, } // 初始化配置文件if err := c.initConfig(); err != nil { return err } // 监控配置文件变化并热加载程序 c.watchConfig() return nil}func (c *Config) initConfig() error { if c.Name != "" { viper.SetConfigFile(c.Name) // 如果指定了配置文件,则解析指定的配置文件 } else { viper.AddConfigPath("conf") // 如果没有指定配置文件,则解析默认的配置文件 viper.SetConfigName("config") } viper.SetConfigType("yaml") // 设置配置文件格式为YAML viper.AutomaticEnv() // 读取匹配的环境变量 viper.SetEnvPrefix("APISERVER") // 读取环境变量的前缀为APISERVER replacer := strings.NewReplacer(".", "_") viper.SetEnvKeyReplacer(replacer) if err := viper.ReadInConfig(); err != nil { // viper解析配置文件return err } return nil}// 监控配置文件变化并热加载程序func (c *Config) watchConfig() { viper.WatchConfig() viper.OnConfigChange(func(e fsnotify.Event) { log.Printf("Config file changed: %s", e.Name) })}
config.Init()
通过 initConfig()
函数来解析配置文件,通过 watchConfig()
函数来 watch 配置文件,两个函数解析如下:
func (c *Config) initConfig() error
设置并解析配置文件。如果指定了配置文件
*cfg
不为空,则解析指定的配置文件,否则解析默认的配置文件conf/config.yaml
。通过指定配置文件可以很方便地连接不同的环境(开发环境、测试环境)并加载不同的配置,方便开发和测试。通过如下设置
viper.AutomaticEnv() viper.SetEnvPrefix("APISERVER") replacer := strings.NewReplacer(".", "_")
可以使程序读取环境变量,具体效果稍后会演示。
config.Init
函数中的viper.ReadInConfig()
函数最终会调用 Viper 解析配置文件。func (c *Config) watchConfig()
通过该函数的 viper 设置,可以使 viper 监控配置文件变更,如有变更则热更新程序。所谓热更新是指:可以不重启 API 进程,使 API 加载最新配置项的值。
配置并读取配置
API 服务器端口号可能经常需要变更,API 服务器启动时间可能会变长,自检程序超时时间需要是可配的(通过设置次数),另外 API 需要根据不同的开发模式(开发、生产、测试)来匹配不同的行为。开发模式也需要是可配置的,这些都可以在配置文件中配置,新建配置文件conf/config.yaml
(默认配置文件名字固定为 config.yaml
),config.yaml
的内容为:
runmode: debug # 开发模式, debug, release, testaddr: :6663 # HTTP绑定端口name: apiserver # API Server的名字url: http://127.0.0.1:6663 # pingServer函数请求的API服务器的ip:portmax_ping_count: 10 # pingServer函数尝试的次数
在main
函数中将相应的配置改成从配置文件读取,需要替换的配置见下图中红框部分。
替换后,代码为:
另外根据配置文件的 runmode
调用 gin.SetMode
来设置 gin 的运行模式:
func main() { pflag.Parse() // init configif err := config.Init(*cfg); err != nil { panic(err) }
// Set gin mode. gin.SetMode(viper.GetString("runmode"))
....
}
gin 有 3 种运行模式:debug、release 和 test,其中 debug 模式会打印很多 debug 信息。
编译并运行
下载 apiserver_demos 源码包(如前面已经下载过,请忽略此步骤)
$ git clone https://github.com/lexkong/apiserver_demos
将
apiserver_demos/demo02
复制为$GOPATH/src/apiserver
$ cp -a apiserver_demos/demo02/ $GOPATH/src/apiserver
在 apiserver 目录下编译源码
$ cd $GOPATH/src/apiserver$ gofmt -w .$ go tool vet .$ go build -v .
修改conf/config.yaml
将端口修改为8888
,并启动 apiserver修改后配置文件为:
runmode: debug # 开发模式, debug, release, testaddr: :8888 # HTTP绑定端口name: apiserver # API Server的名字url: http://127.0.0.1:8888 # pingServer函数请求的API服务器的ip:portmax_ping_count: 10 # pingServer函数try的次数
修改后启动 apiserver:
可以看到,启动 apiserver 后端口为配置文件中指定的端口。
Viper 高级用法
从环境变量读取配置
在本节第一部分介绍过,Viper 可以从环境变量读取配置,这是个非常有用的功能。现在越来越多的程序是运行在 Kubernetes 容器集群中的,在 API 服务器迁移到容器集群时,可以直接通过 Kubernetes 来设置环境变量,然后程序读取设置的环境变量来配置 API 服务器。读者不需要了解如何通过 Kubernetes 设置环境变量,只需要知道 Viper 可以直接读取环境变量即可。
例如,通过环境变量来设置 API Server 端口:
$ export APISERVER_ADDR=:7777$ export APISERVER_URL=http://127.0.0.1:7777$ ./apiserver [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /sd/health --> apiserver/handler/sd.HealthCheck (5 handlers)[GIN-debug] GET /sd/disk --> apiserver/handler/sd.DiskCheck (5 handlers)[GIN-debug] GET /sd/cpu --> apiserver/handler/sd.CPUCheck (5 handlers)[GIN-debug] GET /sd/ram --> apiserver/handler/sd.RAMCheck (5 handlers)Start to listening the incoming requests on http address: :7777The router has been deployed successfully.
从输出可以看到,设置APISERVER_ADDR=:7777
和 APISERVER_URL=http://127.0.0.1:7777
后,启动 apiserver,API 服务器的端口变为7777
。
环境变量名格式为config/config.go
文件中 viper.SetEnvPrefix("APISERVER")
所设置的前缀和配置名称大写,
二者用 _
连接,比如APISERVER_RUNMODE
。如果配置项是嵌套的,情况可类推,比如
....max_ping_count: 10 # pingServer函数try的次数db: name: db_apiserver
对应的环境变量名为APISERVER_DB_NAME
。
热更新
在 main
函数中添加如下测试代码(for {}
部分,循环打印runmode
的值):
import ( "fmt" ....)var ( cfg = pflag.StringP("config", "c", "", "apiserver config file path."))func main() { pflag.Parse() // init configif err := config.Init(*cfg); err != nil { panic(err) } for { fmt.Println(viper.GetString("runmode")) time.Sleep(4*time.Second) } ....}
编译并启动apiserver
后,修改配置文件中 runmode
为 test
,可以看到runmode
的值从debug
变为test
:
小结
本小节展示了如何用强大的配置管理工具 Viper 来解析配置文件并读取配置,还演示了 Viper 的高级用法。
本系列文章转载自公众号:腾讯游戏存储与计算技术 微信号: game_infra
【Go API 开发实战 6】基础 2:配置文件读取相关推荐
- 《ASP.NET Core 与 RESTful API 开发实战》-- (第10章)-- 读书笔记
第 10 章 部署 10.1 部署到 IIS ASP.NET Core 应用程序支持部署到 IIS 中,之后它将作为应用程序的反向代理服务器和负载均衡器,向应用程序中转传入的 HTTP 请求 默认情况 ...
- 名师讲坛——Java Web开发实战经典基础篇(JSP、Servlet、Struts、Ajax)
[书名]<名师讲坛--Java Web开发实战经典基础篇(JSP.Servlet.Struts.Ajax)> [作者]李兴华.王月清 [ISBN]9787302231585 }:YKf: ...
- 名师讲坛—Java Web开发实战经典基础篇(JSP、Servlet、Struts、Ajax)
名师讲坛-Java Web开发实战经典基础篇(JSP.Servlet.Struts.Ajax) 基本信息 作者: 李兴华 王月清 出版社:清华大学出版社 ISBN:9787302231585 ...
- android趣味项目,AndroidStudio项目开发实战——从基础入门到趣味开发
AndroidStudio项目开发实战--从基础入门到趣味开发 编辑 锁定 讨论 上传视频 <AndroidStudio项目开发实战--从基础入门到趣味开发>是2020年3月电子工业出版社 ...
- 启动服务错误5拒绝访问_【Go API 开发实战 5】基础1:启动一个最简单的 RESTful API 服务器...
启动一个最简单的 RESTful API 服务器 本节核心内容 启动一个最简单的 RESTful API 服务器 设置 HTTP Header API 服务器健康检查和状态查询 编译并测试 API 本 ...
- 【Go API 开发实战 5】基础1:启动一个最简单的 RESTful API 服务器
本节核心内容 启动一个最简单的 RESTful API 服务器 设置 HTTP Header API 服务器健康检查和状态查询 编译并测试 API 本小节源码下载路径:demo01 可先下载源码到本地 ...
- 【Go API 开发实战】Go API 开发实战教程简介(1-7)
教程介绍 现代软件架构已经逐渐从单体架构转向微服务架构,在微服务架构中服务间通信采用轻量级通信机制.对于轻量级通信的协议而言,通常基于 HTTP 和 RPC ,能让服务间的通信变的标准化并且无状态化. ...
- 【Go API 开发实战 3】API 流程和代码结构
API 流程和代码结构 为了使读者在开始实战之前对 API 开发有个整体的了解,这里选择了两个流程来介绍: HTTP API 服务器启动流程 HTTP 请求处理流程 本小节也提前给出了程序代码结构图, ...
- 【Go API 开发实战 2】RESTful API 介绍
RESTful API 介绍 API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数或者接口,目的是提供应用程序与开发人员基于某软件或硬件得 ...
最新文章
- OpenCV中的立体图像创建深度图
- centos6.5环境下zookeeper-3.4.6集群环境部署及单机部署详解
- Python time strptime()方法 时间操作
- 大剑无锋之SQL求用户最近的登录时间【面试推荐】
- 如何借助Kubernetes实现持续的业务敏捷性
- CSSSCSS的学习笔记
- it专员职责_【IT专员工作内容|工作职责|IT专员做什么】-看准网
- css画饼状图圆形,CSS样式圆形饼图百分比
- 基于单片机的电子密码锁设计
- SOUI中几个view视图控件的基本使用
- C# 基础 (3) 垃圾回收机制(Garbage Collector)
- halcon轮廓擦除_Halcon中轮廓分割segment
- 如何将静态图片制作成闪图效果?
- 冬瓜子 , 初来乍到,请多关照!
- 如何创建unity的菜单栏和窗口
- 回忆旧时读叶芝的WHEN YOU ARE OLD
- VUE 首屏加载时间优化
- thingsboard 编译及分析
- 2021年质量员-装饰方向-岗位技能(质量员)最新解析及质量员-装饰方向-岗位技能(质量员)试题及解析
- android word分页,控制分页
热门文章
- 微积分31--微分学在几何上的应用
- http://jingyan.baidu.com/article/dca1fa6fa07000f1a44052f6.html
- Validate + Boostrap tooltip 表单验证示例
- android WebView 显示网页
- 在 ASP.NET 使用 jQuery BlockUI 插件
- HDU - 5790 Prefix(主席树+字典树)
- 中石油训练赛 - Faulhaber’s Triangle(打表)
- c语言指针字符串逆序存放,C语言指针实现字符串的反转
- amd处理器更新zen4服务器芯片,AMD更新CPU、GPU路线图:Zen4架构与硬件光追可期
- 11.IDA-this指针