7-docker容器的网络通信

2021-11-16 16:30:23 浏览数 (1)

一 容器网络的类型

Docker 网络从覆盖范围可分为单个 host 上的容器网络和跨多个 host 的网络,多host网络又分为原生网络和第三方网络,如下:

  • 原生单机网络
    • None:不为容器配置任何网络功能,--net=none
    • Host:与主机共享Network Namespace,--net=host
    • Container:与另一个运行中的容器共享网络名称空间,--net=container:ID
    • Bridge:Docker设计的,默认的NAT网络模型,--net=bridge
  • 原生多机网络
    • overlay:基于vxlan的隧道网络
    • macvlan:基于网卡虚拟化的大局域网
  • 第三方多机网络[本章不讨论]
    • flannel
    • weave
    • calico

原生网络和单机网络都是通过不同的driver来实现的,未来可能还会有更多的开源driver

二 原生单机网络

docker安装好后,默认会创建三个网络,分别是none,host和bridge,用docker network ls命令查看如下

代码语言:javascript复制
[root@docker01 ~]# docker network ls
NETWORK ID       NAME      DRIVER     SCOPE
3cb9e3ca4456     bridge    bridge     local
4cc3166d4351     host      host       local
f61ddbb4efdf     none      null       local

A. none网络

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

代码语言:javascript复制
docker run -it --rm --network=none centos:6.9 
[root@5fa702165cb2 /]# ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0

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

B. host网络

连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样。可以通过 --network=host 指定使用 host 网络。 在容器中可以看到 host 的所有网卡,并且连 hostname 也是 host 的。

代码语言:javascript复制
docker run -it --rm --network=host busybox
/ # hostname
docker01
/ # ip l|egrep ^[1-9]|awk '{print $1,$2}'
1: lo:
2: eth0:
3: docker0:
9: vethccf4863@if8:

Docker host 的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,可以选择 host 网络,但要考虑端口冲突问题 另一个用途是让容器可以直接配置 host 网路。如某些跨 host 的网络解决方案,本身也是以容器方式运行的,需要对网络进行配置,比如管理 iptables

C. Container网络

container网络严格来说并不是一种网络类型,因为它只是让一个容器使用主容器的网络名称空间,主容器的网络是什么类型都不影响

  1. 创建主容器并查看网卡信息docker run -d --name bbx --rm busybox sleep 900 [root@docker01 ~]# docker exec -it bbx ip a|egrep eth0|awk '{print $1,$2}' 34: eth0@if35: inet 172.17.0.2/16
  2. 创建新容器并使用主容器网络[root@docker01 ~]# docker run --network=container:bbx busybox ip a|grep eth0|awk '{print $1,$2}' 34: eth0@if35: inet 172.17.0.2/16
  3. 用途说明 可以明显看出来,上诉两个容器使用的是同一个网卡,其他整个网络名称空间用的都是一个,用这种方式组织的容器,容器间通信十分便捷,效率也很高

bridge 网络

A. bridge网络入门解释

如果不指定--network,创建的容器默认都会挂到 docker0 上,docker0是安装时创建的linux bridge网络(可以理解为NAT),可以用linux管理bridge的命令进行查看和管理

代码语言:javascript复制
yum install bridge-utils
docker container rm -f `docker container ls -a -q`
[root@docker01 ~]# brctl show
bridge name	bridge id		    STP enabled	    interfaces
docker0		8000.024277f99a61	no	

可以看到网桥docker0的信息,可以把docker0理解为一个虚拟交换机,现在这个交换机上没有接设备,我们启动一个容器看看结果

代码语言:javascript复制
docker run -d --name bbx --rm busybox sleep 900
[root@docker01 ~]# brctl show
bridge name	bridge id		    STP enabled	    interfaces
docker0		8000.024277f99a61	no		        veth0652c67

交换机docker0已近连接了虚拟接口对(veth pair)的接口veth0652c67,该虚拟接口对的另一个接口连接到了刚刚新建的容器bbx中

veth pair 是一种成对出现的特殊网络设备,可以想象成由一根虚拟网线连接起来的一对网卡,网卡的一头在容器中,另一头挂在网桥 docker0 上

代码语言:javascript复制
[root@docker01 ~]# ip a|grep veth0652c67|awk '{print $1,$2}'
33: veth0652c67@if32:
[root@docker01 ~]# docker exec -it bbx sh
/ # ip a|grep eth0|awk '{print $1,$2}'
32: eth0@if33: 
[root@docker01 ~]# docker network inspect bridge |grep -A1 Subnet
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"

上面代码解释说明:

  • docker主机中多了一块网卡,编号33,名称veth0652c67,对端网卡编号if32
  • bbx容器中有一个网卡,编号32,名称eth0,对端网卡边哈if33,正好是一对
  • 默认分配的IP地址段是172.17.0.0/16,网关IP就是docker0的IP

B. bridge网络自定义

默认的bridge网络是自动创建的,已有的信息不能修改,但docker支持自定义新的bridge网络,子网段、网关、是否自动分配等都可以自定义

  1. 创建简单的自定义bridge网络docker network create --driver bridge noah_net [root@docker01 ~]# brctl show bridge name bridge id STP enabled interfaces br-a83f1d0be49e 8000.0242e25e18d4 no docker0 8000.024277f99a61 no [root@docker01 ~]# docker network inspect noah_net |grep -A1 Subnet "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1"
  2. 创建自定义网段的bridge网络docker network create --driver bridge --subnet 192.168.4.0/24 --gateway 192.168.4.1 noah_net2 [root@docker01 ~]# docker network inspect noah_net2 |grep -A1 Subnet "Subnet": "192.168.4.0/24", "Gateway": "192.168.4.1"
  3. 使用自定义网络创建容器 以上两个自定义网络创建好以后,创建容器时只要指定--network=xxx,就可以使用新的bridge网络了. 使用--subnet创建的网络,还可以通过--ip手动分配IP,非--subnet参数创建的网络不能手动分配IP,会报错[root@docker01 ~]# docker run -it --rm --network=noah_net busybox ip addr|grep "172" inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 [root@docker01 ~]# docker run -it --rm --network=noah-net2 --ip 192.168.4.99 busybox ip addr|grep "192" inet 192.168.4.99/24 brd 192.168.4.255 scope global eth0

