Docker的网络模式学习

在之前我们学习过了Docker的一些基本知识,我们可以注意到在我们启动一个docker容器后系统会自动生成一个ip,那么有ip就一定会有网络,那么我们今天就来学习docker的网络。

Docker的四种网络模式(Bridge,Host,Container,None)

Docker在启动时会开启一个虚拟网桥docker0,容器启动后都会被桥接到docker0,并自动分配一个IP地址
在这里插入图片描述
在这里插入图片描述
每一个容器都会有一个都有的Pid
在这里插入图片描述
每一个独有的Pid都会在/proc目录下有一个相应的以Pid为名的目录,这个目录的ns/目录中有着关于这个Pid容器网络的文件
在这里插入图片描述
通常我们的容器启动后都是以桥接的形式连接网络的,容器生成的ip会以网桥的ip向上递增,一般只要容器桥接docker0后,使用ip a就可以看到多了相应的虚拟网卡
在这里插入图片描述
在这里插入图片描述
veth设备是成对出现的,一端是容器内部命名为eth0,一端是加入到网桥命名为veth,他们组成了一个数据传输通道,一端进,一端出,实现数据通信

Docker在创建容器时有三种网络模式,bridge为默认不需要用–net去指定,其他三种模式需要在创建容器时使用–net去指定。

bridge	模式,使用–net=bridge指定,默认设置。
none	模式,使用–net=none指定。
host	模式,使用–net=host指定。
container	模式,使用–net=container:容器名称或ID指定

1.桥接模式

bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是
不可见的,但容器通过宿主机的NAT规则后可以访问外网。

在这里插入图片描述
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,则立即会被 eth0 接收,实现宿主机到Docker Container 网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性
    Bridge桥接模式的缺陷:
  • 最明显的是,该模式下 Docker Container 不具有一个公有 IP,即和宿主机的 eth0 不处于同一个网段。导致的结果是宿主机以外的世界不能直接和容器进行通信。
  • 虽然 NAT 模式经过中间处理实现了这一点,但是 NAT 模式仍然存在问题与不便,如:容器均需要在宿主机上竞争端口,容器内部服务的访问者需要使用服务发现获知服务的外部端口等。
  • 另外 NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。

2.Host网络模式

host 模式是 bridge 桥接模式很好的补充。采用 host 模式的 Docker Container,可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。

host模式可以让容器共享宿主机网络栈,这样的好处是外部主
机与容器直接通信,但是容器的网络缺少隔离性。

在这里插入图片描述
Host 网络模式的缺陷:
我们可以发现这样的网络方式很方便,但是也肯定会损失一些其他的特性

  • 最明显的是 Docker Container 网络环境隔离性的弱化。即容器不再拥有隔离、独立的网络栈。
  • 另外,使用 host 模式的 Docker Container 虽然可以让容器内部的服务和传统情况无差别、无改造的使用,但是由于网络隔离性的弱化,该容器会与宿主机共享竞争网络栈的使用;
  • 另外,容器内部将不再拥有所有的端口资源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以 bridge 网络模式容器的端口映射。

3.Container模式

Container 网络模式是 Docker 中一种较为特别的网络的模式。
在容器创建时使用–network=container:name指定。(name指定的
是运行的容器名)

处于这个模式下的 Docker 容器会共享一个网络栈,这样两个
容器之间可以使用localhost高效快速通信。

在这里插入图片描述
Container 网络模式的实现步骤主要如下:

  • 1、查找 other container(即需要被共享网络环境的容器)的网络 namespace;
  • 2、将新创建的 Docker Container(也是需要共享其他网络的容器)的 namespace,使用other container 的 namespace。

Docker Container 的 other container 网络模式,可以用来更好的服务于容器间的通信。
在这种模式下的 Docker Container 可以通过 localhost 来访问 namespace 下的其他容器,传输效率较高。虽然多个容器共享网络环境,但是多个容器形成的整体依然与宿主机以及其他容器形成网络隔离。另外,这种模式还节约了一定数量的网络资源。

Container网络模式的缺陷:
它并没有改善容器与宿主机以外世界通信的情况(和桥接模式一样,不能连接宿主机以外的其他设备)。

4.None网络模式

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

在这里插入图片描述

容器的高级网络设置

自定义网络模式,docker提供了三种自定义网络驱动:

  • bridge
  • overlay
  • macvlan
    bridge驱动类似默认的bridge网络模式,但增加了一些新的功能,
    overlay和macvlan是用于创建跨主机网络。

