Nacos的安装与使用

24 阅读7分钟

Nacos 介绍

Nacos (Dynamic Naming and Configuration Service)是阿里巴巴开源的一个动态服务发现、配置管理和服务管理平台。

主要作用

  1. 服务注册与发现:微服务可以注册到 Nacos,其他服务通过 Nacos 发现并调用它们
  2. 配置管理:集中管理应用配置,支持动态配置更新,无需重启应用
  3. 服务健康监测:实时监控服务健康状态,自动剔除不健康实例
  4. 动态 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"

访问控制台

访问: http://localhost:8080

  • 用户名: nacos
  • 密码: nacos

(第一次访问要设置密码)



番外: 排查问题 常用命令

# 查看日志
docker logs -f nacos

# 停止 Nacos
docker stop nacos

# 启动 Nacos
docker start nacos

# 重启 Nacos
docker restart nacos

# 删除容器
docker rm -f nacos


使用

登录后,会看到 Nacos 控制台 左侧菜单有以下几个主要模块:

配置管理 (最常用)

用于集中管理微服务的配置文件

服务管理

用于服务注册与发现

命名空间

用于环境隔离(开发、测试、生产)

集群管理

查看 Nacos 集群状态


快速上手:配置管理

创建配置

  1. 点击左侧菜单 配置管理配置列表
  2. 点击右上角 "+" 按钮创建配置
  3. 填写以下信息:
Data ID: application.yml
Group: DEFAULT_GROUP
配置格式: YAML
配置内容:
server:
  port: 8081

spring:
  application:
    name: demo-service

message: "Hello from Nacos!"
  1. 点击 发布

查看配置

  • 在配置列表中可以看到刚创建的配置
  • 点击配置可以查看详情、编辑、查看历史版本
  • 支持配置回滚

服务注册与发现示例

查看服务列表

  1. 点击 服务管理服务列表
  2. 目前是空的,需要应用注册后才能看到

使用命名空间隔离环境

创建命名空间

  1. 点击 命名空间
  2. 点击 新建命名空间
  3. 填写信息:
命名空间名: dev
命名空间ID: (自动生成)
描述: 开发环境
  1. 同样创建 testprod 命名空间

在 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;
    }
}

实用操作技巧

配置动态刷新

  1. 修改 Nacos 中的配置
  2. 点击 发布
  3. 应用会自动获取最新配置(无需重启)

配置搜索

  • 支持按 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、端口等

服务下线

  • 点击服务实例的 下线 按钮
  • 该实例将不再接收流量

实践建议

  1. 命名规范: Data ID 建议使用 ${应用名}-${环境}.${后缀} 格式
  2. 分组使用: 可以按业务模块分组,如 USER_GROUP, ORDER_GROUP
  3. 权限管理: 生产环境建议修改默认密码,配置权限
  4. 备份配置: 定期导出重要配置做备份




在 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",
})

七、注意事项

  1. 命名空间 ID: 如果使用 public 命名空间,NamespaceId 留空字符串
  2. 服务注销: 程序退出时记得注销服务
  3. 心跳机制: Nacos 会自动发送心跳,保持服务健康状态
  4. 配置缓存: SDK 会在本地缓存配置,即使 Nacos 服务不可用也能读取