Nacos 介绍
Nacos (Dynamic Naming and Configuration Service)是阿里巴巴开源的一个动态服务发现、配置管理和服务管理平台。
主要作用
- 服务注册与发现:微服务可以注册到 Nacos,其他服务通过 Nacos 发现并调用它们
- 配置管理:集中管理应用配置,支持动态配置更新,无需重启应用
- 服务健康监测:实时监控服务健康状态,自动剔除不健康实例
- 动态 DNS 服务:支持基于 DNS 的服务发现
安装/启动
docker run -d \
--name nacos \
--restart=always \
--platform linux/arm64 \
-e MODE=standalone \
-e NACOS_AUTH_ENABLE=true \
-e NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789 \
-e NACOS_AUTH_IDENTITY_KEY=nacos \
-e NACOS_AUTH_IDENTITY_VALUE=nacos \
-e JVM_XMS=512m \
-e JVM_XMX=512m \
-p 8080:8080 \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
nacos/nacos-server:latest
等待启动
echo "等待 Nacos 启动..." sleep 25
验证端口映射
docker port nacos
检查启动状态
docker logs nacos | grep "started successfully"
访问控制台
- 用户名:
nacos - 密码:
nacos
(第一次访问要设置密码)
番外: 排查问题 常用命令
# 查看日志
docker logs -f nacos
# 停止 Nacos
docker stop nacos
# 启动 Nacos
docker start nacos
# 重启 Nacos
docker restart nacos
# 删除容器
docker rm -f nacos
使用
登录后,会看到 Nacos 控制台 左侧菜单有以下几个主要模块:
配置管理 (最常用)
用于集中管理微服务的配置文件
服务管理
用于服务注册与发现
命名空间
用于环境隔离(开发、测试、生产)
集群管理
查看 Nacos 集群状态
快速上手:配置管理
创建配置
- 点击左侧菜单 配置管理 → 配置列表
- 点击右上角 "+" 按钮创建配置
- 填写以下信息:
Data ID: application.yml
Group: DEFAULT_GROUP
配置格式: YAML
配置内容:
server:
port: 8081
spring:
application:
name: demo-service
message: "Hello from Nacos!"
- 点击 发布
查看配置
- 在配置列表中可以看到刚创建的配置
- 点击配置可以查看详情、编辑、查看历史版本
- 支持配置回滚
服务注册与发现示例
查看服务列表
- 点击 服务管理 → 服务列表
- 目前是空的,需要应用注册后才能看到
使用命名空间隔离环境
创建命名空间
- 点击 命名空间
- 点击 新建命名空间
- 填写信息:
命名空间名: dev
命名空间ID: (自动生成)
描述: 开发环境
- 同样创建
test和prod命名空间
在 Spring Boot 项目中使用 Nacos
1. 添加依赖 (pom.xml)
<dependencies>
<!-- Nacos 配置管理 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2022.0.0.0</version>
</dependency>
<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2022.0.0.0</version>
</dependency>
</dependencies>
2. 配置文件 (bootstrap.yml)
spring:
application:
name: my-service
cloud:
nacos:
# 配置中心
config:
server-addr: localhost:8848
file-extension: yaml
namespace: dev # 使用 dev 命名空间
username: nacos
password: nacos
# 服务发现
discovery:
server-addr: localhost:8848
namespace: dev
username: nacos
password: nacos
3. 启动类添加注解
@SpringBootApplication
@EnableDiscoveryClient // 启用服务发现
public class MyServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MyServiceApplication.class, args);
}
}
4. 读取配置
@RestController
@RefreshScope // 支持配置动态刷新
public class ConfigController {
@Value("${message:default}")
private String message;
@GetMapping("/config")
public String getConfig() {
return message;
}
}
实用操作技巧
配置动态刷新
- 修改 Nacos 中的配置
- 点击 发布
- 应用会自动获取最新配置(无需重启)
配置搜索
- 支持按 Data ID、Group 搜索
- 支持模糊搜索
配置历史
- 点击配置详情 → 历史版本
- 可以对比版本差异
- 支持回滚到历史版本
配置监听查询
- 查看哪些客户端正在监听某个配置
- 在配置详情页可以看到
常见使用场景
场景 1: 多环境配置管理
命名空间: dev, test, prod
Data ID: application.yml
不同环境配置不同的数据库连接等
场景 2: 微服务配置
Data ID: user-service.yml (用户服务配置)
Data ID: order-service.yml (订单服务配置)
Data ID: common.yml (公共配置)
场景 3: 动态开关
# 在 Nacos 中配置
feature:
newFeature: true # 新功能开关
# 在代码中使用
@Value("${feature.newFeature}")
private boolean newFeatureEnabled;
监控与运维
查看服务健康状态
- 服务管理 → 服务列表 → 点击服务名
- 可以看到服务实例的健康状态、IP、端口等
服务下线
- 点击服务实例的 下线 按钮
- 该实例将不再接收流量
实践建议
- 命名规范: Data ID 建议使用
${应用名}-${环境}.${后缀}格式 - 分组使用: 可以按业务模块分组,如
USER_GROUP,ORDER_GROUP - 权限管理: 生产环境建议修改默认密码,配置权限
- 备份配置: 定期导出重要配置做备份
在 Golang 中使用 Nacos
阿里巴巴提供了官方的 Go SDK
一、安装 Nacos Go SDK
go get -u github.com/nacos-group/nacos-sdk-go/v2
二、配置管理示例
1. 基础配置读取
package main
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
func main() {
// 创建 ServerConfig
sc := []constant.ServerConfig{
{
IpAddr: "localhost",
Port: 8848,
},
}
// 创建 ClientConfig
cc := constant.ClientConfig{
NamespaceId: "dev", // 命名空间ID,如果是public则留空
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
LogLevel: "info",
Username: "nacos",
Password: "nacos",
}
// 创建配置客户端
configClient, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
panic(err)
}
// 获取配置
content, err := configClient.GetConfig(vo.ConfigParam{
DataId: "application.yml",
Group: "DEFAULT_GROUP",
})
if err != nil {
panic(err)
}
fmt.Println("配置内容:\n", content)
}
2. 监听配置变化(动态刷新)
package main
import (
"fmt"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
func main() {
// 创建配置客户端(同上)
sc := []constant.ServerConfig{{IpAddr: "localhost", Port: 8848}}
cc := constant.ClientConfig{
NamespaceId: "",
TimeoutMs: 5000,
Username: "nacos",
Password: "nacos",
}
configClient, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
panic(err)
}
// 监听配置变化
err = configClient.ListenConfig(vo.ConfigParam{
DataId: "application.yml",
Group: "DEFAULT_GROUP",
OnChange: func(namespace, group, dataId, data string) {
fmt.Println("配置发生变化:")
fmt.Println("Namespace:", namespace)
fmt.Println("Group:", group)
fmt.Println("DataId:", dataId)
fmt.Println("新配置内容:\n", data)
},
})
if err != nil {
panic(err)
}
// 保持程序运行
select {}
}
3. 发布配置
package main
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
func main() {
// 创建配置客户端
sc := []constant.ServerConfig{{IpAddr: "localhost", Port: 8848}}
cc := constant.ClientConfig{
Username: "nacos",
Password: "nacos",
}
configClient, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
panic(err)
}
// 发布配置
success, err := configClient.PublishConfig(vo.ConfigParam{
DataId: "test-config.yml",
Group: "DEFAULT_GROUP",
Content: "server:\n port: 8080\n name: test-service",
})
if err != nil {
panic(err)
}
fmt.Println("发布配置成功:", success)
}
三、服务注册与发现
1. 服务注册
package main
import (
"fmt"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
func main() {
// 创建服务发现客户端
sc := []constant.ServerConfig{{IpAddr: "localhost", Port: 8848}}
cc := constant.ClientConfig{
NamespaceId: "",
TimeoutMs: 5000,
Username: "nacos",
Password: "nacos",
}
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
panic(err)
}
// 注册服务实例
success, err := namingClient.RegisterInstance(vo.RegisterInstanceParam{
Ip: "127.0.0.1",
Port: 8080,
ServiceName: "user-service",
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
Metadata: map[string]string{"version": "1.0"},
ClusterName: "DEFAULT",
GroupName: "DEFAULT_GROUP",
})
if err != nil {
panic(err)
}
fmt.Println("注册服务成功:", success)
// 保持服务运行
time.Sleep(time.Hour)
}
2. 服务发现
package main
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
func main() {
// 创建服务发现客户端
sc := []constant.ServerConfig{{IpAddr: "localhost", Port: 8848}}
cc := constant.ClientConfig{
Username: "nacos",
Password: "nacos",
}
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
panic(err)
}
// 获取服务实例列表
instances, err := namingClient.SelectInstances(vo.SelectInstancesParam{
ServiceName: "user-service",
GroupName: "DEFAULT_GROUP",
HealthyOnly: true, // 只返回健康实例
})
if err != nil {
panic(err)
}
fmt.Println("服务实例列表:")
for _, instance := range instances {
fmt.Printf("IP: %s, Port: %d, Weight: %.2f\n",
instance.Ip, instance.Port, instance.Weight)
}
}
3. 订阅服务变化
package main
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/model"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
func main() {
// 创建服务发现客户端
sc := []constant.ServerConfig{{IpAddr: "localhost", Port: 8848}}
cc := constant.ClientConfig{
Username: "nacos",
Password: "nacos",
}
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
panic(err)
}
// 订阅服务变化
err = namingClient.Subscribe(&vo.SubscribeParam{
ServiceName: "user-service",
GroupName: "DEFAULT_GROUP",
SubscribeCallback: func(services []model.Instance, err error) {
fmt.Println("服务列表发生变化:")
for _, service := range services {
fmt.Printf(" - %s:%d (健康: %v)\n",
service.Ip, service.Port, service.Healthy)
}
},
})
if err != nil {
panic(err)
}
// 保持程序运行
select {}
}
四、完整的 Web 服务示例
结合 Gin 框架的完整示例:
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
"gopkg.in/yaml.v3"
"log"
)
// 配置结构体
type AppConfig struct {
Server struct {
Port int `yaml:"port"`
Name string `yaml:"name"`
} `yaml:"server"`
Message string `yaml:"message"`
}
var appConfig AppConfig
func main() {
// 1. 创建 Nacos 配置客户端
sc := []constant.ServerConfig{{IpAddr: "localhost", Port: 8848}}
cc := constant.ClientConfig{
NamespaceId: "",
TimeoutMs: 5000,
Username: "nacos",
Password: "nacos",
}
configClient, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
log.Fatal(err)
}
// 2. 获取配置
content, err := configClient.GetConfig(vo.ConfigParam{
DataId: "application.yml",
Group: "DEFAULT_GROUP",
})
if err != nil {
log.Fatal(err)
}
// 3. 解析配置
err = yaml.Unmarshal([]byte(content), &appConfig)
if err != nil {
log.Fatal(err)
}
// 4. 监听配置变化
err = configClient.ListenConfig(vo.ConfigParam{
DataId: "application.yml",
Group: "DEFAULT_GROUP",
OnChange: func(namespace, group, dataId, data string) {
log.Println("配置发生变化,重新加载...")
yaml.Unmarshal([]byte(data), &appConfig)
},
})
if err != nil {
log.Fatal(err)
}
// 5. 创建服务发现客户端并注册服务
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
log.Fatal(err)
}
// 注册服务
_, err = namingClient.RegisterInstance(vo.RegisterInstanceParam{
Ip: "127.0.0.1",
Port: uint64(appConfig.Server.Port),
ServiceName: appConfig.Server.Name,
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
})
if err != nil {
log.Fatal(err)
}
// 6. 启动 Web 服务
r := gin.Default()
r.GET("/config", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": appConfig.Message,
"port": appConfig.Server.Port,
"name": appConfig.Server.Name,
})
})
r.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "UP"})
})
log.Printf("服务启动在端口 %d\n", appConfig.Server.Port)
r.Run(fmt.Sprintf(":%d", appConfig.Server.Port))
}
对应的 Nacos 配置(application.yml):
server:
port: 8080
name: demo-service
message: "Hello from Nacos Config!"
五、项目结构建议
your-project/
├── main.go
├── config/
│ └── nacos.go # Nacos 客户端初始化
├── model/
│ └── config.go # 配置结构体
└── service/
└── user_service.go # 业务逻辑
config/nacos.go
package config
import (
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
type NacosClient struct {
ConfigClient config_client.IConfigClient
NamingClient naming_client.INamingClient
}
func NewNacosClient() (*NacosClient, error) {
sc := []constant.ServerConfig{{
IpAddr: "localhost",
Port: 8848,
}}
cc := constant.ClientConfig{
NamespaceId: "",
TimeoutMs: 5000,
Username: "nacos",
Password: "nacos",
}
configClient, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
return nil, err
}
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
if err != nil {
return nil, err
}
return &NacosClient{
ConfigClient: configClient,
NamingClient: namingClient,
}, nil
}
六、常用操作
删除配置
success, err := configClient.DeleteConfig(vo.ConfigParam{
DataId: "test-config.yml",
Group: "DEFAULT_GROUP",
})
注销服务
success, err := namingClient.DeregisterInstance(vo.DeregisterInstanceParam{
Ip: "127.0.0.1",
Port: 8080,
ServiceName: "user-service",
GroupName: "DEFAULT_GROUP",
})
获取一个健康实例(负载均衡)
instance, err := namingClient.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
ServiceName: "user-service",
GroupName: "DEFAULT_GROUP",
})
七、注意事项
- 命名空间 ID: 如果使用
public命名空间,NamespaceId留空字符串 - 服务注销: 程序退出时记得注销服务
- 心跳机制: Nacos 会自动发送心跳,保持服务健康状态
- 配置缓存: SDK 会在本地缓存配置,即使 Nacos 服务不可用也能读取