问题描述:部署在白嫖的腾讯云轻量服务器上的服务向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
执行了一下,遇到了让我很头疼的问题:
这也没有外网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了,两个服务之间就不用在同个局域网内了
那么问题解决了,todo要及时up掉吗?
当然是不,摸鱼摸鱼摸鱼