【踩坑日记】使用公网ip向nacos注册服务

5,522 阅读2分钟

问题描述:部署在白嫖的腾讯云轻量服务器上的服务向nacos注册了内网ip,导致不在一个内网内的服务无法访问。

在太阳刚从窗边探出头的一个清晨,我自信的将写好的springcloud alibaba架构的服务打包并打算部署上从朋友那py来的两台服务器上,部署完成之后我就发现了,反问服务时一定概率出现time out情况(feign默认使用ribbon的轮训,所以当命中不在本服务器上的服务时,因为不是同一个账号,所以两台在同一个区域的腾讯云轻量服务器就算同是10.0.xx.xx网段也无法互通,所以无法服务之间并不能访问)

然后我就开始想办法解决(当然是开始百度)

我兴奋的从网上找到了这种解决方案:

spring.cloud.inetutils.preferred-networks=xxx.xxx.

通过这个配置,引导使用xxx.xxx开头的ip去注册,我不同的服务器 前缀都不一致呀,然后我也看到了可以忽略网卡

spring.cloud.inetutils.ignored-interfaces[0]=xxx

然后我就上服务器ip a

执行了一下,遇到了让我很头疼的问题:

image.png

这也没有外网ip的网卡啊?

然后我就赶紧百度了一波将服务注册上nacos的过程

如果没有配置ip配置选项 走的是这些配置


@Bean
@ConditionalOnMissingBean
public SimpleDiscoveryProperties simpleDiscoveryProperties(@Value("${spring.application.name:application}") String serviceId) {
    this.simple.getLocal().setServiceId(serviceId);
    this.simple.getLocal().setUri(URI.create("http://" + this.inet.findFirstNonLoopbackHostInfo().getHostname() + ":" + this.findPort()));
    return this.simple;
}

其中 findFirstNonLoopbackHostInfo()

public HostInfo findFirstNonLoopbackHostInfo() {
    InetAddress address = this.findFirstNonLoopbackAddress();
    if (address != null) {
        return this.convertAddress(address);
    } else {
        HostInfo hostInfo = new HostInfo();
        hostInfo.setHostname(this.properties.getDefaultHostname());
        hostInfo.setIpAddress(this.properties.getDefaultIpAddress());
        return hostInfo;
    }
}

但是从ip a的命令中并未找到公网ip,所以我好像只能:

spring.cloud.nacos.discovery.ip=xxx.xxx.xxx.xxx

这直接把注册ip写死在配置文件内,虽然解决了这个问题,但是……

这不就是为难我这个大懒人吗,一台服务器一个包,太难了吧,假设我有20台服务器,我不就得打20个包?

当然有人会说通过启动命令去配置(-D),但是

我不想写命令呀

所以我在想,是否可以启动的时候获取本机的公网ip去注册到nacos上

思路大概是: 启动的时候加载完配置文件后,设置配置文件中的spring.cloud.nacos.discovery.ip值为本机的公网ip

那么第一个问题来了,我怎么知道自己的公网ip呢?

开发过程中常见的方式就是从请求中取,但是如果是通过nginx代理的服务就得让nginx代理的时候将真实访问ip也代理过去,那我们是否就可以从nginx来获取呢?

于是我在我的nginx上加了这个配置(配置在server中)

   location = /getIp{
        return 200 "$remote_addr";
  }

这时候你访问 域名/getIp 就会直接返回访问端的IP地址了

这个公网ip来源解决了,接下来就是把ip更新到配置中去

增加一个listener:

public class AfterConfigListener implements SmartApplicationListener, Ordered {


    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        return(ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(aClass) ||
                ApplicationPreparedEvent.class.isAssignableFrom(aClass) );
    }
    @Override
    public int getOrder() {
        return(ConfigFileApplicationListener.DEFAULT_ORDER + 1);
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        RestTemplate restTemplate=new RestTemplate();
        ResponseEntity<String> response=restTemplate.getForEntity("https://xxxx.xxx/getIp",String.class);
        String currenIp=response.getBody();
        if (applicationEvent instanceof ApplicationEnvironmentPreparedEvent)
        {
            System.setProperty("spring.cloud.nacos.discovery.ip", currenIp);
        }
    }
}

然后在启动类的main方法中注册这个listener:

SpringApplication springApplication = new SpringApplication(xxxxApplication.class);
springApplication.addListeners(new AfterConfigListener());
springApplication.run(args);

这时候你启动这个服务的时候,在服务最后你就能发现输出了一行:

(NacosServiceRegistry.java:65)- nacos registry, DEFAULT_GROUP xxx-xxx-xxx xxx.xxx.xxx.xxx:port register finished

这时候你到nacos控制台上就能发现,ip已经是公网ip了,两个服务之间就不用在同个局域网内了

image.png

那么问题解决了,todo要及时up掉吗?

当然是不,摸鱼摸鱼摸鱼