在宿主机上执行 ifconfig,可以看到一个 docker0 的虚拟网桥。

  1. $ ifconfig
  2. docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
  3. inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
  4. inet6 fe80::42:52ff:fe31:9057 prefixlen 64 scopeid 0x20<link>
  5. ether 02:42:52:31:90:57 txqueuelen 0 (Ethernet)
  6. RX packets 8 bytes 536 (536.0 B)
  7. RX errors 0 dropped 0 overruns 0 frame 0
  8. TX packets 30 bytes 3054 (2.9 KiB)
  9. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

如果没有 ifconfig 命令,使用以下命令安装:

  1. $ yum install net-tools.x86_64 -y

安装网桥管理程序

  1. $ yum install bridge-utils
  2. # or
  3. $ apt-get install bridge-utils

先运行一个容器,查看网桥设备状态

  1. $ brctl show
  2. bridge name bridge id STP enabled interfaces
  3. docker0 8000.024252319057 no veth7bfa1b9
  4. virbr0 8000.525400e0956a yes virbr0-nic

可以看到在 docker0 的网桥设备上连接了一个 interface,使用 ifconfig 可以看到:

  1. $ ifconfig
  2. veth7bfa1b9: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
  3. inet6 fe80::80bd:9fff:feb7:e5 prefixlen 64 scopeid 0x20<link>
  4. ether 82:bd:9f:b7:00:e5 txqueuelen 0 (Ethernet)
  5. RX packets 8 bytes 648 (648.0 B)
  6. RX errors 0 dropped 0 overruns 0 frame 0
  7. TX packets 38 bytes 3702 (3.6 KiB)
  8. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

网桥配置

修改 docker 网桥配置

  1. $ ifconfig docker0 192.168.40.100 netmask 255.255.255.0
  2. $ systemctl reload docker # 重启docker服务生效

添加 docker 虚拟网桥

  1. $ brctl addbr br0
  2. $ ifconfig br0 192.168.100.1 netmask 255.255.255.0

然后编辑 docker 配置文件,添加如下信息:

  1. $ vim /etc/docker/daemon.json
  2. {
  3. "bridge": "br0"
  4. }

然后重启 docker,启动一个容器并进入:

  1. $ systemctl restart docker
  2. $ docker start -i server2

进入容器,可以看到已经分配了新的网桥给 docker:

  1. root@c096b413dc42:/# ifconfig
  2. eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
  3. inet 192.168.100.2 netmask 255.255.255.0 broadcast 0.0.0.0
  4. inet6 fe80::42:c0ff:fea8:6402 prefixlen 64 scopeid 0x20<link>
  5. ether 02:42:c0:a8:64:02 txqueuelen 0 (Ethernet)
  6. RX packets 8 bytes 648 (648.0 B)
  7. RX errors 0 dropped 0 overruns 0 frame 0
  8. TX packets 8 bytes 648 (648.0 B)
  9. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

:::warning 使用网桥管理工具创建的网桥会在下次物理机重启时失效。可以通过直接修改网桥配置文件达到重启不失效的目的。 :::

解决方案如下,创建一个网络配置文件:

$ vim /etc/sysconfig/network-scripts/ifcfg-br0
IPADDR=192.168.1.1
TYPE=Bridge
BOOTPROTO=static
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
#IPV6INIT=yes
#IPV6_AUTOCONF=yes
#IPV6_DEFROUTE=yes
#IPV6_PEERDNS=yes
#IPV6_PEERROUTES=yes
#IPV6_FAILURE_FATAL=no
#NAME=eno16777736
#UUID=d0d3289e-9c2c-45f7-a569-c55aca9f0e8a
DEVICE=br0
ONBOOT=yes

重启网络服务,并配置网桥ip及子网掩码

$ service network restart
Restarting network (via systemctl):                        [  确定  ]
$ ifconfig br0 192.168.1.1 netmask 255.255.255.0

参考:centos 7.2 网卡配置文件 及 linux bridge的静态配置

容器互联

默认情况下,docker并不会阻止容器之间的通讯,容器之间可以通过ip相互进行访问。

但是,如果重启docker服务,ip会发生改变,如果是提供服务的容器,使用之前的ip就不能进行访问了,因此使用ip进行通讯的方式并不可靠。

因此,在运行容器时,可以使用 --link 参数来指定连接的容器,而不必担心ip地址的变化。

$ docker run --link=[CONTAINER_NAME]:[ALIAS] [IMAGE] [COMMOND]

