Docker入门到精通《网络》

174 阅读11分钟

一、Docker 网络模式

Docker 网络提供了容器之间、容器与外部世界(包括宿主机和互联网)进行通信的机制。Docker 通过使用网络驱动(Network Drivers)来支持多种网络类型,每种类型都适用于不同的使用场景。

默认情况下,当你安装 Docker 后,它会自动创建三个网络。

# 列出所有网络模式
docker network ls

# 输出:
# NETWORK ID     NAME      DRIVER    SCOPE
# a1b2c3d4e5f6   bridge    bridge    local
# f1e2d3c4b5a6   host      host      local
# abcdef123456   none      null      local

二、Docker 的五大网络驱动(类型)

网络模式简介
bridge为每一个容器分配、设置 IP 等,并将容器连接到一个docker0虚拟网桥,默认为该模式。
host容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。
none容器有独立的 Network namespace,但并没有对其进行任何网络设置,如分配 veth pair 和网桥连接,IP 等。
container新创建的容器不会创建自己的网卡和配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。(不属于默认网络,但在Kubernetes中会使用到)

2.1、Bridge网络(桥接网络)

这是 默认 的网络模式。如果你不指定网络,容器就会连接到这个默认的 bridge 网络。

工作原理: Docker 会在宿主机上创建一个名为 docker0 的虚拟网桥。连接到该网络的容器会通过 veth pair(虚拟以太网设备对)连接到这个网桥。容器被分配一个私有 IP 地址,数据包通过网桥在容器之间转发,并通过宿主的 IP 地址进行 NAT 来访问外部网络。

特点:

  1. 容器之间可以通过 IP 地址通信。
  2. 默认情况下,使用容器名称无法直接通信需要通过端口映射(-p)来将容器端口暴露给宿主机外部。

关于 bridge 网络模式的使用,只需要在创建容器时通过参数 --net bridge 或者 --network bridge 指定即可,当然这也是创建容器默认使用的网络模式,也就是说这个参数是可以省略的。

演示案例:

1、运行一个基于busybox 镜像构建的容器 mybox,并查看容器的ip地址信息

docker run -it --name=mybox busybox


可以看到mybox容器有一个lo 本地回环地址 和 一个4: eth0@if5网卡

2、查看宿主机的ip地址信息
可以看到宿主机有一个lo 本地回环地址、一个ens32网卡 (即:eth0)、一个docker0网桥和一个5: vetha1025cd@if4网卡。

