企业——Docker容器的网络管理

 一.Docker容器的四种网络模式

容器的本质是一个被隔离的进程,而这个进程又有其独立的网络栈,即网卡(Network Interface)、回环设备(Loopback Device)、路由表(Routing Table)和 iptables 规则。单机时代的容器网络实际上有三种通信需求,分别是:

  容器之间通信  容器与宿主机之间通信  容器与外部主机通信

 

Docker在创建容器时有四种网络模式,bridge为默认不需要用–net去指定,其他三种模式需要在创建容器时使用–net去指定。
  bridge模式,使用–net=bridge指定,默认设置。
  none模式,使用–net=none指定。
  host模式,使用–net=host指定。
  container模式,使用–net=container:容器名称或ID指定

 

二.四种网络模式的实现原理

Bridge桥接方式

  实现的步骤如下:
(1) Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备,假设为 veth0 和 veth1。而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方。
(2) Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。保证宿主机的网络报文可以发往 veth0;
(3) Docker Daemon 将 veth1 添加到 Docker Container 所属的 namespace 下,并被改名为 eth0。 如此一来,保证宿主机的网络报文若发往 veth0,则立即会被 eth0 接收,实现宿主机到 Docker Container 网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性。
bridge 桥接模式下的 Docker Container 在使用时,并非为开发者包办了一切。最明显的是, 该模式下 Docker Container 不具有一个公有 IP,即和宿主机的 eth0 不处于同一个网段。导致 的结果是宿主机以外的世界不能直接和容器进行通信。虽然 NAT 模式经过中间处理实现了 这一点,但是 NAT 模式仍然存在问题与不便,如:容器均需要在宿主机上竞争端口,容器 内部服务的访问者需要使用服务发现获知服务的外部端口等。另外 NAT 模式由于是在三层 网络上的实现手段,故肯定会影响网络的传输效率。
  大致的过程图:

      

 

Host 网络模式

  host 模式是 bridge 桥接模式很好的补充。采用 host 模式的 Docker Container,可以直接使用 宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公 有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。当然, 有这样的方便,肯定会损失部分其他的特性,最明显的是 Docker Container 网络环境隔离性 的弱化,即容器不再拥有隔离、独立的网络栈。另外,使用 host 模式的 Docker Container 虽 然可以让容器内部的服务和传统情况无差别、无改造的使用,但是由于网络隔离性的弱 化,该容器会与宿主机共享竞争网络栈的使用;另外,容器内部将不再拥有所有的端口资 源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以 bridge 网 络模式容器的端口映射。
  大致的结构图:
      

 

Container 网络模式

  (1) 查找 other container(即需要被共享网络环境的容器)的网络 namespace;
  (2) 将新创建的 Docker Container(也是需要共享其他网络的容器)的 namespace,使用 other container 的 namespace。
Docker Container 的 other container 网络模式,可以用来更好的服务于容器间的通信。 在这种模式下的 Docker Container 可以通过 localhost 来访问 namespace 下的其他容器,传输 效率较高。虽然多个容器共享网络环境,但是多个容器形成的整体依然与宿主机以及其他 容器形成网络隔离。另外,这种模式还节约了一定数量的网络资源。但是需要注意的是,它并没有改善容器与宿主机以外世界通信的情况。

  大致结构图如下:

      

 

None 网络模式:

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

 

 

三.docker 网络的基本管理 

1.查看docker网络的模式:docker network ls

  docker network ls 

    NETWORK ID    NAME    DRIVER    SCOPE
    21ca12d3508c    bridge    bridge       local
    f4ff71176a19      host      host       local
    b12b1dd0542e     none     null      local

 

2.通过pid来获取容器的id

      

 

3.bridge网络的配置过程

(1)利用ubuntu的镜像创建一个新的容器

  docker load -i ubuntu.tar
  docker run -it --name vm1 ubuntu  ##这是开启了一个交互的界面,因为没有 -d,所以直接进入了一个界面
  root@a84448835d94:/# [root@foundation79 images]# ##ctrl + pq  ##退出交互的界面

 

  查看网络桥接的信息

  brctl show  ##在开启docker服务之后,会自动的创建一个docker0,用于网络桥接,bridge是默认的网络模式

      

 

  上图显示,因为开启了一个新的容器,所以会自动的创建docker0这个网桥,并且docker0后面有相应的接口信息

  docker stop vm1  ##关闭容器
  brctl show  ##查看网桥后面的接口信息,没有了。则表示docker默认的是bridge网络模式,刚才的接口信息是vm1的

      

 

