Loading...
墨滴

我不是廖梓鉴

2021/05/20  阅读:43  主题:橙心

Nacos细节篇

环境: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
port int 服务实例port
namespaceId 字符串 命名空间ID
weight double 权重
enabled boolean 是否上线
healthy boolean 是否健康
metadata 字符串 扩展信息
clusterName 字符串 集群名
serviceName 字符串 服务名
groupName 字符串 分组名
ephemeral boolean 是否临时实例

测试:

  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

我不是廖梓鉴

2021/05/20  阅读:43  主题:橙心

作者介绍

我不是廖梓鉴