101: nacos

[toc]

介绍

一句话介绍 nacos: 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

GITHUB 地址:

  • https://github.com/alibaba/nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。

服务(Service)是 Nacos 世界的一等公民。Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理:

Nacos 的关键特性包括:

  • 服务发现和服务健康监测

    Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 原生SDKopen in new windowOpenAPIopen in new window、或一个独立的Agent TODOopen in new window注册 Service 后,服务消费者可以使用DNS TODOopen in new windowHTTP&APIopen in new window查找和发现服务。

    Nacos 提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。

  • 动态配置服务

    动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。

    动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。

    配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。

    Nacos 提供了一个简洁易用的UI (控制台样例 Demoopen in new window) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。

  • 动态 DNS 服务

    动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以 DNS 协议为基础的服务发现,以帮助您消除耦合到厂商私有服务发现 API 上的风险。

    Nacos 提供了一些简单的 DNS APIs TODOopen in new window 帮助您管理服务的关联域名和可用的 IP:PORT 列表.

  • 服务及其元数据管理

    Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。

  • 更多的特性列表 ...open in new window

功能

动态配置服务: 动态配置服务让您能够以中心化、外部化和动态化的方式管理所有环境的配置。动态配置消除了配置变更时重新部署应用和服务的需要。配置中心化管理让实现无状态服务更简单,也让按需弹性扩展服务更容易。

服务发现以及管理: 动态服务发现对以服务为中心的(例如微服务和云原生)应用架构方式非常关键。Nacos支持DNS-Based和RPC-Based(Dubbo、gRPC)模式的服务发现。Nacos也提供实时健康检查,以防止将请求发往不健康的主机或服务实例。借助Nacos,您可以更容易地为您的服务实现断路器。

动态 DNS 服务: 通过支持权重路由,动态DNS服务能让您轻松实现中间层负载均衡、更灵活的路由策略、流量控制以及简单数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以DNS协议为基础的服务发现,以消除耦合到厂商私有服务发现API上的风险。

快速上手

源码启动:

Nacos 依赖 Javaopen in new window 环境来运行。如果您是从代码开始构建并运行Nacos,还需要为此配置 Mavenopen in new window环境,请确保是在以下版本环境中安装使用:

  1. 64 bit OS,支持 Linux/Unix/Mac/Windows,推荐选用 Linux/Unix/Mac。
  2. 64 bit JDK 1.8+;下载open in new window & 配置open in new window
  3. Maven 3.2.x+;下载open in new window & 配置open in new window

在2.2.0.1和2.2.1版本时,必须执行此变更,否则无法启动;其他版本为建议设置。

修改conf目录下的application.properties文件。

设置其中的nacos.core.auth.plugin.nacos.token.secret.key值,详情可查看鉴权-自定义密钥open in new window.

注意,文档中的默认值SecretKey012345678901234567890123456789012345678901234567890123456789VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMTIzNDU2Nzg=为公开默认值,可用于临时测试,实际使用时请务必更换为自定义的其他有效值。

启动:

  • 注:Nacos的运行建议至少在2C4G 60G的机器配置下运行。

Linux/Unix/Mac

启动命令(standalone代表着单机模式运行,非集群模式):

sh startup.sh -m standalone

如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:

bash startup.sh -m standalone

Windows

启动命令(standalone代表着单机模式运行,非集群模式):

startup.cmd -m standalone

服务注册&发现和配置管理

服务注册

curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'

服务发现

curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'

发布配置

curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"

获取配置

curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"

关闭服务器

Linux/Unix/Mac

sh shutdown.sh

Windows

shutdown.cmd

或者双击shutdown.cmd运行文件。

docker 部署

  • Clone 项目

    git clone https://github.com/nacos-group/nacos-docker.git
    cd nacos-docker
    
  • 单机模式 Derby

    docker-compose -f example/standalone-derby.yaml up
    
  • 服务注册

    curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
    
  • 服务发现

    curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'
    
  • 发布配置

    curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=helloWorld"
    
  • 获取配置

      curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
    
  • Nacos 控制台

    link:http://127.0.0.1:8848/nacos/