(2)创建一个bridge模式的网络

  docker network create --driver bridge my_net1  ##默认的设置ip和网关
    89b97e70be47c758684ca2bd34e86242a0643be9a01fd297f5487b5cdef4f82c
  docker network ls
    NETWORK ID      NAME      DRIVER     SCOPE
    5c0d59e54cbc      bridge      bridge      local
    082bf249cd4b       host      host       local
    89b97e70be47     my_net1     bridge      local
    bf84585ce5e5      none      null       local

  ip addr
    14: br-89b97e70be47: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
    link/ether 02:42:fd:98:f5:ac brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-89b97e70be47
    valid_lft forever preferred_lft forever

  docker network inspect my_net1
    {
      "Subnet": "172.18.0.0/16",   ##默认单调递增,18,19...
      "Gateway": "172.18.0.1"
    }

 

(3)再创建一个bridge的网络 (自定义ip和网关)

  docker network create --driver bridge --subnet 172.20.0.0/24 --gateway 172.20.0.1 my_net2   ##自定义

  docker network ls
    NETWORK ID      NAME    DRIVER     SCOPE
    5c0d59e54cbc      bridge     bridge       local
    082bf249cd4b        host     host       local
    89b97e70be47      my_net1   bridge        local
    8f8e4347cd7d       my_net2   bridge      local
    bf84585ce5e5      none      null       local

  
  docker network inspect my_net2
    {
      "Subnet": "172.20.0.0/24",
      "Gateway": "172.20.0.1"
    }

  ip addr
   14: br-89b97e70be47: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
    link/ether 02:42:fd:98:f5:ac brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-89b97e70be47
    valid_lft forever preferred_lft forever
   15: br-8f8e4347cd7d: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
    link/ether 02:42:e7:f9:c5:d8 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.1/24 brd 172.20.0.255 scope global br-8f8e4347cd7d
    valid_lft forever preferred_lft forever

 

(4)创建容器

  docker load -i ubuntu.tar

  docker run -it --name vm1 --net my_net1 ubuntu
  root@bfd519244ae0:/# ip addr
   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
   16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0      ##容器IP为172.18.0.2/16
    valid_lft forever preferred_lft forever

 

(5)重新开启一个shell

  docker run -it --name vm2 --net my_net2 ip 172.20.0.10 ubuntu
  root@b010954d0ef6:/# ip addr
   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
   18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:14:00:0a brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.10/24 brd 172.20.0.255 scope global eth0  ##上面开启容器的命令因为设定了容器的ip,所以就不会自己设置相关的ip
    valid_lft forever preferred_lft forever

  root@b010954d0ef6:/# ping 172.20.0.1      ## ping网关可以通
    PING 172.20.0.1 (172.20.0.1) 56(84) bytes of data.
    64 bytes from 172.20.0.1: icmp_seq=1 ttl=64 time=0.103 ms
    64 bytes from 172.20.0.1: icmp_seq=2 ttl=64 time=0.116 ms
    ^C

  root@b010954d0ef6:/# ping 172.18.0.2      ##但是因为两个容器不在一个网段,所以容器间不能ping通

    PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
    ^C
    --- 172.18.0.2 ping statistics ---
    2 packets transmitted, 0 received, 100% packet loss, time 999ms

 

(6)建立两个容器之间的连接

  docker network connect my_net1 vm2  ##给容器 vm2,在172.18.0.0/16这个网段上,创建一对虚拟网卡,一端在主机上,一端在docker容器上。
   18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:14:00:0a brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.10/24 brd 172.20.0.255 scope global eth0
    valid_lft forever preferred_lft forever
   20: eth1@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth1
    valid_lft forever preferred_lft forever

  root@b010954d0ef6:/# ping 172.18.0.2      ##此时可以ping通
    PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
    64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.128 ms
    64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.089 ms
    ^C

4.docker的跨主机网络方案——macvlan

  macvlan是Linux操作系统内核提供的网络虚拟化方案之一,更准确的说法是网卡虚拟化方案。它可以为一张物理网卡设置多个mac地址,相当于物理网卡施展了影分身之术,由一个变多个,同时要求物理网卡打开混杂模式。针对每个mac地址,都可以设置IP地址,本来是一块物理网卡连接到交换机,现在是多块虚拟网卡连接到交换机。macvlan应该很简单
 

 实验环境

  创建两台虚拟机server1,server2,都是两块网卡(先添加一个网卡,后面会要求添加)     两台虚拟机都安装docker,都导入ubuntu.tar镜像

 

