基于多网卡环境下Eureka服务注册IP的选择问题

作者:取个昵称好难啊Elaine 时间:2022-09-16 17:59:15 

多网卡环境下Eureka服务注册IP选择

问题场景

服务器上分别配置了eth0和eth1两块网卡,只有eth1的地址可供其它机器访问,在这种情况下,服务注册时Eureka Client会自动选择eth0作为服务ip, 导致其它服务无法调用。

问题原因

由于官方并没有写明Eureka Client探测本机IP的逻辑,所以只能翻阅源代码。Eureka Client的源码在eureka-client模块下,com.netflix.appinfo包下的InstanceInfo类封装了本机信息,其中就包括了IP地址。在

Spring Cloud 环境下,Eureka Client并没有自己实现探测本机IP的逻辑,而是交给Spring的InetUtils工具类的findFirstNonLoopbackAddress()方法完成的:

public InetAddress findFirstNonLoopbackAddress() {
        InetAddress result = null;
        try {
            // 记录网卡最小索引
            int lowest = Integer.MAX_VALUE;
            // 获取所有网卡
            for (Enumeration<NetworkInterface> nics = NetworkInterface
                    .getNetworkInterfaces(); nics.hasMoreElements();) {
                NetworkInterface ifc = nics.nextElement();
                if (ifc.isUp()) {
                    log.trace("Testing interface: " + ifc.getDisplayName());
                    if (ifc.getIndex() < lowest || result == null) {
                        lowest = ifc.getIndex(); // 记录索引
                    }
                    else if (result != null) {
                        continue;
                    }
 
                    // @formatter:off
                    if (!ignoreInterface(ifc.getDisplayName())) { // 是否是被忽略的网卡
                        for (Enumeration<InetAddress> addrs = ifc
                                .getInetAddresses(); addrs.hasMoreElements();) {
                            InetAddress address = addrs.nextElement();
                            if (address instanceof Inet4Address
                                    && !address.isLoopbackAddress()
                                    && !ignoreAddress(address)) {
                                log.trace("Found non-loopback interface: "
                                        + ifc.getDisplayName());
                                result = address;
                            }
                        }
                    }
                    // @formatter:on
                }
            }
        }
        catch (IOException ex) {
            log.error("Cannot get first non-loopback address", ex);
        }
 
        if (result != null) {
            return result;
        }
 
        try {
            return InetAddress.getLocalHost(); // 如果以上逻辑都没有找到合适的网卡,则使用JDK的InetAddress.getLocalhost()
        }
        catch (UnknownHostException e) {
            log.warn("Unable to retrieve localhost");
        } 
        return null;
    }

通过源码可以看出,该工具类会获取所有网卡,依次进行遍历,取ip地址合理、索引值最小、已经启动且不在忽略列表的网卡的ip地址作为结果。如果仍然没有找到合适的IP, 那么就将InetAddress.getLocalHost()做为最后的fallback方案。

解决方案

A.忽略指定网卡

spring.cloud.inetutils.gnored-interfaces[0]=eth0 # 忽略eth0, 支持正则表达式

因通过配置application.properties让应用忽略无效的网卡。

B.配置host

当网查遍历逻辑都没有找到合适ip时会走JDK的InetAddress.getLocalHost()。该方法会返回当前主机的hostname, 然后会根据hostname解析出对应的ip。因此第二种方案就是配置本机的hostname和/etc/hosts文件,直接将本机的主机名映射到有效IP地址。

C.手工指定IP

# 指定此实例的ip
eureka.instance.ip-address=
# 注册时使用ip而不是主机名
eureka.instance.prefer-ip-address=true

D.启动时指定IP

java -jar -Dspring.cloud.inetutils.preferred-networks=192.168.20.123

E.禁用eth0

查看网卡的连接信息

[root@localhost ~]# nmcli con sh
NAME         UUID                                  TYPE            DEVICE 
System eth0  5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03  802-3-ethernet  eth0   

禁用eth0

[root@localhost ~]# ifdown eth0
Device 'eth0' successfully disconnected.

启用eth0

[root@localhost ~]# ifup eth0

Eureka中使用IP注册服务

在将微服务放入docker部署在多个云服务器上的时候,发现eureka里显示的是机器名,然后弄了个spring boot admin监控平台,发现它就找不到各个微服务对应的主机了。

在网上查得eureka.instance.prefer-ip-address=true,使用这条配置eureka里显示的就是ip地址了,但是依然不够的,在监控平台里面还是连接不上。

还需要配置instance-和hostname才能使客户端访问到实例

效果应该是这样,点击ip后能访问到相应内容

基于多网卡环境下Eureka服务注册IP的选择问题

eureka服务端配置

