Docker 的(Linux/Mac OS)网络配置问题

1. Docker 网络插件(Docker’s networking subsystem is pluggable)

1.1. bridge

  1. Docker 默认设置的网络模式。
  2. Linux :
    • Docker 宿主机创建一个 docker0网卡, 随机分配一个本地未占用的私有网段,e.g: 172.17.0.1/16;
    • Docker 容器会增加一个 eth0 的网卡,随机分配同一网段: e.g 172.17.0.0/16 中的一个 ip.
    • 当 Docker 创建一个容器时,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@test: ~]# ifconfig | grep docker -A 8
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:d4ff:fe03:eab8 prefixlen 64 scopeid 0x20<link>
ether 02:42:d4:03:ea:b8 txqueuelen 0 (Ethernet)
RX packets 140626666 bytes 26229498288 (26.2 GB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 130811220 bytes 10411613754 (10.4 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

[root@test ~]# ifconfig | grep eth0 -A 7
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:42917297 errors:0 dropped:0 overruns:0 frame:0
TX packets:46190780 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3410200893 (3.1 GiB) TX bytes:9281693393 (8.6 GiB)

15604185541426

  1. Mac :
    因为实现的方式不同(见下),所以没有 docker0 网卡。

1.1.1. Linux 和 Mac 网络的区别

  1. Linux 下的网络结构:

Linux-docker-network
Docker 在 Linux 的自带内核上实现的,所以 Docker 在 Linux 上安装后, 会创建一个 docker0 的虚拟网卡,Linux 宿主机和 Docker 中的容器通过该网卡进行通信。

  1. Mac 下的网络结构:

Mac-docker-network
Docker 在 Mac 中的实现是通过 Hypervisor 创建一个轻量级的虚拟机,然后 将 docker 放入到虚拟机中实现。Mac OS 宿主机和 Docker 中的容器通过 /var/run/docker.sock 这种 socket 文件来通信,所以在 Mac OS 中 ping 容器的 IP,在容器中 ping 宿主机的 IP 就不通。

1.2. host :

  1. 直接使用宿主机的 IP 地址,最简单,但是容器跟宿主机共享,直接对外暴露,安全性低。
  2. Docker 17.06+ 支持。
  3. 仅支持 Linux。

1.3. overlay :

  1. docker 自带的跨主机网络模型

1.4. macvlan :

  1. macvlan 网卡虚拟化技术,可以在一张物理网卡上配置多个 MAC 地址,对应多个 interfaces,每个 interface 一个ip。优点是性能极好,不需要创建Linux bridge,而是直接通过interface连接到物理网络。
  2. Docker 中,可以为每个容器分配一个 MAC 地址,直接通过 MAC 地址转发数据。
  3. 需要考虑网络性能时,或者希望应用直接通过 物理网卡连接到网络时可以使用。

1.5. none :

  1. 禁用网络配置,通常是在使用第三方网络配置插件时设置。

1.6. Network plugins : 插件

  1. 从 Docker Hub hove 第三方获取

2. Docker 在 Mac 中的两种实现方式

  1. docker 在 Mac 中有两种实现,一种是基于 HyperKit (Docker Desktop for Mac),另一种是基于Virtual Box(Docker Toolbox).
  2. 两者的区别会导致宿主机和容器直接网络访问方式不同,Docker Desktop for Mac 是基于 /var/run/docker.sock 文件。Docker Toolbox 是基于虚拟网卡。还有就是管理容器的方式不一样, Docker Desktop for Mac 是使用 HyperKit, 基于 Hypervisor 的轻量级虚拟化机;Docker Toolbox 则是使用 Virtual Box 创建虚拟机的方式来创建容器。

2.1. Docker Desktop for Mac

2.1.1. 1. 宿主机和容器的端口映射

docker run -p HOST_PORT:CLIENT_PORT xxxxx
e.g : doker run -p 80:80 -d nginx

2.1.2. 2. Mac OS 中的限制

  1. 没有 docker0 bridge 网卡。
  2. 宿主机不能 ping 通容器的ip,宿主机
  3. 不能从主机 Mac 访问 Linux bridge.

2.1.3. 3. mac 宿主机 和 容器互通 的解决方案

  1. 容器内访问宿主机,在 Docker 18.03 过后推荐使用 特殊的 DNS 记录 host.docker.internal 访问宿主机。但是注意,这个只是在 Docker Desktop for Mac 中作为开发时有效。 网关的 DNS 记录: gateway.docker.internal。

  2. 宿主机访问容器,使用本机 localhost 端口映射功能,使用 –publish(单个端口), -p(单个端口), -P(所有端口) 将本机的端口和容器的端口映射。

  3. 宿主机访问容器,使用 -p 参数映射端口。容器访问宿主机,可以在宿主机使用下面的命令获取 宿主机的 ip 地址:

    1
    ps -ef | grep -i docker | grep -i  "\-\-host\-ip" |awk -F "host-ip" '{print $2}' | awk -F '--lowest-ip' '{print $1}'
    • 在宿主机的 mac 上查看 docker deamon的进程,可以找到启动的配置参数如下
      docker-deamon-on-mac

    • 从进程中可以提取到宿主机的 ip 地址,这个 ip 地址的网段在 Docker for Mac –> Preferences – > Advanced –> Docker subnet 中配置。

    • 可以在容器中安装 Rinetd 来转发本地的 socket 请求到宿主机。

      • CentOS 安装

        • 添加第三方 64 位源:

          1
          2
          3
          4
          5
          6
          7
          8
          echo "
          [nux-misc]
          name=Nux Misc
          baseurl=http://li.nux.ro/download/nux/misc/el6/x86_64/
          enabled=0
          gpgcheck=1
          gpgkey=http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
          " > /etc/yum.repos.d/nux-misc.repo
        • 安装 : yum –enablerepo=nux-misc install rinetd

      • Ubuntu 安装

        • apt-get install rinetd
      • 编译安装

        • 执行下面的命令:
          cd ~
          wget http://www.boutell.com/rinetd/http/rinetd.tar.gz
          tar zxvf rinetd.tar.gz
          cd rinetd
          mkdir -p /usr/man/man8
          make && make install
      • 配置 : vi /etc/rinetd.conf

        #### [bindaddress] [bindport] [connectaddress] [connectport]
        #### 绑定的地址       绑定的端口  连接的地址      连接的端口
        #### [Source Address] [Source Port] [Destination Address] [Destination Port]
        #### 源地址            源端口         目的地址               目的端口
        0.0.0.0 8080 172.19.94.3 8080
        0.0.0.0 2222 192.168.0.103 3389
        1.2.3.4 80 192.168.0.10 80
        allow *.*.*.*
        logfile /var/log/rinetd.log
      • 启动: rinetd start

      • 关闭: rinetd stop

      • 查看帮助: rinetd -h

  4. 如果以上方案都不OK,那就用 Docker Toolbox

2.2. Docker Toolbox

目的是为了适配老版本的 Mac OS 和 Windows,实现方式和 Docker Desktop for Mac 不同。

Just for my love !!