docker集成nacos微服务的注册地址问题

环境说明:

docker版本:20.10.3

nacos版本:1.3,而nacos镜像是基于此版本自己制作的,并没有拉取官方的镜像。

 

如果我们的组件集成了nacos,那么服务之间的调用都是采用服务名,来进行服务间的通信。所有的服务启动的时候会向nacos注册自己的地址。我们假设有下面的服务:

服务A---pmadmin

服务B---gateway

服务C---athena

 

问题描述

 容器内的服务A在启动的时候,需要去访问服务gateway进行路由注册,结果出现连接超时,报错日志:

从日志中,看出,服务A-pmadmin 取访问 gateway,实际是先去nacos拿到了gateway的地址:10.0.0.7:65,然后通过此地址访问gateway,但是出现了连接超时,日志如下:

 

 

问题排查

确认gateway的地址

去nacos查询gateway的地址,发现确实是10.0.0.7:65,地址是没有问题,那是不是网络的问题?

 

查看docker网络

docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
52561b34842f   bridge            bridge    local
0f0904683e30   docker_gwbridge   bridge    local
3273b79adf49   host              host      local
yuggnzybujkt   iam_default       overlay   swarm
1yl193gp08xc   ingress           overlay   swarm
45c9f5d126c9   none              null      local

iam_default这个网络是我启动iam 这个stack时,自动创建的网络,我们看下这个网络中有哪些容器

