為什么需要配置中心
- 添加配置
- 你現在的用戶服務有10個部署實例,那么添加配置項你得去十個地方修改配置文件還得重新啟動等
- 即使go的viper能完成修改配置文件自動生效,那么你得考慮其他語言是否也能做到這點,其他的服務是否也一定會使用viper
- 修改配置
- 大量的服務可能會使用同一個配置,比如我要更好jwt的secrect,這么多實例需要統一更新
- 開發,測試,uat以及生產環境如何隔離
配置中心可以幫助我們解決以上問題,不需要手動更改每個實例的配置文件,並且能夠快速方便的讀取到配置文件在線更新。
安裝
docker run --name nacos-standalone -e MODE=standalone -e JVM_XMS=512m -e JVM_XMX=512m -e JVM_XMN=256m -p 8848:8848 -d nacos/nacos-server:latest
訪問需要http://192.168.0.102:8848/nacos/index.html,不能不帶后面的nacos/index.html,賬號和密碼為nacos和nacos
配置
按服務創建命名空間
選擇好命名空間后,創建配置文件
將自己的配置按圖示填寫
同理把user-api的也發布了
讀取配置
user-service
改造之前的配置結構體,添加json的tag,方便后面的解析
type DBConfig struct {
Username string `mapstructure:"username" json:"username"`
Password string `mapstructure:"password" json:"password"`
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
Dbname string `mapstructure:"dbname" json:"dbname"`
DefaultStringSize int `mapstructure:"defaultStringSize" json:"defaultStringSize"`
MaxIdleConn int `mapstructure:"maxIdleConn" json:"maxIdleConn"`
MaxOpenConn int `mapstructure:"maxOpenConn" json:"maxOpenConn"`
}
type LogConfig struct {
LogPath string `mapstructure:"logPath" json:"logPath"`
MaxSize int `mapstructure:"maxSize" json:"maxSize"`
MaxBackups int `mapstructure:"maxBackups" json:"maxBackups"`
MaxAge int `mapstructure:"maxAge" json:"maxAge"`
Level string `mapstructure:"level" json:"level"`
}
type ServiceConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
Name string `mapstructure:"name" json:"name"`
Id string `mapstructure:"id" json:"id"`
Tags string `mapstructure:"tags" json:"tags"`
}
type ConsulConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
}
type NacosConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
DataId string `mapstructure:"dataId"`
Namespace string `mapstructure:"namespace"`
Group string `mapstructure:"group"`
Timeout int `mapstructure:"timeout"`
LogLevel string `mapstructure:"logLevel"`
LogPath string `mapstructure:"logPath"`
CachePath string `mapstructure:"cachePath"`
}
單獨定義一個nacos的配置文件
var (
DB *gorm.DB
Config *ServerTO
NacosConfig *models.NacosConfig
)
type ServerTO struct {
DBConfig *models.DBConfig `mapstructure:"db" json:"db"`
Log *models.LogConfig `mapstructure:"log" json:"log"`
Service *models.ServiceConfig `mapstructure:"service" json:"service"`
Consul *models.ConsulConfig `mapstructure:"consul" json:"consul"`
}
func init() {
Config = &ServerTO{
DBConfig: &models.DBConfig{},
Log: &models.LogConfig{},
Service: &models.ServiceConfig{},
Consul: &models.ConsulConfig{},
}
NacosConfig = &models.NacosConfig{}
}
修改配置文件
nacos:
host: xx.xx.xx.xx
port: xxx
DataId: xxx
Namespace: xxxxxxxxxxxx
Group: xx
Timeout: xxx
LogLevel: xxx
cachePath: xx/xx/xx
logPath: xx/xx/xx
修改讀取配置文件的函數
func InitConfig() {
vp := viper.New()
vp.AddConfigPath("configs/")
vp.SetConfigName("config")
vp.SetConfigType("yml")
err := vp.ReadInConfig()
if err != nil {
panic(any(fmt.Sprintf("Read config failed:%v", err)))
}
err = vp.UnmarshalKey("nacos", &global.NacosConfig)
if err != nil {
panic(any(fmt.Sprintf("Read nacos failed:%v", err)))
}
sc := []constant.ServerConfig{
{
IpAddr: global.NacosConfig.Host,
Port: uint64(global.NacosConfig.Port),
ContextPath: "/nacos",
},
}
cc := constant.ClientConfig{
NamespaceId: global.NacosConfig.Namespace,
TimeoutMs: uint64(global.NacosConfig.Timeout),
NotLoadCacheAtStart: true,
LogDir: global.NacosConfig.LogPath,
CacheDir: global.NacosConfig.CachePath,
LogLevel: global.NacosConfig.LogLevel,
}
configClient, err := clients.CreateConfigClient(map[string]interface{}{
"serverConfigs": sc, "clientConfig": cc,
})
if err != nil {
panic(any(err))
}
content, err := configClient.GetConfig(vo.ConfigParam{
DataId: global.NacosConfig.DataId,
Group: global.NacosConfig.Group,
})
if err != nil {
panic(any(err))
}
err = json.Unmarshal([]byte(content), &global.Config)
if err != nil {
panic(any(fmt.Sprintf("Read config failed:%v", err)))
}
}
另外,需要將nacos中的配置文件由yaml轉為json,可以通過https://www.json2yaml.com/convert-yaml-to-json進行轉換。修改完畢之后如下所示
user-api
修改global文件,除nacos之外的配置結構體添加json的tag
package global
import user "imooc/mxshop-api/api/user/v0"
var (
Config *ServerConfig
Nacos *NacosConfig
UserClient user.UserServiceClient
)
type LogConfig struct {
LogPath string `mapstructure:"logPath" json:"logPath"`
MaxSize int `mapstructure:"maxSize" json:"maxSize"`
MaxBackups int `mapstructure:"maxBackups" json:"maxBackups"`
MaxAge int `mapstructure:"maxAge" json:"maxAge"`
Level string `mapstructure:"level" json:"level"`
}
type ServiceConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
Name string `mapstructure:"name" json:"name"`
}
type JwtConfig struct {
SigningKey string `mapstructure:"key" json:"key"`
Expire int `mapstructure:"expire" json:"expire"`
}
type RedisConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
}
type SmsConfig struct {
Template string `mapstructure:"code" json:"code"`
Key string `mapstructure:"key" json:"key"`
Secret string `mapstructure:"secret" json:"secret"`
Expire int `mapstructure:"expire" json:"expire"`
Domain string `mapstructure:"domain" json:"domain"`
Region string `mapstructure:"region" json:"region"`
Name string `mapstructure:"name" json:"name"`
Version string `mapstructure:"version" json:"version"`
}
type ConsulConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
}
type ServerConfig struct {
Log *LogConfig `mapstructure:"log" json:"log"`
Service *ServiceConfig `mapstructure:"service" json:"service"`
UserService *ServiceConfig `mapstructure:"user-service" json:"user-service"`
Jwt *JwtConfig `mapstructure:"jwt" json:"jwt"`
Sms *SmsConfig `mapstructure:"sms" json:"sms"`
Redis *RedisConfig `mapstructure:"redis" json:"redis"`
}
func init() {
Config = &ServerConfig{
Log: &LogConfig{},
Service: &ServiceConfig{},
UserService: &ServiceConfig{},
Jwt: &JwtConfig{},
Sms: &SmsConfig{},
Redis: &RedisConfig{},
Consul: &ConsulConfig{},
}
Nacos = &NacosConfig{}
}
修改配置文件
nacos:
host: xx.xx.xx.xx
port: xxx
DataId: xxx
Namespace: xxxxxxxxxxxx
Group: xx
Timeout: xxx
LogLevel: xxx
cachePath: xx/xx/xx
logPath: xx/xx/xx
修改讀取配置文件的函數
vp := viper.New()
vp.AddConfigPath("configs/")
vp.SetConfigName("config")
vp.SetConfigType("yml")
err := vp.ReadInConfig()
if err != nil {
panic(any(fmt.Sprintf("Read configs failed:%v", err.Error())))
}
err = vp.UnmarshalKey("nacos", &global.Nacos)
if err != nil {
panic(any(fmt.Sprintf("Read nacos configs failed:%v", err)))
}
sc := []constant.ServerConfig{
{
IpAddr: global.Nacos.Host,
Port: uint64(global.Nacos.Port),
ContextPath: "/nacos",
},
}
cc := constant.ClientConfig{
NamespaceId: global.Nacos.Namespace,
TimeoutMs: uint64(global.Nacos.Timeout),
NotLoadCacheAtStart: true,
LogDir: global.Nacos.LogPath,
CacheDir: global.Nacos.CachePath,
LogLevel: global.Nacos.LogLevel,
}
configClient, err := clients.CreateConfigClient(map[string]interface{}{
"serverConfigs": sc, "clientConfig": cc,
})
if err != nil {
panic(any(err))
}
content, err := configClient.GetConfig(vo.ConfigParam{
DataId: global.Nacos.DataId,
Group: global.Nacos.Group,
})
if err != nil {
panic(any(err))
}
err = json.Unmarshal([]byte(content), &global.Config)
if err != nil {
panic(any(fmt.Sprintf("Read config failed:%v", err)))
}
修改main函數
host, port, err := utils.FilterServiceByName(global.Config.UserService.Name)
if err != nil {
zap.S().Fatalw("FilterServiceByName", "name", global.Config.UserService.Name, "err", err)
return
}
zap.S().Infof("init user-service at %s:%d", host, port)
userConn := initialize.InitUserConnection(host, port)
defer func() {
if err := userConn.Close(); err != nil {
panic(err.(any))
}
}()
global.UserClient = user.NewUserServiceClient(userConn)
zap.S().Info("user-api running...")
addr := fmt.Sprintf("%s:%d", global.Config.Service.Host, global.Config.Service.Port)
將涉及到的配置修改的地方一一修改,然后將nacos中的配置格式更改為json格式后,即可啟動
至此,配置中心已經完成