docker入门(四)——网络

学习资料:公众号cloudman

none和host网络的适用场景

本章开始讨论Docker网络。

我们会首先学习Docker提供的几种原生网络,以及如何创建自定义网络。然后探讨容器之间如何通信,以及容器与外界如何交互。

Docker网络从覆盖范围可分为单个host上的容器网络和跨多个host的网络。

Docker安装时会自动在host上创建三个网络,我们可用docker network ls命令查看:

在这里插入图片描述

none网络

什么都没有的网络。挂在这个网络下的容器除了lo,没有其他任何网卡。容器创建时,可以通过--network-none指定使用none网络。

这样的网络的应用场景是什么呢?

封闭意味着隔离,一些对安全性要求高并且不需要联网的应用可以使用none网络。比如某个容器的唯一用途是生成随机密码,就可以放到none网络中避免密码被窃取。

host

大部分容器其实是需要网络的,连接到host网络的容器共享Docker host的网络栈,容器的网络配置与host完全一样。可以通过--network=host 指定host网络

在这里插入图片描述

在容器中可以看到所有的网卡,并且连hostname也是host的。host网络的使用场景又是什么呢?

直接使用Docker host的网络最大的好处就是性能,如果容器对网络传输效率较高要求,则可以选择host网络。当然不便之处就是**牺牲一些灵活性,**比如要考虑端口冲突问题,Docker host上已经使用的端口就不能再用了。

Docker host的另一个用途是让容器可以直接配置host网络。比如某些跨host的网络解决方案,其本身也是以容器方式运行的,这些方案需要对网络进行配置,比如管理iptables。

学容器必须懂bridge网络

Docker安装时会创建一个命名为docker0的linux bridge。如果不指定--network,创建的容器默认都会挂到docker0上。

在这里插入图片描述

当前docker0上没有任何其他网络设备,我们创建一个容器看看有什么变化。

在这里插入图片描述

一个新的网络接口veth28c57df被挂到了docker0上,veth28c57df就是新创建容器的虚拟网卡

下面看一下容器的网络配置。

在这里插入图片描述

容器有一个网卡eth0@if34。大家可能会问了,为什么不是veth28c57df呢?

实际上eth0@if34veth28c57df是一对veth pair。veth pair是一种成对出现的特殊网络设备,可以把它们想象成由一根虚拟网线连接起来的一对网卡,网卡的一头(eth0@if34)在容器中,另一头(veth28c57df)挂在网桥docker0上,其效果就是将eth0@if34也挂在了docker0上。

我们还看到eth0@if34已经配置了IP172.17.0.2,为什么是这个网段呢?让我们通过docker network inspect bridges看一下bridge网络的配置信息:

在这里插入图片描述

原来bridge网络配置的subset就是172.17.0.0/16,并且网关是172.17.0.1、这个网关就是docker0.

在这里插入图片描述

当前容器网络拓扑结构如图所示

在这里插入图片描述

容器创建时,docker会从172.17.0.0/16中分配一个IP,这里16位的掩码保证有足够多的IP可以供容器使用。

如何自定义容器网络?

除了none,host,bridge这三个自动创建的网络,用户也可以根据业务需要创建user-defined网络。

Docker提供三种user-defined网络驱动:bridge、overlay和macvlan。overlay和macvlan用于创建跨主机的网络。

我们可通过bridge驱动创建类似前面默认的bridge网络,例如:

在这里插入图片描述

查看一下当前host的网络结构变化:

在这里插入图片描述

新增了一个网桥br-eaed97dc9a77,这里eaed97dc9a77正好是新建的bridge网络my_net的短ID,执行docker network inspect查看一下my_net的配置信息。
在这里插入图片描述

这里172.18.0.0/16是Docker自动分配的IP网段。

我们也可以自己指定IP网段。

只需在创建网段时指定--subnet--gateway参数

在这里插入图片描述

这里我们创建了新的bridge网络my_net2,网段为172.22.16.0/24,网关为172.22.16.1。与前面一样,网关在my_net1对应的网桥br-5d863e9f78b6上:

在这里插入图片描述

容器要使用新的网络,需要在启动时通过--network指定:

在这里插入图片描述

容器分配到的IP为172.22.16.2。

到目前为止,容器的IP都是docker自动从subnet中分配,我们能否指定一个静态IP呢?

  • 可以,通过--ip指定

在这里插入图片描述

注:只有使用--subnet创建的网络才能指定静态IP

当前docker host的网络拓扑结构:

在这里插入图片描述

理解容器之间的连通性

上图展示了两个busybox容器都挂在my_net2上,应该能够互通,验证:

在这里插入图片描述

可见同一网络中的容器、网关之间都是可以通信的。

my_net2与默认bridge网络能通信吗?

从拓扑图可知,两个网络属于不同的网桥,应该不能通信,我们通过实验验证一下,让 busybox 容器 ping httpd 容器:

在这里插入图片描述

确实 ping 不通,符合预期。

“等等!不同的网络如果加上路由应该就可以通信了吧?”我已经听到有读者在建议了。

这是一个非常非常好的想法。

确实,如果 host 上对每个网络的都有一条路由,同时操作系统上打开了 ip forwarding,host 就成了一个路由器,挂接在不同网桥上的网络就能够相互通信。下面我们来看看 docker host 满不满足这些条件呢?

ip r 查看 host 上的路由表:

\# ip r

......

172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1

172.22.16.0/24 dev br-5d863e9f78b6  proto kernel  scope link  src 172.22.16.1

......

172.17.0.0/16 和 172.22.16.0/24 两个网络的路由都定义好了。再看看 ip forwarding:

\# sysctl net.ipv4.ip_forward

net.ipv4.ip_forward = 1

ip forwarding 也已经启用了。

条件都满足,为什么不能通行呢?

我们还得看看 iptables:

\# iptables-save

......

-A DOCKER-ISOLATION -i br-5d863e9f78b6 -o docker0 -j DROP

-A DOCKER-ISOLATION -i docker0 -o br-5d863e9f78b6 -j DROP

......

原因就在这里了:iptables DROP 掉了网桥 docker0 与 br-5d863e9f78b6 之间双向的流量

从规则的命名DOCKER-ISOLATION可知docker在设计上就是要隔离不同的network。

那么接下来的问题是:怎么才能容busybox与httpd通信呢?

答案是:为httpd容器添加一块my_net2的网卡。这个可以通过docker network connect命令实现
在这里插入图片描述

我们在 httpd 容器中查看一下网络配置:

在这里插入图片描述

容器中增加了一个网卡 eth1,分配了 my_net2 的 IP 172.22.16.3。现在 busybox 应该能够访问 httpd 了,验证一下:

在这里插入图片描述

busybox 能够 ping 到 httpd,并且可以访问 httpd 的 web 服务。当前网络结构如图所示:

在这里插入图片描述

容器间通信的三种方式

IP通信

从上一节的例子可以得出这样一个结论:两个容器要能通信,必须要有属于同一个网络的网卡。

满足这个条件后,容器就可以通过IP交互了。具体做法是在容器创建时通过--network指定相应的网络,或者通过docker network connect将现有容器加入到指定网络。

Docker DNS sERVER

通过IP访问容器虽然满足了通信的要求,但还是不够灵活。因为我们在部署应用之前可能无法确定IP,部署之后再指定要访问的IP会比较麻烦。对于这个问题,可以通过docker自带的DNS服务解决。

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

下面启动两个容器bbox1和bbox2:

 docker run -it --network=my_net2 --name=bbox1 busybox
 docker run -it --network=my_net2 --name=bbox2 busybox

然后,bbox2就可以直接ping到bbox1了:

在这里插入图片描述

使用docker DNS有一个限制只能user-defined网络中使用。也就是说,默认的bridge网络是无法使用DNS的。

joined容器

joined容器是另一种实现容器间通信的方式。

joined容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined容器之间可以通过127.0.0.1直接通信。请看下面的例子:

先创建一个httpd容器,名字为web:

在这里插入图片描述

然后创建busybox容器并通过--network=container:web指定joined容器为web:

在这里插入图片描述

请注意busybox容器中的网络配置信息,下面我们查看一下web的网络:
在这里插入图片描述
在这里插入图片描述

看!busybox和web1的网卡mac地址与IP完全一样,它们共享了相同的网络栈。busybox可以直接用127.0.0.1访问web1的http服务。

在这里插入图片描述

joined容器非常适合以下场景:

  1. 不同容器中的程序希望通过loopback高效快速地通信,比如web server与app server
  2. 希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。

容器如何访问外部世界?

前面我们已经解决了容器间通信的问题,接下来讨论容器如何与外部世界通信。这里涉及两个方向:

  1. 容器访问外部世界
  2. 外部世界访问容器

容器访问外部世界

在我们当前的实验环境下,docker host是可以访问外网的。

在这里插入图片描述

我们看一下容器是否也能访问外网呢?

在这里插入图片描述

可见,容器默认就能访问外网

注意:这里外网指的是容器网络以外的网络环境,并非特指internet。

在容器内访问外网是怎么实现的呢?

busybox位于docker0这个私有bridge网络中(172.17.0.0/16),当busybox从容器向外ping时,数据包是怎么到达baidu.com的呢?

这里的关键是NAT,即网络地址转换。将ping包的源地址换成了host的IP,从而保证数据包能够到达外网。下面用一张图来说明这个过程:

在这里插入图片描述

  1. busybox发送ping包:172.0.0.2>www.baidu.com
  2. docker0收到包,发现是发送到外网的,交给NAT处理
  3. NAT将源地址转换成enp0s3的IP:10.0.2.15>www.baidu.com
  4. ping包从enp0s3发送出去,到达www.bing.com

通过NAT,docker实现了容器对外网的访问。

外部世界如何访问容器?

上节我们学习了容器如何访问外部网络,今天讨论另一个方向:外部网络如何访问到容器?

答案是:端口映射。

docker可将容器对外提供服务的端口映射到host的某个端口,外网通过该端口访问容器。容器启动时通过-p参数映射窗口。

在这里插入图片描述

容器启动后,可通过docker ps或者docker port查看host映射的端口。在上面的例子中,httpd容器的80端口被映射到host 8242上,这样就可以通过<host ip>:<32773>访问容器的web服务了。

在这里插入图片描述

除了映射动态端口,也可以在-p中指定映射到host某个特定的端口,例如可将80端口映射到host的8081端口:

在这里插入图片描述

每一个映射的端口,host都会启动一个docker-proxy进程来处理访问容器的流量:

在这里插入图片描述

以0.0.0.0:32773->80/tcp为例分析整个过程:

在这里插入图片描述

  1. docker-proxy监听host的32773端口
  2. 当curl访问10.0.2.15:32773时,docker-proxy转发给容器172.17.0.2:80
  3. httpd容器相应请求并返回结果

本章小结

本章学习了Docker的三种网络:none,host和bridge并讨论了它们的不同使用场景;然后我们实践了创建自定义网络;最后详细讨论了如何实现容器与容器之间,容器与外部网络之间的通信。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值