docker network inspect iam_default
[
    {
        "Name": "iam_default",
        "Id": "yuggnzybujktpkkutkf0110pu",
        "Created": "2021-03-10T16:52:56.364889741+08:00",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.1.0/24",
                    "Gateway": "10.0.1.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
             ......
            "c4d4ce1fc5330d791b8fbdf2869bfc40bd64535f5ae6d5ad51531227c5c87472": {
                "Name": "iam_nacosserver.1.o8ccif1ktcaoh7pj21qnrsyql",
                "EndpointID": "076e8d35347afe3fb5980629837d2008d1d9affe138e5dcb07c1646e4f4008c1",
                "MacAddress": "02:42:0a:00:01:06",
                "IPv4Address": "10.0.1.6/24",
                "IPv6Address": ""
            },
"fae43956f124d19248d7d00dfc1be4bb615ccde82b5875c15f8ffa4193ece218": {
                "Name": "iam_gateway.1.z40ua51l1wlhrsxdol1v35o32",
                "EndpointID": "8fc8443b9f7d19d5cb4854b6424c4178dcabf92fd7a4a955fc908dafe820f859",
                "MacAddress": "02:42:0a:00:01:0c",
                "IPv4Address": "10.0.1.12/24",
                "IPv6Address": ""
            },
"lb-iam_default": {
                "Name": "iam_default-endpoint",
                "EndpointID": "f5ecad6250919d7730a3d4bb588eb2d710d673964dd839052e2d89644cbf52a6",
                "MacAddress": "02:42:0a:00:01:04",
                "IPv4Address": "10.0.1.4/24",
                "IPv6Address": ""
            }

 

注意到iam_default这个网络中的所有容器都在10.0.1.0/24这个网段中,并且里面有个gateway的地址为10.0.1.12,省略其他无关的容器详情。

问题来了,那10.0.0.7这个地址也是gateway的地址啊,这个是从nacos的页面确认的

我们知道,swarm集群正常工作需要两个overlay网络,在现在这个环境里,除了iam_default之外,还有一个ingress的网络,这个网络的主要目的是将外部流量导到我们的集群服务,也就是iam-default网络的服务。

那确认一下10.0.0.7这个地址是属于 ingress网络的。查看ingress网络中的容器地址:发现所有的容器 在 10.0.0.0/24 这个网络中

 

 docker network inspect ingress
[
    {
        "Name": "ingress",
        "Id": "1yl193gp08xc48ogm5l2qnf8q",
        "Created": "2021-03-10T16:52:56.364392994+08:00",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": true,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "344903fbfd671c51bbe4ca379a29ddcdd1b970555229caca57fdb89a8b7fe56c": {
                "Name": "iam_pmadmin.1.oqtdd8wo0rhff813a2fjjmtoq",
                "EndpointID": "f2fc565d0ceb7df1fe80a031523e324a2bef33f909d2faa5ad3f58af6f9f2f36",
                "MacAddress": "02:42:0a:00:00:c9",
                "IPv4Address": "10.0.0.201/24",
                "IPv6Address": ""
            },
          
            "c4d4ce1fc5330d791b8fbdf2869bfc40bd64535f5ae6d5ad51531227c5c87472": {
                "Name": "iam_nacosserver.1.o8ccif1ktcaoh7pj21qnrsyql",
                "EndpointID": "7582d63054303734363d7b9d8dd7d69d5a733ca31cf39b00aaafcc1968a8c5d0",
                "MacAddress": "02:42:0a:00:00:04",
                "IPv4Address": "10.0.0.4/24",
                "IPv6Address": ""
            },


            "fae43956f124d19248d7d00dfc1be4bb615ccde82b5875c15f8ffa4193ece218": {
                "Name": "iam_gateway.1.z40ua51l1wlhrsxdol1v35o32",
                "EndpointID": "0e08b11fe06750edb5252b757f464aa07dbb672976066bb69c69917b253468b3",
                "MacAddress": "02:42:0a:00:00:07",
                "IPv4Address": "10.0.0.7/24",
                "IPv6Address": ""
            },
            "ingress-sbox": {
                "Name": "ingress-endpoint",
                "EndpointID": "e0845b4d04150dfda8bb30259a2d2c9516e55b0716bdbc7c03c467e4bceb0395",
                "MacAddress": "02:42:0a:00:00:02",
                "IPv4Address": "10.0.0.2/24",
                "IPv6Address": ""
            }

 

我们确实发现了10.0.0.7这个地址是gateway的。所以,10.0.1.12和10.0.0.7是swarm网络中 不同网络的地址,也就是说nacos客户端采集的地址是ingress网络中的地址,也就是10.0.0.7这个地址。

那为什么服务A去访问服务B不通呢?难道是网络不通。

由于服务A没有启动,无法进入容器内部,我们进入此集群中另外一个容器c-athena 内部,看看这个容器的网络是什么样的情况?

cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
10.0.1.8	athena

发现athena这个服务的地址10.0.1.8 此地址恰好在iam-default这个网络中,也就是说容器里的ip地址,采用的是集群服务网络,而不是ingress网络,这也是说的通的,ingress网络主要是用来流量导向的。

 

在此容器内部,我们看下和ingress网络的联通性

# ping 10.0.0.7
PING 10.0.0.7 (10.0.0.7) 56(84) bytes of data.
64 bytes from 10.0.0.7: icmp_seq=1 ttl=64 time=0.144 ms
64 bytes from 10.0.0.7: icmp_seq=2 ttl=64 time=0.075 ms
64 bytes from 10.0.0.7: icmp_seq=3 ttl=64 time=0.080 ms
64 bytes from 10.0.0.7: icmp_seq=4 ttl=64 time=0.077 ms
^C
--- 10.0.0.7 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.075/0.094/0.144/0.028 ms

说明iam_default网络中的容器,访问ingress网络中的gateway容器地址可以联通。

那我们再ping 一下gateway,看下到底返回哪个地址

# ping gateway
PING gateway (10.0.1.12) 56(84) bytes of data.
64 bytes from iam_gateway.1.z40ua51l1wlhrsxdol1v35o32.iam_default (10.0.1.12): icmp_seq=1 ttl=64 time=0.301 ms
64 bytes from iam_gateway.1.z40ua51l1wlhrsxdol1v35o32.iam_default (10.0.1.12): icmp_seq=2 ttl=64 time=0.074 ms
64 bytes from iam_gateway.1.z40ua51l1wlhrsxdol1v35o32.iam_default (10.0.1.12): icmp_seq=3 ttl=64 time=0.065 ms
64 bytes from iam_gateway.1.z40ua51l1wlhrsxdol1v35o32.iam_default (10.0.1.12): icmp_seq=4 ttl=64 time=0.075 ms

iam_default网络中的所有地址是互通的,都是在10.0.1.0/24网络中的。gateway的地址是10.0.1.12,这也说明了,容器内部的ipvs服务也是正常工作的。

 

以上实验说明:

ingress网络和iam-default网络互通,

容器内部的地址采用的是iam-default这个集群服务网络中地址,在10.0.1.0/24网段中。

 

所以最开始的那个问题,连接超时实际是

10.0.1.0/24中的某个地址去访问10.0.0.7:65这个服务没有连接成功。

 实验

那么直接通过iam_default网络访问gateway能否成功呢?

经过实验发现,修改服务A配置,让其直接访问iam-default中gateway的地址10.0.1.12:65,

也就是说将 https://gateway/xxx改为 https://10.0.1.12:65/xxx

这样是可以正常通信的:

同样,将gateway的地址的地址改为 物理机ip也是正常启动的。

 

问题来了:

  • 容器访问ingress(10.0.0.0/24)不行,访问iam_default(10.0.1.0/24)是可以的,但是又是可以ping的,那么为什么网络互通的情况下,到了tcp协议这一层就不通了呢?

 

  • nacos客户端采集的地址是 ingress网络中的,为什么不是iam-default网络中的。

 

问题解决

查阅nacos的资料,发现可以让客户端自定义注册的地址,因为一般容器中会有多个网卡,nacos采集的地址不一定就是我们想要的那个,所以如何让客户端采集某个网卡的地址向服务器注册呢?可以参见下面的解决方案,确实解决我遇到的问题。

如何让nacos中服务注册的ip是自定义的网段ip ( docker swarm )

 

好,采用上面方法解决了问题,那遗留的问题就是为啥:同一网络中的容器互相访问的时候,通过ingress网络无法通信(即使可以ping通ingress网络中的地址),现在的猜想如下:

 

所谓的端口暴露,应该是物理机和集群网络(而不是ingress)之间的映射,容器访问ingress网络中的某个地址时,无法根据端口做转发??

 

扩展知识

在服务c-athena容器内部,查看网卡信息

# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever


37646: eth0@if37647: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
    link/ether 02:42:0a:00:01:08 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.1.8/24 brd 10.0.1.255 scope global eth0
       valid_lft forever preferred_lft forever


37658: eth2@if37659: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:13:00:08 brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet 172.19.0.8/16 brd 172.19.255.255 scope global eth2
       valid_lft forever preferred_lft forever


37680: eth1@if37681: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
    link/ether 02:42:0a:00:00:05 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 10.0.0.5/24 brd 10.0.0.255 scope global eth1
       valid_lft forever preferred_lft forev

 

eth0:10.0.1.8 ——iam_default网络

eth1: 10.0.0.5 —— ingress网络

eth2: 172.19.0.8 ——docker_gwbridge网络

 

前面两个都已经证实了,证实一下eth2网络,在主机上执行一下命令,发现,docker_gwbridge网络中的容器地址都在172.19.0.0/24网中,

docker network inspect docker_gwbridge |grep Gateway
                    "Gateway": "172.19.0.1"

所以,以上三个网卡分别对应三个网络,根据不同ip走不同的网卡,流量默认走docker_gwbridge网络

# ip route
default via 172.19.0.1 dev eth2 
10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.5 
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.8 
172.19.0.0/16 dev eth2 proto kernel scope link src 172.19.0.8

在主机上查看路由,也有三个网络,默认走ens192网卡,看到最后一个docker_gwbridge,负责172.19.0.0网段。所以容器也可以通过docker_gwbridge和主机通信。

ip route
default via 10.92.4.1 dev ens192 proto static metric 100 
10.92.4.0/24 dev ens192 proto kernel scope link src 10.92.4.126 metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
172.19.0.0/16 dev docker_gwbridge proto kernel scope link src 172.19.0.1 

更多的docker网络知识:

Docker网络实战-Overlay网络及服务发现

Docker网络-mesh routing 负载均衡

Docker网络-overlay网络驱动架构

Docker网络-网桥网络(bridge)驱动架构

https://blog.neuvector.com/article/docker-swarm-container-networking

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章