建议使用自定义的网络来控制哪些容器可以相互通信,还可
以自动DNS解析容器名称到IP地址。

1.添加docker的自定义网络
a.使用自动分配的ip地址和网关地址

  1. 查看bridge自定义网络(自动分配的ip地址和网关地址)之前的网络:bridge,host,none

在这里插入图片描述
2. 创建自定义网络
在这里插入图片描述
3. 查看bridge自定义网络(自动分配的ip地址和网关地址)的网关地址
在这里插入图片描述
4. docker network inspect my_net1 查看bridge自定义网络(自动分配的ip地址和网关地址)的信息
在这里插入图片描述
5. 使用自定义网络模式创建容器
在这里插入图片描述
我们可以发现使用自定义的网桥,在同一个网桥上的容器之间是可以通信的

2.使用–ip参数可以指定容器ip地址,但必须是在自定义网桥上(自定义的ip地址和网关地址),默认的bridge模式不支持,同一网桥上的容器是可以通信的

  • docker的bridge自定义网络之间默认是有域名解析的;
  • docker的bridge自定义网络与系统自带的网桥之间默认是有解析的;
  • 但是docker的系统自带的网桥之间默认是没有解析的。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    我们可以一发现不同网络模式的两个容器时不可以直接通信的
    3.让使用两个不同网络模式的容器通信
    在这里插入图片描述
    在这里我们的vm4使用的是my_net,vm5使用的是my_net2
    使用 docker network connect命令为vm4添加一块my_net2 的网卡
    在这里插入图片描述
    成功使其通信
    但是值得我们注意的是:
  • docker的bridge自定义网络之间:双方可以随便添加对方的网卡
  • docker的bridge自定义网络与系统自带的网桥之间:只能是,系统自带的网桥对应的容器添加bridge自定义网络对应的容器的网卡。而反过来会报错。
  • 但是docker的系统自带的网桥之间:是可以通信的,因为是在一个网络桥接上。
  • docker 1.10开始,内嵌了一个DNS server。dns解析功能必须在自定义网络中使用。
    4.容器访问外网及外网访问容器

容器如何访问外网是通过iptables的SNAT实现的
在这里插入图片描述
外网如何访问容器:

  • 端口映射,-p指定对应端口

外网访问容器用到了docker-proxy和iptables DNAT
宿主机访问本机容器使用的是iptables DNAT
外部主机访问容器或容器之间的访问是docker-proxy实现

在这里插入图片描述
示例:

  • 查看当前iptable的nat表火墙策略
    在这里插入图片描述
  • 创建nginx的容器,配置端口映射
    在这里插入图片描述
    我们可以在nat表的最后一行看到使用了端口转发

Docker的跨主机网络访问

跨主机网络解决方案:
1、docker原生的macvlan和overlay;
2、第三方的flannel,weave和calico。

众多网络方案是如何与docker集成在一起的?

libnetwork docker容器网络库
CNM(Container Network Model)这个模型对容器网络进行了抽象

CNM分三类组件:

Sandbox:容器网络栈。包括容器接口,dns,路由表。(namespace)
Endpoint:作用是将sanbox接入network(veth pair)
Network:包含一组endpoint,同一network的endpoint可以通信。

在这里插入图片描述
1,macvlan网络方案的实现
Linux kernel提供的一种网卡虚拟化技术。无需Linux bridge,直接使用 物理接口,性能机号。

  • 跨主机的两台虚拟机都需要两个网卡,其中一个打开网卡的混杂模式
    server1:
    在这里插入图片描述
    配置添加的网卡:

    [root@server1 ~]# cd /etc/sysconfig/network-scripts/
    [root@server1 network-scripts]# vim ifcfg-eth1
    [root@server1 network-scripts]# cat ifcfg-eth1
    BOOTPROTO=none
    DEVICE=eth1
    ONBOOT=yes
    [root@server1 network-scripts]# ifup eth1 启动网卡
    server2:
    在这里插入图片描述
    配置eth1网卡

    [root@server2 ~]# cd /etc/sysconfig/network-scripts/
    [root@server2 network-scripts]# vim ifcfg-eth1
    [root@server2 network-scripts]# cat ifcfg-eth1
    BOOTPROTO=none
    DEVICE=eth1
    ONBOOT=yes
    [root@server2 network-scripts]# ifup eth1

