环境:Nacos 1.4.2

在前两篇:Nacos注册中心实战Nacos 配置中心实战阿鉴已经详细介绍了Nacos的两大功能,本篇就来补充一下之前未涉及到的小细节

有时候一个小细节就能使人自闭

OpenAPI

在讲注册中心内容时,我们已经知道Nacos本质上是一个服务,那么,是服务就会有接口,下面阿鉴给大家介绍一下注册实例接口

更多OpenAPI可查看Nacos官网:https://nacos.io/zh-cn/docs/open-api.html

注册实例接口

接口:/nacos/v1/ns/instance

请求方式:POST

参数:

名称类型是否必选描述
ip字符串服务实例IP
portint服务实例port
namespaceId字符串命名空间ID
weightdouble权重
enabledboolean是否上线
healthyboolean是否健康
metadata字符串扩展信息
clusterName字符串集群名
serviceName字符串服务名
groupName字符串分组名
ephemeralboolean是否临时实例

测试:

  1. 发送一个curl请求,当然使用Postman也可以

    curl -i -X POST \
       -H "Content-Type:application/json" \
     'http://192.168.2.11:8850/nacos/v1/ns/instance?serviceName=test&ip=123.123.123.123&port=8081&username=nacos&password=nacos'
    
  2. 打开Nacos控制台查看效果

    由于只传了必要参数,所以命名空间和分组名称都是默认的。

    注意:由于我们只注册了实例,并未定时发送心跳,所以实例会在一定时间内被Nacos剔除

  3. 打开详情

    ip和端口号即为我们填入的信息

OpenAPI在服务中的关系

相信小伙伴已经发现了,我们在调用接口时传入的参数是什么,注册到Nacos上的实例信息就是什么,那么在实际项目中能不能也这样玩呢?

在之前我们使用Nacos时,我们使用的配置是这样:

server:
  port: 8080
spring:
  application:
    name: my-order
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.2.11:8850
        username: nacos
        password: nacos

此时我们并未使用ip和port配置,Nacos将自动发现本地ip地址进行注册, port则使用server.port

现在我们将ipport加上

server:
  port: 8080
spring:
  application:
    name: my-order
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.2.11:8850
        ip: 123.123.123.123
        port: 1234
        username: nacos
        password: nacos

但实际上我本机ip地址为192.168.65.91

启动服务并在控制台查看服务详情

order-dtail

此时IP和端口就成了我们实际配置了的

心急的小伙伴这时候可能就会给阿鉴个大嘴巴子:讲那么多,这有啥用?!

阿鉴:不急不急

容器部署

在实际项目使用时,我们肯定倾向于让服务自己发现IP和端口号进行注册。

多实例部署时,谁关心你的本机ip是个啥,一个服务一会在那台机器,一会在这台机器,不可能每次部署时都改下配置。

但是有一种情况让Nacos自己发现IP是不可行的。那就是使用容器部署服务。

  1. 比如我们在192.168.2.11的服务器上部署一个my-goods服务,此时Nacos自动发现的IP实际上是容器内部IP,如172.19.0.16

  2. 现在尝试使用在192.168.2.12的服务器上的my-order服务,对my-goods服务进行调用,此时会收到一个拒绝连接错误,因为调用的地址是172.19.0.16,但实际需要的地址是192.168.2.11

问题解决

简单的办法就是在配置文件中加上ip的配置,如

server:
  port: 8081
spring:
  application:
    name: my-goods
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.2.11:8850
        ip: 192.168.2.11
        username: nacos
        password: nacos

此时my-goods注册到Nacos上的地址就是服务器的地址了。

但是这种方式有个很明显的弊端,就是服务迁移时需要改动配置,多实例部署时需要频繁改动配置。

一个更优雅的方式

我们把配置改成如下:

server:
  port: 8081
spring:
  application:
    name: my-goods
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.2.11:8850
        ip: ${HOST_IP_ADDRESS:127.0.0.1}
        username: nacos
        password: nacos

此时ip配置中增加了变量:HOST_IP_ADDRESS

docker-compose.yaml

version: '3.5'
services:
  my-goods:
    restart: always
    image: my-goods
    container_name: my-goods
    environment:
      HOST_IP_ADDRESS: $HOST_IP_ADDRESS
      TZ: Asia/Shanghai
    ports:
      - 8081:8081

