• 企业——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

  • 相关阅读:
    关于对defer的理解.
    JAVA文件操作类和文件夹的操作
    跟我学XSL(一)
    .NET Remoting程序开发入门篇(一)
    jboss配置入门(一)
    SQL2000 关于 Java JDBC 驱动的安装和设定
    XSL基础教程(三)
    利用WSCF进行契约先行的Web Services开发
    Log4Net使用指南
    java存储过程调用(sqlsever数据库)
  • 原文地址:https://www.cnblogs.com/wf-aiyouwei/p/10786309.html
Copyright © 2020-2023  润新知