通过以上的比较可以发现,证实了之前所说的:守护进程会创建一对对等的虚拟设备接口 veth pair,将其中一个接口设置为容器的 eth0 接口(容器的网卡,即上图容器mybox4: eth0@if5网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx 这样的名字命名 (即:上图宿主机的5: vetha1025cd@if4网卡)。

同时,守护进程还会从网桥 docker0 的私有地址空间中分配一个 ip 地址和子网给该容器,并设置 docker0ip 地址为容器的默认网关。也可以安装 yum install -y bridge-utils 以后,通过 brctl show 命令查看网桥信息。

对于每个容器的 IP 地址和 Gateway 信息,我们可以通过 docker inspect 容器名称|ID 进行查看,在 NetworkSettings 节点中可以看到详细信息。
可以看到 Gateway网关地址为 docker0ip 地址 172.17.0.1,容器的ip地址为172.17.0.2

我们还可以通过 docker network inspect bridge 查看所有 bridge 网络模式下的容器,在 Containers 节点中可以看到容器名称。

2.2、Host网络(主机网络)

容器不会获得独立的网络命名空间,而是直接 使用宿主机的网络

工作原理:容器直接共享宿主机的网络栈(IP 地址、端口范围等)。

特点

  1. 性能最好,没有 NAT 带来的开销。
  2. 容器使用的端口直接绑定在宿主机上,容易造成端口冲突。
  3. 无法在宿主机上运行多个使用相同端口的容器。
  4. 网络隔离性最差。

演示案例:

1、运行一个基于busybox 镜像构建的容器 hostbox,并查看容器的 ip 地址信息

docker run -it --name=hostbox --net host busybox


可以看到hostbox容器有一个lo 本地回环地址、一个ens32网卡 (即:eth0) 和 一个docker0网桥

2、查看宿主机的 ip 地址信息
可以看到宿主机的ip地址信息跟上图的hostbox容器的ip地址信息是一模一样的。我们还可以通过 docker network inspect host 查看所有 host 网络模式下的容器,在 Containers 节点中可以看到容器名称。

2.3、None网络(无网络)

    None网络模式是指禁用网络功能,只有lo地址 (local 的简写),代表 127.0.0.1,即 localhost 本地回环地址。在创建容器时通过参数 --net none 或者 --network none 指定。

特点:容器完全与世隔绝,无法进行任何网络通信。

演示案例:

1.运行一个基于busybox 镜像构建的容器 nonebox,并查看容器的 ip 地址信息

docker run -it --name=nonebox --net none busybox


可以看到nonebox容器有一个lo 本地回环地址,我们还可以通过 docker network inspect none 查看所有 none 网络模式下的容器,在 Containers 节点中可以看到容器名称。

2.4、Container (容器网络模式)

Container 网络模式是 Docker 中一种较为特别的网络的模式。在创建容器时通过参数 --net container:已运行的容器名称|ID 或者 --network container:已运行的容器名称|ID 指定。

特点

  1. 处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用 localhost 高效快速通信。
  2. Container 网络模式即新创建的容器不会创建自己的网卡,配置自己的 ip,而是和一个指定的容器共享 ip、端口范围等。
  3. 两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是隔离的。

演示案例:

1、运行一个基于bridge网络模式的mybox容器创建container网络模式的容器 containerbox,并查看容器的ip地址信息

# 启动原先的mybox容器
docker start mybox

# 运行containerbox容器
docker run -it --name=containerbox --net container:mybox busybox


可以看到containerbox容器有一个lo 本地回环地址 和 一个4: eth0@if5网卡

2、查看mybox 容器的ip地址信息

docker exec -it mybox ip addr


可以看到mybox 容器的ip地址信息跟上图的containerbox容器的ip地址信息是一模一样的

3、查看宿主机的ip地址信息
通过以上测试可以发现,Docker 守护进程只创建了一对对等虚拟设备接口用于连接 mybox 容器和宿主机,而containerbox 容器则直接使用了 mybox 容器的网卡信息。

这个时候如果将mybox容器停止,会发现containerbox 容器就只剩下 lo 本地回环地址
如果mybox容器重启以后,containerbox 容器也重启一下,就又可以获取到网卡信息了

三、自定义网络

    虽然 Docker 提供的默认网络使用比较简单,但是为了保证各容器中应用的安全性,在实际开发中更推荐使用自定义的网络进行容器管理,以及启用容器名称到 ip 地址的自动 DNS 解析。

    从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称通信。方法很简单,只要在创建容器时使用 --name 为容器命名即可。

    但是使用 Docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。

3.1、创建网络

1、通过 docker network create 命令可以创建自定义网络模式,查看 docker network create 命令使用详情,发现可以通过 -d 或者 --driver 指定网络模式且默认是 bridge 网络模式,命令提示如下:

2、创建一个基于 bridge 网络模式的自定义网络模式 custom_network,完整命令如下:

docker network create custom_network
或者
docker network create -d bridge custom_network

3、通过 docker network ls 查看本地网络:

4、通过自定义网络模式 custom_network 创建容器:

docker run -di --name=custombox --net custom_network busybox

5、可以通过 docker inspect 容器名称|ID 查看容器的网络信息,在 NetworkSettings 节点中可以看到详细信息

docker inspect custombox

3.2、连接网络

1、通过 docker network connect 网络名称 容器名称 为容器连接新的网络模式,这里我们为mybox容器添加custom_network网络

docker network connect custom_network mybox

2、通过 docker inspect 容器名称|ID 查看容器的网络信息,可以看到mybox容器多增加了custom_network网络

docker inspect mybox

3.3、断开网络

1、通过 docker network disconnect 网络名称 容器名称 命令断开网络

docker network disconnect custom_network mybox

2、通过 docker inspect 容器名称|ID 再次查看容器的网络信息,发现只剩下默认的 bridge网络了

docker inspect mybox

3.4、移除网络

可以通过 docker network rm 网络名称 命令移除自定义的网络,网络移除成功则会返回自定义的网络名称

docker network rm custom_network


提示:如果某个自定义网络模式被创建的容器使用了,则该网络模式无法被删除。

三、容器间的网络通信

容器之间要想互相通信,必须要有属于同一个网络的网卡。

1、我们先创建两个基于默认的 bridge 网络模式的容器

docker run -di --name=box busybox
docker run -di --name=otherbox busybox

2、通过 docker network inspect bridge 查看两容器的具体 ip 信息


可以看到容器box的 ip 地址为172.17.0.3,容器otherboxip地址为172.17.0.4

3、然后测试两容器间是否可以进行网络通信

# 容器box ping 容器otherbox
docker exec -it box ping -c3 172.17.0.4

# 容器otherbox ping 容器box
docker exec -it otherbox ping -c3 172.17.0.3


经过测试,从结果得知两个属于同一个网络的容器是可以互相进行网络通信的,但是由于容器经常会被删除和创建,其 IP 地址经常会发生变化,是不固定的。那容器内所有通信的 IP 地址也需要进行更改,那么能否使用固定的容器名称进行网络通信呢?我们接着继续测试
经过测试,从结果得知使用容器名称进行网络通信是不行的,那怎么实现这个功能呢?

前面说过,从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称通信。方法很简单,只要在创建容器时使用 --name 为容器命名即可。

但是使用 Docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。

4、我们先基于 bridge 网络模式创建自定义网络 custom_network,然后创建两个基于custom_network自定义网络模式的容器

5、通过 docker network inspect custom_network 查看两容器的具体 ip 信息

6、然后测试两容器间是否可以通过网络名称进行网络通信,分别使用具体 ip 和容器名称进行网络通信

# 通过容器ip地址,容器custombox1 ping 容器custombox2
docker exec -it custombox1 ping -c3 172.19.0.3

# 通过容器名称,容器custombox1 ping 容器custombox2
docker exec -it custombox1 ping -c3 custombox2


经过测试,从结果得知两个属于同一个自定义网络的容器是可以进行网络通信的,并且可以使用容器名称进行网络通信。

那如果此时我希望 bridge 网络下的容器也可以和 custom_network 网络下的容器进行网络又该如何操作?其实答案也非常简单:给 bridge 网络下的容器再添加一个新的 custom_network 网络即可。

# 为容器box添加custom_network网络
docker network connect custom_network box

# 容器custombox1 ping 容器box
docker exec -it custombox1 ping -c3 box

# 容器box ping 容器custombox1
docker exec -it box ping -c3 custombox1