重写Nacos服务发现逻辑动态修改远程服务IP地址

背景

还是先说下做这个的背景,开发环境上了K8S,所有的微服务都注册在K8S内的Nacos,注册地址为K8S内部虚拟IP,K8S内的服务之间相互调用没有问题,但是本机开发联调调用其他微服务就访问不到。

 

解决方案

1、KT Connect,可以理解为一个VPN工具,可以和K8S网络联通,缺点是配置繁琐,每次开发都需要启动KT Connect程序;

2、配置Ribbon的listOfServers,配置如下:

<nacosServiceName>.ribbon.listOfServers=<ip:port>

3、Nacos Client从Nacos Server获取服务列表时,修改远程服务对应的IP地址。

 

重写NacosNamingService

1、看了下nacos-client源码,发现有个NacosNamingService类,主要是服务发现的实现类,可以从这里入手修改远程服务注册IP;

2、NacosNamingService是在NacosDiscoveryClientAutoConfiguration通过注入NacosDiscoveryProperties初始化的,具体源码如下:

@Bean
@ConditionalOnMissingBean
public NacosDiscoveryProperties nacosProperties() {
    return new NacosDiscoveryProperties();
}

3、跟踪到NacosDiscoveryProperties,初始化NacosNamingService的核心代码如下:

    public NamingService namingServiceInstance() {
        if (null != this.namingService) {
            return this.namingService;
        } else {
            Properties properties = new Properties();
            properties.put("serverAddr", this.serverAddr);
            properties.put("namespace", this.namespace);
            properties.put("com.alibaba.nacos.naming.log.filename", this.logName);
            if (this.endpoint.contains(":")) {
                int index = this.endpoint.indexOf(":");
                properties.put("endpoint", this.endpoint.substring(0, index));
                properties.put("endpointPort", this.endpoint.substring(index + 1));
            } else {
                properties.put("endpoint", this.endpoint);
            }

            properties.put("accessKey", this.accessKey);
            properties.put("secretKey", this.secretKey);
            properties.put("clusterName", this.clusterName);
            properties.put("namingLoadCacheAtStart", this.namingLoadCacheAtStart);

            try {
                this.namingService = NacosFactory.createNamingService(properties);
            } catch (Exception var3) {
                log.error("create naming service error!properties={},e=,", this, var3);
                return null;
            }

            return this.namingService;
        }
    }

4、我们直接重新namingServiceInstance方法就可以了,具体实现代码如下:

@Slf4j
@Configuration
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(
        name = {"spring.profiles.active"},
        havingValue = "dev"
)
@AutoConfigureBefore({NacosDiscoveryClientAutoConfiguration.class})
public class DevEnvironmentNacosDiscoveryClient {

    @Bean
    @ConditionalOnMissingBean
    public NacosDiscoveryProperties nacosProperties() {
        return new DevEnvironmentNacosDiscoveryProperties();
    }

    static class DevEnvironmentNacosDiscoveryProperties extends NacosDiscoveryProperties {

        private NamingService namingService;

        @Override
        public NamingService namingServiceInstance() {
            if (null != this.namingService) {
                return this.namingService;
            } else {
                Properties properties = new Properties();
                properties.put("serverAddr", super.getServerAddr());
                properties.put("namespace", super.getNamespace());
                properties.put("com.alibaba.nacos.naming.log.filename", super.getLogName());
                if (super.getEndpoint().contains(":")) {
                    int index = super.getEndpoint().indexOf(":");
                    properties.put("endpoint", super.getEndpoint().substring(0, index));
                    properties.put("endpointPort", super.getEndpoint().substring(index + 1));
                } else {
                    properties.put("endpoint", super.getEndpoint());
                }

                properties.put("accessKey", super.getAccessKey());
                properties.put("secretKey", super.getSecretKey());
                properties.put("clusterName", super.getClusterName());
                properties.put("namingLoadCacheAtStart", super.getNamingLoadCacheAtStart());

                try {
                    this.namingService = new DevEnvironmentNacosNamingService(properties);
                } catch (Exception var3) {
                    log.error("create naming service error!properties={},e=,", this, var3);
                    return null;
                }

                return this.namingService;
            }
        }

    }

    static class DevEnvironmentNacosNamingService extends NacosNamingService {

        public DevEnvironmentNacosNamingService(Properties properties) {
            super(properties);
        }

        @Override
        public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy) throws NacosException {
            List<Instance> instances = super.selectInstances(serviceName, clusters, healthy);
            instances.stream().forEach(instance -> instance.setIp("10.101.232.24"));
            return instances;
        }
    }

}

 

posted @ 2021-04-08 15:38  codest  阅读(2565)  评论(0编辑  收藏  举报