server.port=8666
spring.application.name=eureka-server
#服务注册中心实例的主机名
eureka.instance.hostname=xxx.xxx.xxx.67
#留存的服务示例低于多少比例进入保护模式
eureka.server.renewal-percent-threshold=0.5
#是否开启保护模式
eureka.server.enable-self-preservation=true
#是否向服务注册中心注册自己
eureka.client.register-with-eureka=false
#是否启用获取服务注册信息,因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,故而设为false
eureka.client.fetch-registry=false
#注册和查询都需要依赖该地址,多个以逗号分隔
eureka.client.serviceUrl.defaultZone=http://admin:password@xxx.xxx.xxx.67:8666/eureka/
#使用ip替代实例名
eureka.instance.prefer-ip-address=true
#设置实例的ID为ip:port
eureka.instance.instance-id=xxx.xxx.xxx.67:${server.port}
#这里使用spring security对注册中心做一个基础的用户名密码登录
security.basic.enabled=true
security.user.name=admin
security.user.password=password

注意到:

eureka.instance.hostname=xxx.xxx.xxx.67
eureka.instance.instance-id=xxx.xxx.xxx.67:${server.port}

这里我直接手工指定了ip,而不是通过${spring.cloud.client.ipAddress}来获取本机的ip,因为使用docker后,发现获取的ip是docker0这张网卡上分配的ip,以172.16.xxx.xxx开头的ip,要使docker绑定外网ip网上也有很多资料,这里先简化操作,就直接手工指定ip了哈。。

客户端配置

eureka.client.service-url.defaultZone=http://admin:password@xxx.xxx.xxx.67:8666/eureka/
eureka.instance.lease-renewal-interval-in-seconds=5
eureka.instance.lease-expiration-duration-in-seconds=10
eureka.client.healthcheck.enable=true
eureka.instance.hostname=xxx.xxx.xxx.67
#设置实例的ID为ip:port
eureka.instance.instance-id=xxx.xxx.xxx.67:${server.port}

注意客户端也要写上eureka.instance.instance-id和eureka.instance.hostname

这样在eureka上就显示的是ip地址了

要使spring boot admin正常工作,还需在spring boot admin上配置

admin服务端配置

spring.application.name=admin-monitor
server.port=7001
#为了安全,以后可以把管理端口设置一下
#management.port=7002
#现在测试环境就关闭了身份认证,真实环境还是需要它的
management.security.enabled=false

客户端配置

#关闭身份认证,以免发生401错误
management.security.enabled=false
#admin监控配置,连接到服务端
spring.boot.admin.url=http://xxx.xxx.xxx.96:7001
#在spring boot admin里以ip的形式注册显示
spring.boot.admin.client.prefer-ip=true

这里比较关键的一步就是在客户端里配置spring.boot.admin.client.prefer-ip=true,这样spring boot admin就能通过ip来访问各个微服务端点,然后收集它们的信息,从而来监控各个微服务了

来源:https://blog.csdn.net/dickysun1987/article/details/83414147

标签:多网卡环境,Eureka,注册IP
0
投稿

猜你喜欢

  • 详解c# 深克隆与浅克隆

    2023-09-06 18:00:07
  • 安卓模拟器genymotion的安装与使用图文教程

    2021-12-13 19:28:36
  • javascript最新2020经典面试题

    2023-05-15 09:04:43
  • SpringBoot 导出数据生成excel文件返回方式

    2023-09-01 11:29:27
  • Android Room数据库多表查询的使用实例

    2022-11-07 02:49:49
  • Java使用DFA算法实现敏感词过滤的示例代码

    2022-10-21 00:56:13
  • 1秒钟实现Springboot 替换/写入 word文档里面的文字、图片功能

    2022-05-08 18:35:48
  • Android实现倒计时的按钮的示例代码

    2021-10-17 14:45:11
  • Android kotlin使用注解实现防按钮连点功能的示例

    2023-07-02 11:58:06
  • mybatis 对于生成的sql语句 自动加上单引号的情况详解

    2023-09-21 15:25:00
  • Maven 配置文件 生命周期 常用命令详解

    2022-07-05 19:59:39
  • 在C#中创建和读取XML文件的实现方法

    2021-12-20 08:10:45
  • Java 数据结构深入理解ArrayList与顺序表

    2023-02-15 14:24:07
  • springmvc+shiro+maven 实现登录认证与权限授权管理

    2023-07-04 14:33:03
  • SpringMVC Restful api接口实现的代码

    2023-11-29 12:34:27
  • java开发之内部类的用法

    2023-02-04 21:30:07
  • Java 定时器的多种实现方式

    2021-06-14 03:15:09
  • Android基于ViewPager实现的应用欢迎界面完整实例

    2021-10-02 23:01:52
  • SpringBoot中利用AOP和拦截器实现自定义注解

    2022-09-14 00:26:53
  • 对C# 多态的理解

    2022-10-17 02:37:26
  • asp之家 软件编程 m.aspxhome.com