server1上配置:

  docker network create -d macvlan --subnet 172.25.1.0/24 --gateway 172.25.1.1 -o parent=eth0 mac_net1

  docker network ls
    NETWORK ID       NAME      DRIVER      SCOPE
    590d47201aeb     bridge      bridge       local
    7acae6b7116a   docker_gwbridge   bridge      local
    aabe3d541f65      host       host       local
    8xbgnhdmo84i     ingress      overlay      swarm
    a7a0fc0f184b      mac_net1      macvlan     local
    85ed6bc9ad0b      none        null          local

  docker run -it --name vm1 --net mac_net1 --ip 172.25.1.10 ubuntu
  root@4f333ebdc7bb:/# ip addr
   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
   16: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 02:42:ac:19:01:0a brd ff:ff:ff:ff:ff:ff
    inet 172.25.1.10/24 brd 172.25.1.255 scope global eth0
    valid_lft forever preferred_lft forever

 

server2上配置:

  docker network create -d macvlan --subnet 172.25.1.0/24 --gateway 172.25.1.1 -o parent=eth0 mac_net1
    65605f0175a07dc9feb7966ae63ed3b50b647b8d2745885669cbbb71096fb576
  docker run -it --name vm1 --net mac_net1 --ip 172.25.1.11 ubuntu
  root@e1ed97672c79:/# ip addr
   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
   12: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 02:42:ac:19:01:0b brd ff:ff:ff:ff:ff:ff
    inet 172.25.1.11/24 brd 172.25.1.255 scope global eth0
    valid_lft forever preferred_lft forever
  root@e1ed97672c79:/# ping 172.25.1.10      ##可以ping通,则互联成功

 

测试:两个server是否可以相互ping通(不需要像上面一样,配置容器间的互联)

  PING 172.25.1.10 (172.25.1.10) 56(84) bytes of data.
    64 bytes from 172.25.1.10: icmp_seq=1 ttl=64 time=0.683 ms

       

 

再添加一块网卡:

server1上进行配置:

  ip link set up eth1
  ip link set eth1 promisc on

  docker network create -d macvlan --subnet 172.25.2.0/24 --gateway 172.25.2.1 -o parent=eth1 mac_net2

  docker run -it --name vm2 --net mac_net2 --ip 172.25.2.10 ubuntu
  root@282e8ddf9c14:/# ip addr
   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
   17: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 02:42:ac:19:02:0a brd ff:ff:ff:ff:ff:ff
    inet 172.25.2.10/24 brd 172.25.2.255 scope global eth0
    valid_lft forever preferred_lft forever

 

server2上的配置:

  docker network create -d macvlan --subnet 172.25.2.0/24 --gateway 172.25.2.1 -o parent=eth1 mac_net2
  docker run -it --name vm2 --net mac_net2 --ip 172.25.2.11 ubuntu

 

测试:

   在server2的另一个网卡上,ping 172.25.2.10,可以ping通;

   在server2的之前的网卡上,ping 172.25.1.10,却ping不通。

 

如何解决上面的同一个虚拟机上,不同网段的docker容器得互通问题呢?

server1上配置:

  docker network create -d macvlan --subnet 172.25.3.0/24 --gateway 172.25.3.1 -o parent=eth1.1 mac_net3

    8c1ffd97639e45ff9f4b73c61e83355bf91cba9ff73052811657706db1cad167
  docker run -it --name vm3 --net mac_net3 --ip 172.25.3.10 ubuntu

server2上配置:

  docker network create -d macvlan --subnet 172.25.3.0/24 --gateway 172.25.3.1 -o parent=eth1.1 mac_net3

  docker run -it --name vm3 --net mac_net3 --ip 172.25.3.11 ubuntu
  root@e1ed97672c79:/#  ping 172.25.3.10
    PING 172.25.1.10 (172.25.1.10) 56(84) bytes of data.
    64 bytes from 172.25.1.10: icmp_seq=1 ttl=64 time=0.683 ms
  root@e1ed97672c79:/#  ping 172.25.2.10
    PING 172.25.1.10 (172.25.1.10) 56(84) bytes of data.
    64 bytes from 172.25.1.10: icmp_seq=1 ttl=64 time=0.683 ms

 

posted @ 2019-04-28 20:20  wf-aiyouwei  阅读(550)  评论(0编辑  收藏  举报