Kubernetes Nacos

git clone https://github.com/nacos-group/nacos-k8s.git
  • 简单例子

如果你使用简单方式快速启动,请注意这是没有使用持久化卷的,可能存在数据丢失风险:

cd nacos-k8s
chmod +x quick-startup.sh
./quick-startup.sh
  • 测试

    • 服务注册
    curl -X POST 'http://cluster-ip:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
    
    • 服务发现
    curl -X GET 'http://cluster-ip:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'
    
    • 发布配置
    curl -X POST "http://cluster-ip:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=helloWorld"
    
    • 获取配置
    curl -X GET "http://cluster-ip:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
    

高级使用

在高级使用中,Nacos在K8S拥有自动扩容缩容和数据持久特性,请注意如果需要使用这部分功能请使用PVC持久卷,Nacos的自动扩容缩容需要依赖持久卷,以及数据持久化也是一样,本例中使用的是NFS来使用PVC.

部署 NFS

  • 创建角色
kubectl create -f deploy/nfs/rbac.yaml

如果的K8S命名空间不是default,请在部署RBAC之前执行以下脚本:

# Set the subject of the RBAC objects to the current namespace where the provisioner is being deployed
$ NS=$(kubectl config get-contexts|grep -e "^\*" |awk '{print $5}')
$ NAMESPACE=${NS:-default}
$ sed -i'' "s/namespace:.*/namespace: $NAMESPACE/g" ./deploy/nfs/rbac.yaml
  • 创建 ServiceAccount 和部署 NFS-Client Provisioner
kubectl create -f deploy/nfs/deployment.yaml
  • 创建 NFS StorageClass
kubectl create -f deploy/nfs/class.yaml
  • 验证NFS部署成功
kubectl get pod -l app=nfs-client-provisioner

部署数据库

cd nacos-k8s

kubectl create -f deploy/mysql/mysql-nfs.yaml
  • 验证数据库是否正常工作
kubectl get pod 
NAME                         READY   STATUS    RESTARTS   AGE
mysql-gf2vd                        1/1     Running   0          111m

执行数据库初始化语句

数据库初始化语句位置 https://github.com/alibaba/nacos/blob/develop/distribution/conf/nacos-mysql.sql

部署Nacos

  • 修改 deploy/nacos/nacos-pvc-nfs.yaml
data:
  mysql.host: "数据库地址"
  mysql.db.name: "数据库名称"
  mysql.port: "端口"
  mysql.user: "用户名"
  mysql.password: "密码"
  • 创建 Nacos
kubectl create -f nacos-k8s/deploy/nacos/nacos-pvc-nfs.yaml
  • 验证Nacos节点启动成功
kubectl get pod -l app=nacos


NAME      READY   STATUS    RESTARTS   AGE
nacos-0   1/1     Running   0          19h
nacos-1   1/1     Running   0          19h
nacos-2   1/1     Running   0          19h

扩容测试

for i in 0 1; do echo nacos-$i; kubectl exec nacos-$i cat conf/cluster.conf; done

StatefulSet控制器根据其序数索引为每个Pod提供唯一的主机名。 主机名采用 - 的形式。 因为nacos StatefulSet的副本字段设置为2,所以当前集群文件中只有两个Nacos节点地址

k8s

  • 使用kubectl scale 对Nacos动态扩容
kubectl scale sts nacos --replicas=3

scale

for i in 0 1 2; do echo nacos-$i; kubectl exec nacos-$i cat conf/cluster.conf; done

get_cluster_after

for i in 0 1 2; do echo nacos-$i; kubectl exec nacos-$i curl -X GET "http://localhost:8848/nacos/v1/ns/raft/state"; done

到这里你可以发现新节点已经正常加入Nacos集群当中

注意:

  • Nacos是一个内部微服务组件,需要在可信的内部网络中运行,不可暴露在公网环境,防止带来安全风险。
  • Nacos提供简单的鉴权实现,为防止业务错用的弱鉴权体系,不是防止恶意攻击的强鉴权体系。
  • 如果运行在不可信的网络环境或者有强鉴权诉求,请参考官方简单实现做进行自定义插件开发open in new window