在执行docker-compose前,将HOST_IP_ADDRESS输出到环境变量中

export HOST_IP_ADDRESS=$(ifconfig eth0 | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | awk '{ print $2 }'| cut -f2 -"d:")

这行命令表示将本机ip输出到环境变量HOST_IP_ADDRESS

这个步骤可根据不同的部署工具进行执行,比如阿鉴用的是gitlab-ci,就是在gitlab-ci中执行的。

如此,使用容器部署的方式便优雅完成了~

边车挂载

奇技淫巧

当我们发现了奥秘:只要我们配了IP,配的IP是啥,注册到Nacos的IP就是啥。

掌握奇技淫巧的程序员们有没有想到一些骚操作呢?阿鉴这里却是想到了一个哦~

my-sidercar将my-integral的信息注册到Nacos上

  1. 新建一个my-sidecar服务,配置如下

    server:
      port: 8082
    spring:
      application:
        name: my-sidecar
      main:
        allow-bean-definition-overriding: true
      cloud:
        nacos:
          discovery:
            server-addr: 192.168.1.11:8850
            namespace: public
            service: my-integral
            ip: 192.168.65.91
            port: 8083
            username: nacos
            password: nacos
    
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    

    注册到Nacos的信息是my-integral服务的

  2. 新建一个Spring Boot my-integral服务(注意不是SpringCloud服务,不集成Nacos),配置如下

    server:
      port: 8083
    spring:
      application:
        name: my-integral
    

    spring.application.name 配置加不加无所谓

  3. my-integral服务中编写接口

    @Slf4j
    @RestController
    @RequestMapping("/integral")
    public class IntegralController {
    
        @GetMapping("/remain")
        public String remain(){
            log.info("积分服务被调用了");
            Random random = new Random();
            int i = random.nextInt(100);
            return "您当前的积分为:" + i;
        }
    }
    
  4. 启动项目并打开控制台

    该信息是由my-sidecar注册而来,而非my-integer所注册的,因为my-integral并未集成Nacos

  5. my-order编写调用代码

    @RestController
    @RequestMapping("/order")
    public class OrderController {
    
        @Resource
        private RestTemplate restTemplate;
    
        @GetMapping("/integral")
        public String integral(){
            String url = "http://my-integral/integral/remain";
            return restTemplate.getForObject(url, String.class);
        }
    }
    
  6. 启动my-order测试

    服务调用成功了

回顾一下我们做了什么:我们使用配置ip的奥秘将一个并未集成Nacos的my-integral信息注册到了Nacos上,然后通过my-order成功发起了调用~

意义

这样做有什么意义呢?难道真就为了骚一把?不是的。

假设我们现在有这样的需求,有一个老项目old-project想要加入到微服务系统中,但是这个old-project集成Nacos的成本过高,那么我们就可以使用这样的方式了。

这样的方式支持非Java语言哦~

这里阿鉴偷偷告诉大家,这个方式其实有个术语,叫做:边车模式。

Nacos的边车模式

其实Nacos已经实现了边车模式,集成方式非常简单

  1. 在原Nacos项目(my-sidecar)中引入依赖

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sidecar</artifactId>
    </dependency>
    
  2. 编写配置

    server:
      port: 8082
    spring:
      application:
        name: my-sidecar
      main:
        allow-bean-definition-overriding: true
      cloud:
        nacos:
          discovery:
            server-addr: 192.168.1.11:8850
            service: my-integral
    sidecar:
      ip: 127.0.0.1
      port: 8083
      health-check-url: http://127.0.0.1:8083/integral/health
    
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    

    ip:my-integral的IP

    port: my-integral的端口

    health-check-url: my-integral的健康检查地址

  3. my-integral服务中增加接口

    @RestController
    @RequestMapping("/integral")
    public class IntegralController {
    
        @GetMapping("/health")
        public Map<String,String> health(){
            Map<String, String> map = new HashMap<>(2);
            map.put("status", "UP");
            return map;
        }
    }
    

    返回的内容必须是:status: UP

  4. 测试

小结

本篇补充了关于Nacos的一些细节,首先介绍了Nacos的OpenAPI, 通过OpenAPI延伸出了如何进行容器部署,以及边车模式,希望大家有所收获。

案例地址:https://gitee.com/lzj960515/my-micro-service-demo.git