背景如上一篇文章《request.getRequestDispatcher().forward()的妙用以及DispatcherType 对Filter配置的影响》,项目要将服务从虚拟机从迁入docker中,方便自动化部署以及弹性扩容等。
闭坑一-应用看到的ip及port是docker的内部ip、端口,外部无法访问
应用看到的是docker内部ip及端口,这个是宿主机虚拟出来的,对外部不可见;如果不做任何处理,应用会拿着这个ip及docker去注册服务,导致外部调用方调用失败。
这个是所有厂商面临的问题,因此厂商一般会在docker中提供一种方法去获取宿主机的IP,以及宿主机的映射端口,比如我司就是将这两个信息写入环境变量了,应用层可以通过System.getProperties()获取,或者通过spring的Environment获取(spring会将系统变量存入Environment中)。
然后通过实现ConsulRegistrationCustomizer对consul的注册信息进行定制。
# getHostPort()、getHostIP()大家根据各自云服提供厂商的解决方案适配
public class ConsulRegistrationCustomizerForDocker implements ConsulRegistrationCustomizer
@Override
public void customize(ConsulRegistration registration) {
if (isRunningInHisDcoker()) {
registration.getService().setPort(getHostPort());
registration.getService().setAddress(getHostIP());
}
}
}
具体原理参考spring-cloud-consul-discovery自动配置的源码
org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration#consulRegistration
@Bean @ConditionalOnMissingBean public ConsulAutoRegistration consulRegistration( AutoServiceRegistrationProperties autoServiceRegistrationProperties, ConsulDiscoveryProperties properties, ApplicationContext applicationContext, ObjectProvider> registrationCustomizers, ObjectProvider
> managementRegistrationCustomizers, HeartbeatProperties heartbeatProperties) { return ConsulAutoRegistration.registration(autoServiceRegistrationProperties, properties, applicationContext, registrationCustomizers.getIfAvailable(), managementRegistrationCustomizers.getIfAvailable(), heartbeatProperties); }
org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration#registration
public static ConsulAutoRegistration registration( AutoServiceRegistrationProperties autoServiceRegistrationProperties, ConsulDiscoveryProperties properties, ApplicationContext context, List闭坑二-有时候大家会在虚拟机中配置/etc/hosts,来隔离环境的差异或者说ip的变化,如果hosts中给本机ip也配置了域名(别名,属于私有的,域名系统无法识别),因consul-discovery注册服务时,优先使用域名而不是ip;一般docker中无法去配置hosts(不会让人随便登录进去配置,而且每次重新部署docker都会重建、重新配置,不太可行),导致该域名无法识别,服务间调用不通 解决方案registrationCustomizers, List managementRegistrationCustomizers, HeartbeatProperties heartbeatProperties) { NewService service = new NewService(); String appName = getAppName(properties, context.getEnvironment()); service.setId(getInstanceId(properties, context)); # 重点关注,下面一节会用到这里 if (!properties.isPreferAgentAddress()) { service.setAddress(properties.getHostname()); } service.setName(normalizeForDns(appName)); service.setTags(createTags(properties)); service.setEnableTagOverride(properties.getEnableTagOverride()); service.setMeta(getMetadata(properties)); if (properties.getPort() != null) { service.setPort(properties.getPort()); // we know the port and can set the check setCheck(service, autoServiceRegistrationProperties, properties, context, heartbeatProperties); } ConsulAutoRegistration registration = new ConsulAutoRegistration(service, autoServiceRegistrationProperties, properties, context, heartbeatProperties, managementRegistrationCustomizers); # here,就是使用ConsulRegistrationCustomizer对注册信息进行定制 customize(registrationCustomizers, registration); return registration; }
配置pring.cloud.consul.discovery.preferAgentAddress=true
从上面代码中可以看到address的设置逻辑
if (!properties.isPreferAgentAddress()) {
service.setAddress(properties.getHostname());
}
ConsulDiscoveryProperties源码
public String getHostname() {
return this.preferIpAddress ? this.ipAddress : this.hostname;
}
public ConsulDiscoveryProperties(InetUtils inetUtils) {
this();
this.hostInfo = inetUtils.findFirstNonLoopbackHostInfo();
this.ipAddress = this.hostInfo.getIpAddress();
this.hostname = this.hostInfo.getHostname();
}



