目录

DockerDocker-network原理

Docker——Docker-network原理

摘要

当项目大规模使用 Docker 时,容器通信的问题也就产生了。要解决容器通信问题,必须先了解很多关于网络的知识。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker 同样有着很多不完善的地方,网络方面就是 Docker 比较薄弱的部分。因此,我们有必要深入了解 Docker 的网络知识,以满足更高的网络需求。

一、docker容器网络通信原理

二、docker容器网络模式

[root@localhost ~]# docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
688d1970f72e        bridge              bridge              local
885da101da7d        host                host                local
f4f1b3cf1b7f        none                null                local
常见网络模式使用命令作用业务场景
none使用–network none指定不得使用任务的网络处理一些保密数据,对一些安全考虑,需要将其隔离网络环境执行一些纯计算任务
bridge使用–network bridge指定,默认使用docker0使得容器与容器之间可以相互互通容器需要实现网络通信或者提供网络服务
host主机模式使用–network host指定让容器程序可以使用主机网络容器需要控制主机网络或者用主机网络提 供服务
container模式使用–network container:NAME或者容器ID指定将两个容器放到统一网络空间中,可以直接通过localhost访问两个容器之间需要直接通过localhost通一般用户网络

2.1 bridge网络模式

bridge网络模式是一中基于NAT模式下的网络通信方式。此驱动为Docker的默认设置驱动,使用这个驱动的时候,libnetwork将创建出来的Docker容器连接到Docker网桥上。作为最常规的模式,bridge模式已经可以满足Docker容器最基本的使用需求了。然而其与外界通信使用NAT,增加了通信的复杂性,在复杂场景下使用会有诸多限制。

在该模式中,Docker 守护进程创建了一个虚拟以太网桥 docker0 ,新建的容器会自动桥接到这个接口,附加在其上的任何网卡之间都能自动转发数据包。默认情况下,守护进程会创建一对对等虚拟设备接口 veth pair ,将其中一个接口设置为容器的 eth0 接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx 这样的名字命名,从而将宿主机上的所有容器都连接到这个内部网络上。

https://i-blog.csdnimg.cn/blog_migrate/cf9ffb2b64222fbaf50a74cc7ce3c60b.png

Bridge 桥接模式的实现步骤主要如下:

  • Docker Daemon 利用 veth pair 技术,在宿主机上创建一对对等虚拟网络接口设备,假设为 veth0 和 veth1。而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方。
  • Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。保证宿主机的网络报文可以发往 veth0;
  • Docker Daemon 将 veth1 添加到 Docker Container 所属的 namespace 下,并被改名为 eth0。如此一来,宿主机的网络报文若发往 veth0,则立即会被 Container 的 eth0 接收,实现宿主机到 Docker Container 网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性。

2.1.1 bridge 网络模式实战

运行一个基于 busybox 镜像构建的容器 bbox01,查看 ip addr:

docker run -it --name bbox01 busybox

然后宿主机通过 ip addr 查看信息如下:

ip addr

https://i-blog.csdnimg.cn/blog_migrate/4fa44ed2b7f1e15edfb1a11c6d0ee9f6.png

https://i-blog.csdnimg.cn/blog_migrate/ce49e5b5571a6651855730eed45d0c6a.png

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

同时,守护进程还会从网桥 docker0 的私有地址空间中分配一个 IP 地址和子网给该容器,并设置 docker0 的 IP 地址为容器的默认网关。也可以安装 yum install -y bridge-utils 以后,通过 brctl show 命令查看网桥信息。对于每个容器的 IP 地址和 Gateway 信息,我们可以通过 docker inspect 容器名称|ID 进行查看,在 NetworkSettings 节点中可以看到详细信息。

https://i-blog.csdnimg.cn/blog_migrate/24d48b48fde69eca060159f22723f661.png

https://i-blog.csdnimg.cn/blog_migrate/63e2564be413bd14946d15ab431b2798.png

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

https://i-blog.csdnimg.cn/blog_migrate/142c261ddc6d1d13b0eb0c08989cd7de.png

2.2 host网络模式

容器内的网络并不是希望永远跟主机是隔离的,有些基础业务需要创建或更新主机的网络配置,我们的程序必须以主机网络模式运行才能够修改主机网络,这时候就需要用到 Docker 的 host 主机网络模式。因此可以认为host驱动适用于对于容器集群规模不大的场景。

采用 host 网络模式的 Docker Container,可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换;host 网络模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性。host 网络模式需要在创建容器时通过参数 --net host 或者 --network host 指定;

https://i-blog.csdnimg.cn/blog_migrate/655e1f7d8bc0bcb0dee185eb28bf78a3.png

2.2.1 host网络模式实战

比如我基于 host 网络模式创建了一个基于 busybox 镜像构建的容器 bbox02,查看 ip addr:

docker run -it --name bbox02 --net host busybox

ip addr

https://i-blog.csdnimg.cn/blog_migrate/2f9ecda597daffd29738b85622c2d1e1.png