macvlan本身是linxu kernel的模块,本质上是一种网卡虚拟化技术。其功能是允许在同一个物理网卡上虚拟出多个网卡,通过不同的MAC地址在数据链路层进行网络数据的转发,一块网卡上配置多个 MAC 地址(即多个 interface),每个interface可以配置自己的IP,Docker的macvlan网络实际上就是使用了Linux提供的macvlan驱 动。

因为多个MAC地址的网络数据包都是从同一块网卡上传输,所以需要打开网卡的混杂模式ip link set eth0 promisc on。

  • 打开server1和server2的eth1网卡的混杂模式

      [root@server1 network-scripts]# ip link set eth1 promisc on
      [root@server1 network-scripts]# ip addr show | grep eth1
      20: eth1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
      [root@server2 network-scripts]# ip link set eth1 promisc on
      [root@server2 network-scripts]# ip addr show | grep eth1
      3: eth1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
      只要我们可以看到PROMISC,则表示成功
    

注意:如果不开启混杂模式,会导致macvlan网络无法访问外界,具体在不使用vlan时,表现为无法ping通路由,无法ping通同一网络内其他主机。

2.在两台主机上各创建macvlan网络

创建macvlan网络不同于桥接模式,需要指定网段和网关(因为要保证跨主机上网段和网关是相同的),并且都得是真实存在的

server1:
在这里插入图片描述
server2:
在这里插入图片描述
3.在两台主机上分别使用创建的macvlan1运行一个容器
server1

[root@server1 ~]# docker run -it --name vm1 --network=macvlan1 --ip=172.22.0.10 ubuntu
root@a1c8bdb2a1e7:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
21: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether 02:42:ac:16:00:0a brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.10/24 brd 172.22.0.255 scope global eth0
       valid_lft forever preferred_lft forever

server2:

[root@server2 ~]# docker run -it --name vm2 --network=macvlan1 --ip=172.22.0.20 ubuntu
root@816cfcc1bb2a:/# 
root@816cfcc1bb2a:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
5: eth0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether 02:42:ac:16:00:14 brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.20/24 brd 172.22.0.255 scope global eth0
       valid_lft forever preferred_lft forever
root@816cfcc1bb2a:/# 

访问测试:
在这里插入图片描述

  • macvlan模式不依赖网桥,所以brctl show查看并没有创建新的bridge,但是查看容器的网络,会看到虚拟网卡对应了一个interface是20。
    在这里插入图片描述
  • 查看宿主机的网络,20正是虚机的eth1网卡
    在这里插入图片描述
    可见,容器的 eth0 就是宿主机的eth0通过macvlan虚拟出来的interface。容器的interface直接与主机的网卡连接,这种方案使得容器无需通过NAT和端口映射就能与外网直接通信(只要有网关),在网络上看起来与其他独立主机没有区别。

4、macvlan会独占主机的网卡的解决方案
macvlan会独占主机网卡,但可以使用vlan子接口实现多macvlan网络
vlan可以将物理二层网络划分为4094个逻辑网络,彼此隔离,vlan id取值为1~4094
我们只需要在创建容器时使用vlan子接口就可以i解决:
在这里插入图片描述
各个vlan子接口创建的容器之间的相互通讯,给容器添加vlan子接口

[root@server1 ~]# docker network connect macvlan1 vm3
[root@server1 ~]# docker attach vm3
root@067c3733cfea:/# 
root@067c3733cfea:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
23: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether 02:42:ac:17:00:1e brd ff:ff:ff:ff:ff:ff
    inet 172.23.0.30/24 brd 172.23.0.255 scope global eth0
       valid_lft forever preferred_lft forever
24: eth1@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether 02:42:ac:16:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.2/24 brd 172.22.0.255 scope global eth1
       valid_lft forever preferred_lft forever
root@067c3733cfea:/# ping 172.22.0.20
PING 172.22.0.20 (172.22.0.20) 56(84) bytes of data.
64 bytes from 172.22.0.20: icmp_seq=1 ttl=64 time=0.376 ms
64 bytes from 172.22.0.20: icmp_seq=2 ttl=64 time=0.395 ms
^C
--- 172.22.0.20 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.376/0.385/0.395/0.021 ms

这样就可以实现不同主机之间容器的相互通信了

猜你喜欢

转载自blog.csdn.net/weixin_42446031/article/details/91452126