通信场景

本章我们继续讲解docker网络驱动,在学习docker网络驱动之前我们先思考下面几个docker容器之间常见的通信场景:

1、同一dockerd守护进程内容器和容器之间如何通信

2、同一dockerd守护进程容器和主机其它服务进程之间如何通信

3、不同dockerd守护进程容器和容器之间如何通信

4、不同dockerd守护进程容器之间如何通信

回顾我们前面章节的myhelloworld例子,myhelloworld可以正常通过容器名称访问到myredis,这正是docker网络驱动发挥的作用。在讲解compose章节时我们似乎并没有手动配置过网络,而是compose帮我们配置好了。本章着重讲解网络驱动,接下来我们自己手动来管理和配置网络驱动。

网络模式

docker可以通过创建虚拟网卡,通过虚拟网卡转发到宿主机网卡和外部进行通信。除此之外,也可以不创建自己的虚拟网卡而是直接和宿主机共用网卡直接占用宿主机IP和端口的方式和外部进行通信。docker的网络驱动是可插拔的,默认情况下存在以下几种网络模式:

1、桥接网络模式(bridge): 这是docker默认的网络驱动程序,如果在创建驱动程序时未指定驱动程序类型,默认便是bridge模式。当你的应用程序是在同一个主机部署独立容器时,推荐使用桥接网络模式。连接到同一桥接网络的容器可以互相通信,对不同桥接网络的容器则无法直接相互通信。

2、覆盖网络模式(overlay):覆盖网络模式可以将不同的Dockerd守护进程连接在一起,该网络模式支持集群容器之间相互通信,以及集群和某个单机版独立容器直接相互通信,或不同Dockerd守护进程的独立容器之间进行通信。该网络模式使用场景比较广泛,通常集群部署时会使用该模式。

3、主机网络模式(host):如果某个容器需要访问主机的某个服务,那么需要配置主机网络模式,该模式直接占用主机的网络端口和网卡资源。也就是说docker网络并非隔离而是直接和宿主机共享资源,就好像应用是直接在宿主机上运行一样。但是其它(例如存储,进程命名空间和用户命名空间)相对宿主机隔离的。该模式仅适用于Docker 17.06及更高版本的swarm服务。

4、MAC网络模式(macvlan):Macvlan网络允许您为容器分配MAC地址,使其显示为网络上的物理设备。Docker守护程序通过其MAC地址将流量路由到容器。macvlan 使用场景在于如果希望直接连接到物理网络时,使用驱动程序有时是最佳选择,而不是通过Docker宿主机的网络堆栈进行路由。

5、禁用网络模式(none): 禁用容器所有网络。通常与自定义网络驱动程序一起使用。none不适用于群组服务。

6、其它模式(网络插件):可以使用Docker安装和使用第三方网络插件。这些插件可从 Docker Hub或第三方供应商处获得。有关安装和使用给定网络插件的信息,请参阅供应商的文档。

使用场景

下面我们总结下不同场景建议使用的网络模式:

1、当您需要多个容器在同一个Docker宿主机上进行通信时,使用自定义的桥接网络模式(bridge)是最佳选择。

2、当容器网络堆栈不应与Docker主机隔离但又希望隔离容器的其他方面(cgroup,unix file system)时,使用主机网络模式(host)是最佳选择。

3、当您需要在不同Docker守护进程上运行的容器进行通信时,或者当多个应用程序使用swarm服务协同工作时,覆盖网络模式(overlay)是最佳选择。

4、当您从VM设置迁移或需要容器看起来像网络上的物理主机时,Macvlan网络是最佳的,这样每个主机都具有唯一的MAC地址。

5、另外如果以上模式都不能满足您的需求是,可以查找第三方网络插件进行集成。

使用方式

下面我们操练下网络相关的命令,在没有说明情况下,默认我们在node3节点上执行。

在练习之前我们先在节点3安装好docker ce且配置好daemon.json加速配置

1、查看网络列表

docker network ls

docker系列 - 9、网络模式

当我们安装好docker之后默认就已经创建好了3个不同网络模式驱动。当我们直接执行docker run xxxx没有通过-network指定网络驱动时,默认使用的是bridge。这种方式不建议在生产级使用,一般我们都会使用自定义网络。自定义网桥的优势在于:

a、自定义网桥可以将某些容器加入到同一个网桥,这些容器在该网桥内部互相暴露所有端口。对外只会暴露指定映射出来的端口。

b、自定义网桥可以在容器之间提供DNS(通过容器名称相互解析)解析,而默认网桥只能通过ip地址相互访问,如果想在默认网桥上支持类型的功能需要使用--link选项

c、可以动态将运行中的容器与自定义网络连接或断开,不需要重启。如果使用默认网桥,则需要停止容器,再通过不同选项重新创建容器。

d、可以针对自定义网桥进行个性化配置,而不会影响其它使用该网桥的容器。