https://i-blog.csdnimg.cn/blog_migrate/708eb6e5fb4b14998a47a28834404e45.png

你没有看错,返回信息一模一样,我也可以肯定我没有截错图,不信接着往下看。我们可以通过 docker network inspect host 查看所有 host 网络模式下的容器,在 Containers 节点中可以看到容器名称。

https://i-blog.csdnimg.cn/blog_migrate/02a1d4123b684295df949392b5e81d53.png

2.3 none网络模式

none 网络模式即不为 Docker Container 创建任何的网络环境,容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。可以说 none 模式为 Docke Container 做了极少的网络设定,但是俗话说得好“少即是多”,在没有网络配置的情况下,作为 Docker 开发者,才能在这基础做其他无限多可能的网络定制开发。这也恰巧体现了 Docker 设计理念的开放。

有时候,我们需要处理一些保密数据,出于安全考虑,我们需要一个隔离的网络环境执行一些纯计算任务。这时候 null 网络模式就派上用场了,这时候我们的容器就像一个没有联网的电脑,处于一个相对较安全的环境,确保我们的数据不被他人从网络窃取。

2.3.1 none网络模式实战

比如我基于 none 网络模式创建了一个基于 busybox 镜像构建的容器 bbox03,查看 ip addr:

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

ip addr

https://i-blog.csdnimg.cn/blog_migrate/d42ddbcd7ed5534822d532d6d47abe58.png

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

https://i-blog.csdnimg.cn/blog_migrate/cc127ae9471b04369ac0ad1bb94f90d3.png

2.4 container网络模式

container网络模式允许一个容器共享另一个容器的网络命名空间。当两个容器需要共享网络,但其他资源仍然需要隔离时就可以使用 container 网络模式,例如我们开发了一个 http 服务,但又想使用 nginx 的一些特性,让 nginx 代理外部的请求然后转发给自己的业务,这时我们使用 container 网络模式将自己开发的服务和 nginx 服务部署到同一个网络命名空间中。Container 网络模式是 Docker 中一种较为特别的网络的模式,处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用 localhost 高效快速通信。

在创建容器时通过参数 --net container:已运行的容器名称|ID 或者 --network container:已运行的容器名称|ID 指定。 Container 网络模式即新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等 。同样两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是隔离的。

https://i-blog.csdnimg.cn/blog_migrate/71e591db869752a46dd6a7823a5c0740.png

2.4.1 container网络模式实战

比如我基于容器 bbox01 创建了 container 网络模式的容器 bbox04,查看 ip addr:

docker run -it --name bbox04 --net container:bbox01 busybbox

ip addr

https://i-blog.csdnimg.cn/blog_migrate/1af4330848aea800bfa0db85f4f5f2d3.png

https://i-blog.csdnimg.cn/blog_migrate/dfcc0f00540c5627040d9064730354e9.png

https://i-blog.csdnimg.cn/blog_migrate/9c49517cf61eaa62e63ffce7ea7cc116.png

通过以上测试可以发现,Docker 守护进程只创建了一对对等虚拟设备接口用于连接 bbox01 容器和宿主机,而 bbox04 容器则直接使用了 bbox01 容器的网卡信息。这个时候如果将 bbox01 容器停止,会发现 bbox04 容器就只剩下 lo 接口了。

https://i-blog.csdnimg.cn/blog_migrate/790f74fd0bcf09f128f9f2bf99b4c2a7.png

然后 bbox01 容器重启以后,bbox04 容器也重启一下,就又可以获取到网卡信息了。

https://i-blog.csdnimg.cn/blog_migrate/6b77a73800814498c3e0c3cbb3544e95.png

2.5 docker自定义网络模式

虽然 Docker 提供的默认网络使用比较简单,但是为了保证各容器中应用的安全性,在实际开发中更推荐使用自定义的网络进行容器管理,以及启用容器名称到 IP 地址的自动 DNS 解析。从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称进行通信。方法很简单,只要在创建容器时使用 --name 为容器命名即可。但是使用 Docker DNS 有个限制: 只能在 user-defined 网络中使用 。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。

2.5.1 docker自定义网络模式实战

通过 docker network create 命令可以创建自定义网络模式,命令提示如下:

docker netwwork --help

进一步查看 docker network create 命令使用详情,发现可以通过 --driver 指定网络模式且默认是 bridge 网络模式,提示如下:

https://i-blog.csdnimg.cn/blog_migrate/7ef3d22a1cac4036d09e8280824f7e3c.png

https://i-blog.csdnimg.cn/blog_migrate/e91a84f47912314f297a22544d151bca.png

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

docker network create custom_network

通过 docker network ls 查看网络模式:

[root@localhost ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
b3634bbd8943        bridge              bridge              local
062082493d3a        custom_network      bridge              local
885da101da7d        host                host                local
f4f1b3cf1b7f        none                null                local

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

docker run -di --name bbox05 --net custom_network busybox

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

docker inspect b356565632561d       

https://i-blog.csdnimg.cn/blog_migrate/1d3c8a8b5378446a1740ba645d526e37.png

通过 docker network connect 网络名称 容器名称 为容器连接新的网络模式。

docker network connect bridge bbox05

https://i-blog.csdnimg.cn/blog_migrate/563256d9a070d4b025b6b0fa3d89335e.png

https://i-blog.csdnimg.cn/blog_migrate/d72b8bd73e829a642623d35aba1c03dc.png

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

docker network disconnect custom_network bbox05

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

https://i-blog.csdnimg.cn/blog_migrate/d624eebb9503a359804ae86317059f03.png

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

docker network rm custom_network

注意:如果通过某个自定义网络模式创建了容器,则该网络模式无法删除。
接下来我们通过所学的知识实现容器间的网络通信。首先明确一点,容器之间要互相通信,必须要有属于同一个网络的网卡。

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

docker run -di --name default_bbox01 busybox
docker run -di --name default_bbox02 busybox

通过 docker network inspect bridge 查看两容器的具体 IP 信息。

https://i-blog.csdnimg.cn/blog_migrate/671b6d61dd2aa387344fc89dc0e6a331.png

https://i-blog.csdnimg.cn/blog_migrate/bbd1eba5dee337c566ebe160cf6c5faa.png

经过测试,从结果得知两个属于同一个网络的容器是可以进行网络通信的,但是 IP 地址可能是不固定的,有被更改的情况发生,那容器内所有通信的 IP 地址也需要进行更改,能否使用容器名称进行网络通信?继续测试。

https://i-blog.csdnimg.cn/blog_migrate/ea740355c1f088da529127839cdff7f8.png

经过测试,从结果得知使用容器进行网络通信是不行的,那怎么实现这个功能呢?

从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称通信。方法很简单,只要在创建容器时使用 --name 为容器命名即可。 但是使用 Docker DNS 有个限制: 只能在 user-defined 网络中使用 。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。 我们先基于 bridge 网络模式创建自定义网络 custom_network ,然后创建两个基于自定义网络模式的容器。

docker run -di --name custom_bbox01 --net custom_network busybox

docker run -di --name custom_bbox02 --net custom_network busybox

通过 docker network inspect custom_network 查看两容器的具体 IP 信息。

https://i-blog.csdnimg.cn/blog_migrate/f3d64efd44ba289acec9f08eef13569b.png

https://i-blog.csdnimg.cn/blog_migrate/ee84af99e6bb8935f4424cba8c9d90c8.png

三、docker容器网络命令

# 创建网络

docker network create

实例:docker network create -d bridge   my-net

# 查看查看网络列表

docker network ls

实例:docker network ls

# 查询网络的模型详细信息

docker network inspect

# 网络连接

docker network connect

# 网络断开

docker network disconnect

# 网络删除

docker network rm

# 自定义网络固定IP

docker network create --subnet=172.18.0.0/16 mynetwork

docker run -itd --name test2 --net mynetwork --ip 172.18.0.100 centos:7 /bin/bash

docker inspect 1effd1f15ef3

# 在宿主机环境执行容器内命令

docker exec -it 容器ID /bin/bash -c 'nginx'

四、docker容器网络的解决方案

docker容器内部的ip是有可能会发生改变的,如何保证容器之间的通信?

  • 容器间的互联和通信以及端口映射
  • 容器lp变动时候可以通过服务名直接网络通信而不受到影响

如果没有使用自定义网络可能出现: 按照IP地址ping是OK的,但是当服务出现宕机的时候服务iP地址发生变化,导致的服务请求的地址出现错误,导致服务不可用。

docker run -d -p 8081:8080   --name tomcat81 billygoo/tomcat8-jdk8

docker run -d -p 8082:8080   --name tomcat82 billygoo/tomcat8-jdk8

https://i-blog.csdnimg.cn/blog_migrate/011de9c6ad2f8e6e72ed20bb5f866d68.png

https://i-blog.csdnimg.cn/blog_migrate/62e3400aa8ad68a79af616d6bd8a51d1.png

https://i-blog.csdnimg.cn/blog_migrate/dc501bbc2426400be45a4953701392f3.png

https://i-blog.csdnimg.cn/blog_migrate/4fb399b259675422712ed20dbf7f191d.png

使用自定义网络解决当服务出现宕机的时候服务的IP地址发生变化,使用服务名依然可以访问。

docker run -d -p 8081:8080 --network zzyy_network  --name tomcat81 billygoo/tomcat8-jdk8

docker run -d -p 8082:8080 --network zzyy_network  --name tomcat82 billygoo/tomcat8-jdk8

https://i-blog.csdnimg.cn/blog_migrate/30eed24030eee8c005a868b4edb1ddc1.png

https://i-blog.csdnimg.cn/blog_migrate/906781f92f44874fcef5d192711bcf12.png

https://i-blog.csdnimg.cn/blog_migrate/e05fc31b7dfde02484ec788f061fe255.png

博文参考