网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
kratos配置
简介
微服务或者说云原生应用的配置最佳实践是将配置文件和应用代码分开管理——不将配置文件放入代码仓库,也不打包进容器镜像,而是在服务运行时,把配置文件挂载进去或者直接从配置中心加载。Kratos的config组件就是用来帮助应用从各种配置源加载配置。
设计理念
支持多种配置源
Kratos定义了标准化的Source和Watcher接口来适配各种配置源。
package config
// KeyValue is config key value.
type KeyValue struct {
Key string
Value []byte
Format string
}
// Source is config source.
type Source interface {
Load() ([]*KeyValue, error)
Watch() (Watcher, error)
}
// Watcher watches a source for changes.
type Watcher interface {
Next() ([]*KeyValue, error)
Stop() error
}
另外,在contrib/config下面,提供了如下的配置中心的适配供使用:
如果上述的配置加载方式无法涵盖您的环境,您也可以通过实现接口来适配您自己的配置加载方式。
支持多种配置格式
配置组件复用了encoding
中的反序列化逻辑作为配置解析使用。
框架将根据配置文件类型匹配对应的Codec,进行配置文件的解析。
您也可以通过实现Codec并用encoding.RegisterCodec
方法,将它注册进去,来解析其它格式的配置文件。
配置文件类型的提取,根据配置源具体实现不同而略有区别,内置的file是把文件后缀作为文件类型的,其它配置源插件的具体逻辑请参考对应的文档。
默认支持以下格式的解析:
- json
- proto
- xml
- yaml
热更新
Kratos的config组件支持配置的热更新,可以使用配置中心配合config的热更新功能,在服务不重新发布/不停机/不重启的情况下,在线更新服务的配置,修改服务的一些行为。
配置合并
在config组件中,所有的配置源中的配置(文件)将被逐个读出,分别解析成map,并合并到一个map中去。因此在加载完毕后,不需要再理会配置的文件名,不用文件名来进行查找,而是用内容中的结构来对配置的值进行索引即可。设计和编写配置文件时,请注意各个配置文件中,根层级的key不要重复,否则可能会被覆盖。
配置文件的各层级将分别合并,在key冲突时会发生覆盖,而具体的覆盖顺序,会由配置源实现中的读取顺序决定,因此这里重新提醒一下,各个配置文件中,根层级的key不要重复,也不要依赖这个覆盖的特性,从根本上避免不同配置文件的内容互相覆盖造成问题
API概览
New
New方法使用选项创建一个Config
func New(opts ...Option) Config
Option
可以通过Option注入自定义的组件, WithSource这个是必定会用到,其他一般不怎么会用到。
- WithDecoder: 自定义解码器
- WithLogger: 注入一个日志组件,该接口已经被废弃,可以使用全局日志组件替代
- WithResolver: 自定义占位符处理器
- WithSource: 添加配置源
func WithDecoder(d Decoder) Option
func WithLogger(l log.Logger) Option
func WithResolver(r Resolver) Option
func WithSource(s ...Source) Option
Config
type Config interface {
Load() error
Scan(v interface{}) error
Value(key string) Value
Watch(key string, o Observer) error
Close() error
}
- Load: 加载配置源
- Scan: 将配置反射到结构体中
- Value: 获取配置的值
- Watch: 监听配置更新
- Close: 关闭所有watch
File
初始化配置源
path := "config.yaml"
// 初始化配置源
c := config.New(
config.WithSource(
file.NewSource(path),
),
)
读取配置
读取配置可以使用Scan来反射到结构体也可以使用Value获取指定键值
使用Scan
var v struct {
Service struct {
Name string `json:"name"`
Version string `json:"version"`
} `json:"service"`
}
// Unmarshal the config to struct
if err := c.Scan(&v); err != nil {
panic(err)
}
如果通过Scan方法来读取, 修改文件内容后结构体的也会跟着更改
for {
version, err := c.Value("service.version").String()
if err != nil {
panic(err)
}
log.Printf("version: %s", version)
time.Sleep(time.Second)
}
// 2023/05/07 11:51:47 version: v1.0.0
// 2023/05/07 11:51:48 version: v1.0.011
使用Value
name, err := c.Value("service.name").String()
if err != nil {
panic(err)
}
log.Printf("service: %s", name)
监听配置变更
通过.Watch
方法,可以监听配置中某个字段的变更,在本地或远端的配置中心有配置文件变更时,执行回调函数进行自定义的处理
// watch key
if err := c.Watch("service.name", func(key string, value config.Value) {
log.Printf("config changed: %s = %v\n", key, value)
}); err != nil {
panic(err)
}
env
如果有配置需要从环境变量读取可以配置env.NewSource
c := config.New(
config.WithSource(
// 添加前缀为 KRATOS\_ 的环境变量,不需要的话也可以设为空字符串
env.NewSource("KRATOS\_"),
// 添加配置文件
file.NewSource(path),
))
// 加载配置源:
if err := c.Load(); err != nil {
log.Fatal(err)
}
// 获取环境变量 KRATOS\_PORT 的值,这里用去掉前缀的名称进行读取
port, err := c.Value("PORT").String()
除了上面使用Value方法直接读的方式,也可以在配置文件内容里使用占位符来把环境变量中的值渲染进去:
service:
name: "kratos\_app"
http:
server:
# 使用 service.name 的值
name: "${service.name}"
# 使用环境变量 PORT 替换,若不存在,使用默认值 8080
port: "${PORT:8080}"
# 使用环境变量 TIMEOUT 替换,无默认值
timeout: "$TIMEOUT"
consul
部署consul
这里我们使用docker-compose部署
version: "3.0"
services:
consul:
container_name: consul
image: consul
restart: always
ports:
- 8500:8500
command: ["consul","agent","-server","-bootstrap","-data-dir","/consul","-ui","-bind","127.0.0.1","-client","0.0.0.0"]
添加配置
docker exec -it consul consul kv put http/server/port 8000
代码实现
package main
import (
"github.com/go-kratos/kratos/contrib/config/consul/v2"
"github.com/go-kratos/kratos/v2/config"
"github.com/hashicorp/consul/api"
"log"
)
![img](https://img-blog.csdnimg.cn/img_convert/57c66f3ae981b5e06868941882b7e772.png)
![img](https://img-blog.csdnimg.cn/img_convert/62bded7cdc37a41a54e2fb7d94a272db.png)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
nfig"
"github.com/hashicorp/consul/api"
"log"
)
[外链图片转存中...(img-9W8qpJvG-1715480888020)]
[外链图片转存中...(img-h7z0PZp6-1715480888020)]
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**