插件

Nacos从2.1.0版本开始,支持通过SPIopen in new window的方式注入鉴权相关插件,并在application.properties配置文件中选择某一种插件实现作为实际鉴权服务。本文档会详细介绍如何实现一个鉴权插件和如何使其生效。

注意: 目前鉴权插件还处于Beta测试的阶段,其API及接口定义可能会随后续版本升级而有所修改,请注意您的插件适用版本。

鉴权插件中的概念

鉴权,通俗的表达就是,验证 是否能够对 某个东西 进行 某种操作 ,因此Nacos在设计鉴权插件时,将鉴权信息主要抽象为身份信息资源操作类型3类主要概念。

身份信息 IdentityContext

身份信息(IdentityContext)是请求发起主体在Nacos鉴权插件中的抽象。由于不同的插件实现,身份信息可能不同,较为灵活;比如用户名和密码是一种身份信息,accessToken又是另一种身份信息。因此身份信息(IdentityContext)并没有限制具体的个数和名字,插件实现可以自定义任意个数和身份关键字,Nacos将会从请求中自动获取插件实现定义的身份关键字及其对应的值注入到身份信息(IdentityContext)中,供插件使用。

其中必定会包含的内容有:

字段名描述
remote_ip请求来源ip

资源 Resource

资源(Resource)是请求所操作对象在Nacos鉴权插件中的抽象。它主要由Nacos来定义,具体可以是某个配置,某个服务,或者某个分组。

资源(Resource)主要由以下内容组成:

字段名描述
namespaceId请求资源的命名空间ID,部分接口可能没有该值
group请求资源的分组名,部分接口可能没有该值
name请求资源的资源名,如服务名或配置的dataId,部分接口可能是定义的特殊值,如nacos/admin
type请求资源的类型,可能取值为SignType中的枚举值,主要表示该资源所相关的模块
properties请求资源的扩展配置,不属于上述的资源相关信息,会被放如properties中,比如Grpc请求的Request名称或@Secured注解上的tags等

操作类型 Action

操作类型(Action)是请求操作在Nacos鉴权插件中的抽象,主要有读操作R和写操作W,详情查看ActionTypes枚举。

服务端插件

开发Nacos服务端鉴权插件,首先需要依赖鉴权插件的相关API

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-auth-plugin</artifactId>
            <version>${project.version}</version>
        </dependency>

${project.version} 为您开发插件所对应的Nacos版本

随后实现com.alibaba.nacos.plugin.auth.spi.server.AuthPluginService接口, 并将您的实现添加到SPI的services当中。

接口中需要实现的方法如下:

方法名入参内容返回内容描述
getAuthServiceNamevoidString插件的名称,当名字相同时,后加载的插件会覆盖先加载的插件。
identityNamesvoidCollection插件的身份信息关键字,Nacos会从请求中获取以这些关键字为key的参数,并注入到IdentityContext中。
enableAuthActionTypes,SignTypeboolean在调用validateIdentityvalidateAuthority前调用,插件可自行判断是否对此类型的操作或此类型的模块进行鉴权。
validateIdentityIdentityContext, Resourceboolean对身份信息进行验证,在validateAuthority前调用
validateAuthorityIdentityContext, Permissionboolean对权限进行验证,在validateIdentity返回为true时调用

加载服务端插件

插件开发完成后,需要打包成jar/zip,放置到nacos服务端的classpath中,如果您不知道如何修改classpath,请直接放置到${nacos-server.path}/plugins

放置后,需要修改${nacos-server.path}/conf/application.properties中的以下配置

### 所启用的Nacos的鉴权插件的名称,与`com.alibaba.nacos.plugin.auth.spi.server.AuthPluginService`的`getAuthServiceName`返回值对应
nacos.core.auth.system.type=${authServiceName}

### 开启鉴权功能
nacos.core.auth.enabled=true

随后重启nacos集群,在有请求访问到nacos节点后,可以从${nacos-server.path}/logs/nacos.log中看到如下日志:

[AuthPluginManager] Load AuthPluginService(xxxx) AuthServiceName(xxx) successfully.

使用Nacos自带的鉴权插件

Nacos默认带有一个鉴权的简易实现,主要是为防止业务错用的弱鉴权体系,不是防止恶意攻击的强鉴权体系。开启和使用方式请查看文档用户指南-权限认证open in new window.

客户端插件

Nacos的客户端鉴权插件主要工作为将鉴权相关的身份信息,注入到请求中,让每个请求都能够被对应的服务端鉴权插件识别。

在Nacos的Java客户端默认自带两个实现:

  • 使用usernamepasswordaccessToken的简易鉴权实现;
  • 使用accessKeysecretKey的阿里云鉴权实现;

Nacos简易鉴权实现

当构造客户端实例时传入的properties中带有usernamepassword时,客户端会使用简易鉴权实现插件注入身份信息; 如:

Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "localhost:8848");
properties.setProperty(PropertyKeyConst.USERNAME, "nacos");
properties.setProperty(PropertyKeyConst.PASSWORD, "nacos");
NamingFactory.createNamingService(properties);
ConfigFactory.createConfigService(properties);

该插件会异步地通过usernamepassword进行登录,获取登录成功后的accessToken,并将accessToken注入到所有客户端请求中,开发者可以根据accessToken在实现的服务端插件中进行身份验证及后续的权限验证。

阿里云鉴权实现

当properties中带有accessKeysecretKey时,则会使用阿里云鉴权实现注入身份信息,如:

Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "localhost:8848");
properties.setProperty(PropertyKeyConst.ACCESS_KEY, "nacos");
properties.setProperty(PropertyKeyConst.SECRET_KEY, "nacos");
NamingFactory.createNamingService(properties);
ConfigFactory.createConfigService(properties);

该插件会根据accessKeysecretKey以及请求的资源内容,自动生成对应的请求签名,并注入到请求中,根据资源类型的不同,请求中的身份信息关键字可能不同:

类型身份关键字描述
NamingServiceakaccessKey
NamingServicesignature注册中心模块的签名信息
NamingServicedata签名数据,主要是时间戳
ConfigServiceSpas-AccessKeyaccessKey
ConfigServiceSpas-Signature配置中心模块的签名信息
ConfigServiceTimestamp请求的时间戳
ConfigServiceSpas-SecurityToken临时token(启用阿里云STS功能时使用)

开发者可以根据以上信息,在实现的服务端插件中进行身份验证及后续的权限验证。

其他自定义插件

考虑到开发者的鉴权插件可能有自定义的身份信息关键字,因此Nacos的Java客户端同样可以使用SPI方式注入对应的插件实现。

开发Nacos客户端鉴权插件,首先需要依赖鉴权插件的相关API

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-auth-plugin</artifactId>
            <version>${project.version}</version>
        </dependency>

${project.version} 为您开发插件所对应的Nacos版本

随后实现com.alibaba.nacos.plugin.auth.spi.client.ClientAuthService接口, 并将您的实现添加到SPI的services当中。

接口中需要实现的方法如下:

方法名入参内容返回内容描述
setServerListList,Nacos服务端地址列表void初始化时会调用此接口注入Nacos的服务列表,方便插件访问nacos服务端,如调用登录接口等
setNacosRestTemplateNacosRestTemplate,Nacos的http客户端void初始化时会调用此接口注入Nacos的http客户端,方便插件访问nacos服务端,如调用登录接口等
loginProperties,即初始化Nacos客户端时传入的参数boolean登录接口,主要执行的是身份信息的转换工作,如usernamepassword转换为accessToken
getLoginIdentityContextResourceIdentityContext获取经过登录接口转换后的身份信息,客户端会将该返回对象的内容全部注入到请求中

您也可以选择继承com.alibaba.nacos.plugin.auth.spi.client.AbstractClientAuthService,该父类默认实现了setServerListsetNacosRestTemplate

将开发完成的客户端插件打包成jar/zip,放入到您应用的classpath中即可自动生效。