首先创建一个 Dockerfile:

FROM ubuntu:latest
RUN apt-get update -y
RUN apt-get upgrade -y
RUN apt-get install -y ping
RUN apt-get install -y nginx
RUN apt-get install -y curl
EXPOSE 80
CMD /bin/bash

执行此 Dockerfile 进行镜像构建:

$ docker build -t test/ubuntu:1.0 .

然后通过这个镜像创建一个容器:cct1。

使用 link 选项关联两个容器:

$ docker run -it --name cct2 --link=cct1:webtest test/ubuntu:1.0

进入 cct2,使用 ping 命令检查两个容器的互通性:

root@1d8c06b3dc25:$ ping webtest

注意到使用的是cct1容器的别名,发现网络是通畅的。

查看 /etc/hosts 文件,会发现虚拟主机 webtest 已经自动加上了。使用 env 命令也可看到很多关于 WEBTEST 的环境变量。

使用 docker restart cct1 cct2 重新启动容器,会发现 ping webtest 依然生效,而检查 /etc/hosts 文件会发现ip已经发生了改变,说明容器间通信不是基于 ip 的。

Docker 跨主机连接: 使用网桥

📃 深入阅读:Docker网络 - 图1

原理:在两台主机上,配置可相互通讯的网桥,将不同主机中 Docker 的网桥连接到此网桥。

Docker 跨主机连接: 使用 Open vSwitch

实验环境:两台虚拟机 (centOS)

A主机:

  • 宿主机IP :192.168.42.130
  • Docker 容器中 IP : 192.168.1.2
  • Docker 容器连接的网桥地址(br0) : 192.168.1.1

B主机:

  • 宿主机IP :192.168.42.131
  • Docker 容器中 IP : 192.168.2.2
  • Docker 容器连接的网桥地址(br0) : 192.168.2.1

使两部虚拟机中的 docker 能互通。

什么是 Open VSwitch

ovs (Open VSwitch) 是一个高质量、多层虚拟交换机,使用开源Apache2.0许可协议,由 Nicira Networks 开发,主要实现代码为可移植的 C 代码。它的目的是让大规模网络自动化可以通过编程扩展,同时仍然支持标准的管理接口和协议(例如 NetFlow,SFlow,SPAN,RSPAN,CLI,LACP,802.lag)
📃 深入阅读:Docker网络 - 图2

什么是 GRE 隧道

GRE:通用路由协议封装。

隧道技术(Tunneling)是一种通过使用互联网络的基础设施在网络之间传递数据的方式。使用隧道传递的数据(或负载)可以是不同协议的数据帧或包。隧道协议将其它协议的数据帧或包重新封裝然后通过隧道发送。新的帧头提供路由信息,以便通过互联网传递被封装的负载数据。

使用 ovs 实现跨主机通讯

安装

$ apt-get install openvswitch-switch
// or
$ yum install openvswitch

检测安装

$ ovs-vsctl show
fdbecc9f-193a-45c0-b1b7-599d53e22df9
    ovs_version: "2.10.1"

A主机中的配置:

添加 ovs 网桥 obr0

$ ovs-vsctl add-br obr0

为 obr0 添加接口 gre0

$ ovs-vsctl add-port obr0 gre0
ovs-vsctl: Error detected while setting up 'gre0': could not add network device gre0 to ofproto (Invalid argument).  See ovs-vswitchd log for details.
ovs-vsctl: The default log directory is "/usr/local/var/log/openvswitch".

$ ovs-vsctl show
fdbecc9f-193a-45c0-b1b7-599d53e22df9
    Bridge "obr0"
        Port "gre0"
            Interface "gre0"
                error: "could not add network device gre0 to ofproto (Invalid argument)"
        Port "obr0"
            Interface "obr0"
                type: internal
    ovs_version: "2.10.1"

设置接口类型

$ ovs-vsctl set interface gre0 type=gre options:remote_ip=192.168.42.131

$ ovs-vsctl show
fdbecc9f-193a-45c0-b1b7-599d53e22df9
    Bridge "obr0"
        Port "gre0"
            Interface "gre0"
                type: gre
                options: {remote_ip="192.168.42.131"}
        Port "obr0"
            Interface "obr0"
                type: internal
    ovs_version: "2.10.1"

使用网桥管理工具在物理机新建一个 br0 的网桥,并设置其 ip

$ brctl addbr br0
$ ifconfig br0 192.168.1.1 netmask 255.255.255.0