C. bridge网络之间通信

先说结论:

  • 相同bridge网络下的容器互相之间可以通过IP通信
  • 不同bridge网络下的容器互相之间不能通过IP通信
  • 不同bridge网络之间不能通过添加路由解决通信问题
  • iptables DROP 掉了不同bridge网络间的通信

基于以上原因,要解决不同bridge网络之间的通信问题,常用的解决办法就是为容器配置多个bridge的网卡,通过docker network connect 命令实现。

代码语言:javascript复制
docker run -d --name bbx1 --network=noah_net busybox sleep 900
docker network connect noah-net2 bbx1
[root@docker01 ~]# docker exec -it bbx1 ip a|grep inet
    inet 127.0.0.1/8 scope host lo
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
    inet 192.168.4.2/24 brd 192.168.4.255 scope global eth1
[root@docker01 ~]# docker exec -it bbx1 ping -c1 192.168.4.1
PING 192.168.4.1 (192.168.4.1): 56 data bytes
64 bytes from 192.168.4.1: seq=0 ttl=64 time=0.192 ms

四 macvlan网络

A. 什么是macvlan:

macvlan 本质上是一种网卡虚拟化技术 macvlan 本身是 linux kernel 模块,允许在同一个物理网卡上配置多个 MAC 地址,即多个 interface,每个 interface 可以配置自己的 IP。

使用macvlan可以实现容器跨主机通信:

B. 创建macvlan:

首先需要再开一台虚拟机,创建好docker环境,然后两台机器都执行下列命令

代码语言:javascript复制
docker network create --driver macvlan 
  --subnet 10.0.0.0/24 
  --gateway 10.0.0.254 
  -o parent=eth0   macvlan_1

说明:docker不会为macvlan创建网关,所以这里的网关要事先存在 macvlan最好自己手动管理IP地址,不要自动分配,容易IP冲突

两台docker主机上分别创建容器测试:

  1. docker01: docker run -it --network macvlan_1 --ip=10.0.0.111 busybox:latest /bin/sh
  2. docker02: docker run -it --network macvlan_1 --ip=10.0.0.112 busybox:latest /bin/sh

五 overlay网络

overlay网络是基于 VxLAN 的 隧道网络,VxLAN 可将二层数据封装到 UDP 进行传输,VxLAN 提供与 VLAN 相同的以太网二层服务,但是拥有更强的扩展性和灵活性。 不同overlay网络是互相隔离的,要相互通信的话,也是需要把容器加入多个网络才行. Docerk overlay 网络需要一个 key-value 数据库用于保存网络状态信息,包括 Network、Endpoint、IP 等。Consul、Etcd 和 ZooKeeper 都支持,这里使用 Consul。

A. 环境准备工作

  1. 分别修改docker配置文件 docker01、02上都增加如下配置在daemon.json文件中vim /etc/docker/daemon.json { "cluster-store": "consul://10.0.0.11:8500", "cluster-advertise": "10.0.0.12:2376" } systemctl daemon-reload systemctl restart docker # cluster-store是consul的地址 # cluster-advertise是自己的地址
  2. docker01上运行consuldocker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap 运行成功后,可以访问consul的web页:http://10.0.0.11:8500/ui/#/dc1/kv/

B. overlay网络功能测试

  1. 创建overlay网络(任意主机) 由于overlay信息会写入数据库,所以在docker02上创建overlay网络,docker01上是可以看到的[root@docker02 ~]# docker network create -d overlay olay-1 [root@docker01 ~]# docker network ls|grep olay-1 bda0ae8345d8 olay-1 overlay global [root@docker01 ~]# docker network inspect olay-1|grep -A1 Subnet "Subnet": "10.0.1.0/24", "Gateway": "10.0.1.1"
  2. 启动容器测试[root@docker01 ~]# docker run --rm --network olay-1 busybox ip a s|grep inet inet 127.0.0.1/8 scope host lo inet 10.0.1.2/24 brd 10.0.1.255 scope global eth0 inet 172.19.0.2/16 brd 172.19.255.255 scope global eth1 [root@docker02 ~]# docker run --rm --network olay-1 busybox ip a s|grep inet inet 127.0.0.1/8 scope host lo inet 10.0.1.2/24 brd 10.0.1.255 scope global eth0 inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1
  3. 测试结果说明 上面的结果中,每个容器都分别有eth0和eth1两个网卡,其中eth0属于overlay网络,用于跨主机通信,eth1用于与宿主机通信 overlay网络支持docker dns server,支持使用容器名进行通信

B. overlay IPAM

docker 默认为 overlay 网络分配 24 位掩码的子网(10.0.X.0/24),所有主机共享这个 subnet,容器启动时会顺序从此空间分配 IP。当然我们也可以通过--subnet指定 IP 空间。

代码语言:javascript复制
docker network create -d overlay --subnet 10.22.1.0/24 ov_net3

0 人点赞