2、查看bridge网桥详细信息

docker network inspect bridge
//查看有哪些容器使用该网桥
docker network inspect bridge | grep Containers -A 10

3、创建自定义桥接模式网络my-bridge

docker network create my-bridge
或
docker network create -d bridge my-bridge 

docker系列 - 9、网络模式

将前面演示的myhelloworld拉取到本地,然后使用自定义驱动my-bridge启动:

node1:

docker login registry.laizhiy.cn
docker tag myhelloworld:latest registry.laizhiy.cn/myhelloworld:latest
docker push registry.laizhiy.cn/myhelloworld:latest

node3:

docker login registry.laizhiy.cn
docker pull registry.laizhiy.cn/myhelloworld:latest
docker ps
docker run -d --rm \
--name myhelloworld -p 8100:8100 \
--network my-bridge \
registry.laizhiy.cn/myhelloworld
//查看my-bridge容器连接信息
docker network inspect my-bridge | grep Container -A 10

可以看到,myhelloworld容器已经加入到我们自定义的网络驱动my-bridge。

docker系列 - 9、网络模式

此时我们访问:http://node3:8100/visitor

docker系列 - 9、网络模式

我们继续在node3部署redis容器,然后测试使用默认bridge网络和加入到自定义网络my-bridge时myhelloworld连接myredis的情况。

docker run -d --rm --name myredis redis
docker network inspect bridge | grep Containers -A 10

docker系列 - 9、网络模式

现在myhelloworld通过--network 连接到my-bridge网桥,myredis连接到默认的bridge网桥,它们连接的是不同的网络驱动(myhelloworld ),我们访问

http://node3:8100/visitor

结果如下:

docker系列 - 9、网络模式

可以看到,不同的网络网桥无法通信。现在停止myredis容器,通过--network方式使用my-bridge网桥再次启动容器,此时使用的和myhelloworld是同一个桥接模式的网桥:

docker stop myredis
docker run -d --rm --name myredis --network my-bridge redis
//myredis已经不存在默认bridge网桥列表
docker network inspect bridge | grep Containers -A 10

docker系列 - 9、网络模式

//确认自定义网桥my-bridge包含myredis和myhelloworld容器
docker network inspect my-bridge | grep Containers -A 10

docker系列 - 9、网络模式

我们访问

http://node3:8100/visitor

结果如下

docker系列 - 9、网络模式

可以看到,myhelloworld连上了myredis了。

通过自定义方式,可以自由断开或重新连接网络驱动,命令如下:

docker network disconnect my-bridge myredis
docker network connect my-bridge myredis

可以通过访问

http://node3:8100/visitor

进行测试断开和连上的情况。

如果要删除某个网络驱动可以执行命令:

docker network rm my-bridge

删除之前需要停止该网络关联的所有容器。

4、创建自定义主机模式网络

docker network create -d host my-host

注意,一个宿主机只能有一个host网络模式实例,不能创建多个。下面我们来演示一下主机模式网络的使用。演示思路如下:

a、停止node3部署的myredis容器

docker stop myredis

b、在node3上直接部署redis到宿主机上,具体部署方法自行百度

docker系列 - 9、网络模式

c、配置/etc/hosts,添加如下内容(因为myhelloworld配置文件配置的redis主机是myredis,所以要配置本地dns解析):

127.0.0.1 myredis

d、测试通过docker桥接模式网络是否可以访问到宿主机上的服务

目前myhelloworld使用的仍然是my-bridge桥接网络,所以我们直接浏览器访问:

http://node3:8100/visitor

docker系列 - 9、网络模式

可以看到使用桥接模式是访问不了宿主机redis的

e、测试主机模式是否可以访问宿主机服务,停掉myhelloworld,通过--network指定网络驱动为host(主机模式)重新启动myhelloworld

docker stop myhelloworld
docker run -d --rm \
--name myhelloworld \
--network host -p 8100:8100 \
 registry.laizhiy.cn/myhelloworld
 
 //笔者为了方便,直接关闭防火墙,生产建议通过开放8100端口方式
systemctl stop firewalld

此时我们访问:

http://node3:8100/visitor

docker系列 - 9、网络模式

可以看到只有使用主机网络模式才可以访问宿主服务。

//确认myhelloworld的确是使用host(主机模式)网络驱动
docker network inspect host | grep Container -A 10

docker系列 - 9、网络模式

5、创建自定义覆盖模式网络

docker network create -d overlay my-overlay
docker network ls

docker系列 - 9、网络模式

执行该命令前我们需要先初始化集群管理者(哪台机子执行init,哪台就会成为集群管理者):

docker swarm init

关于覆盖网络的更多使用我们后面讲解集群swarm时再讲解。

6、创建自定义MAC模式网络

docker network create -d macvlan  my-macvlan

7、创建禁用模式网络

docker network create -d null my-none

注意,一个宿主机只能有一个null网络模式实例,不能创建多个。