为 br0 网桥添加 ovs 网桥的连接

$ brctl addif br0 obr0
$ brctl show
bridge name    bridge id        STP enabled    interfaces
br0        8000.aed32285704b    no        obr0
docker0        8000.0242a6aa2d07    no
virbr0        8000.525400e0956a    yes        virbr0-nic

在 docker 配置文件 /etc/docker/daemon.json 中添加:

{
  "bridge": "br0"
}

重启 docker 服务:

$ systemctl restart docker

启动容器,进行连通性测试:

$ docker start -i centos
[root@ab6398eaa692 /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.2  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::42:c0ff:fea8:102  prefixlen 64  scopeid 0x20<link>
        ether 02:42:c0:a8:01:02  txqueuelen 0  (Ethernet)
        RX packets 17  bytes 1947 (1.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6  bytes 508 (508.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@ab6398eaa692 /]# ping 192.168.42.131
PING 192.168.42.131 (192.168.42.131) 56(84) bytes of data.
64 bytes from 192.168.42.131: icmp_seq=1 ttl=63 time=0.298 ms
64 bytes from 192.168.42.131: icmp_seq=2 ttl=63 time=0.310 ms
64 bytes from 192.168.42.131: icmp_seq=3 ttl=63 time=0.331 ms
^C
--- 192.168.42.131 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.298/0.313/0.331/0.013 ms

可以看到,进入容器使用 ping 命令连接另一台虚拟主机成功。

同样的步骤,在另一台虚拟机(B主机)中进行相同的配置:

$ ifconfig br0 192.168.2.1 netmask 255.255.255.0
$ ovs-vsctl set interface gre0 type=gre options:remote_ip=192.168.42.130
$ brctl addif br0 obr0

除此之外,还需要在两部虚拟机的路由表中相互配置对方的docker网段:

先查看路由表:

[root@node1 docker]# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         gateway         0.0.0.0         UG    100    0        0 ens33
192.168.1.0     0.0.0.0         255.255.255.0   U     425    0        0 br0
192.168.42.0    0.0.0.0         255.255.255.0   U     100    0        0 ens33
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0
# A 主机
$ ip route add 192.168.2.0/24 via 192.168.42.131 dev ens33

# B 主机
$ ip route add 192.168.1.0/24 via 192.168.42.130 dev ens33

使用 route 命令查看路由表,可以看到相关配置已经在路由表中了。

$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         gateway         0.0.0.0         UG    100    0        0 ens33
192.168.1.0     0.0.0.0         255.255.255.0   U     425    0        0 br0
192.168.2.0     192.168.42.131  255.255.255.0   UG    0      0        0 ens33
192.168.42.0    0.0.0.0         255.255.255.0   U     100    0        0 ens33
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0

这时,即可实现两台虚拟主机中的 docker 互通。

# A主机中的 docker
[root@ab6398eaa692 /]# ping 192.168.2.2
PING 192.168.2.2 (192.168.2.2) 56(84) bytes of data.
64 bytes from 192.168.2.2: icmp_seq=1 ttl=62 time=0.400 ms
64 bytes from 192.168.2.2: icmp_seq=2 ttl=62 time=1.15 ms
^C
--- 192.168.2.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.400/0.775/1.150/0.375 ms


# B主机中的 docker
[root@ab6398eaa692 /]# ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=62 time=0.299 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=62 time=0.338 ms
^C
--- 192.168.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.299/0.318/0.338/0.026 ms

错误解决

ovs-vsctl: unix:/usr/local/var/run/openvswitch/db.sock: database connection failed 解决方案

$ ovsdb-server  --remote=punix:/usr/local/var/run/openvswitch/db.sock \
                --remote=db:Open_vSwitch,Open_vSwitch,manager_options \
                --private-key=db:Open_vSwitch,SSL,private_key \
                --certificate=db:Open_vSwitch,SSL,certificate \
                --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \
                --pidfile --detach
$ ovs-vsctl --no-wait init
$ ovs-vswitchd --pidfile --detach

编写脚本,使其开机自启:

/root/autorun.sh

#!/bin/bash
ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock --remote=db:Open_vSwitch,Open_vSwitch,manager_options --pidfile --detach
ovs-vsctl --no-wait init
ovs-vswitchd --pidfile --detach --log-file

修改其权限

$ chmod 777 autorun.sh

将其添加到开机自启列表,把路径添加到 /etc/rc.d/rc.local

source /root/autorun.sh

Docker 跨主机连接: 使用 weave

参考资料