docker的网络实现是学习docker的重中之重,首先我们要了解Docker的网络实现其实就是利用了Linux上的网络名字空间和虚拟网络设备(特别是 veth pair)。
基本原理
要实现网络通信,机器需要至少一个网络接口(物理接口或者虚拟接口)来收发数据包;此外,如果不同子网之间要进行通信,需要路由机制。
Docker中的网络接口默认都是虚拟的接口,虚拟接口的优势之一是转发效率较高。Linux通过在内核中进行数据复制来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中,对于本地系统和容器内系统看来就像是一个正常的以太网卡,只是它不需要真正同外部网络设备通信,速度要很快。
Docker容器网络就利用了这项技术,它在本地主机和容器内分别创建了一个虚拟接口,并让它们彼此连通 (这一对接口就叫做 veth pair)
veth pair
- 我们发现这个容器带来的网卡 都是成对成对出现的,就是一对的虚拟设备接口,一端连着协议,一端彼此相连。
- 正因为有这个特性,所以它通常作为桥梁,链接各种虚拟网络设备的。
创建网络参数
Docker创建容器的时候,会执行如下操作
- 创建一对虚拟接口,分别放到本地主机和新容器中;
- 本地主机一端桥接到默认的docker 0 或指定网桥上,并且具有一个唯一的名字,如 veth148b541. 执行run成功后,我们可以使用 ifconfig 查看就会发现多了个虚拟网卡
- 容器一端放到新容器中,并修改名字作为eth0.这个接口只在容器的名字空间可见;
- 从网桥可用地址段中获取一个空闲地址分配给容器的eth0,并配置默认路由到桥接网卡 veth148b541
完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其它容器和其它网络
常见的网络模式
network
network 比较典型的网络模式主要有四种,这四种基本满足我们单机容器的所有场景。
null 空网络模式
null 空网络模式:可以帮助我们构建一个没有网络接入的容器环境,以保障数据安全。相当于一个没有联网的计算机。
作用:
- 保持一个较安全的环境,确保数据不会被他人从网络窃取。可处理一些纯计算任务
格式:
docker run --net=none
使用–net=none 启动容器,并且使用ifconfig查看下容器内的网络配置,可以看到容器内除了 Net Namespace 自带的 lo 网卡外并没有创建任何的虚拟网卡,然后我们再使用 route -n 命令查看一下路由信息:
$ docker run --net=none -it busybox
$ / # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
$ / # route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
这时看到容器内也并没有配置任何路由信息。
bridge
Docker的bridge网络是启动容器时默认的网络模式;
主要作用:
- 实现容器与容器的互通,可以从一个容器直接通过容器IP访问到另一个容器
- 实现主机与容器的互通,在容器内启动的业务,可以从主机直接请求。
实现技术:
- Linux veth
veth 是linux中的虚拟设备接口,veth都是成对出现的,它在容器中,通常充当一个桥梁。veth 可以用来连接虚拟网络设备。例如:veth 可以用来连通两个 Net Namespace,从而使得两个 Net Namespace之间可以互相访问。- Linux bridge
是一个虚拟设备,用来连接网络的设备,相当于物理网络环境中的交换机,linux bridge可以用来转发两个 Net Namespace 内的流量。
自定义网桥命令
$ root@VM-8-11-ubuntu:/home/lighthouse# docker network create my-net
e7fe575b4731606c802e8fb35242aaebad8210e0c0c97870ef7e2fd21bd973dd
$ root@VM-8-11-ubuntu:/home/lighthouse# docker network ls
NETWORK ID NAME DRIVER SCOPE
828b93373c17 bridge bridge local
0ab28e475dc6 host host local
e7fe575b4731 my-net bridge local # 上面创建的bridge模式
e4c628cc77db none null local
$ root@VM-8-11-ubuntu:/home/lighthouse# docker network rm my-net # 删除命令
my-net
docker network create 可以指定子网、IP地址范围、网关和其它选项。具体可以执行 docker network create --help 或者 docker network create.
host主机网络模式
host 主机网络模式:可以让容器内的进程共享主机网络,从而监听或修改主机网络。
使用host主机网络模式时:
- libnetwork 不会为容器创建新的网络配置和Net Namespace。
- Docker 容器中的进程直接共享主机的网络配置,可以直接使用主机的网络信息,此时,在容器内监听的端口,也将直接占用到主机的端口。
- 除了网络共享主机的网络外,其它的包括进程、文件系统、主机名等都是与主机隔离的。
使用场景:
- 主机模式网络可用于优化性能,在容器需要处理大量端口的情况下,由于它不需要网络地址转换(NAT),并且也没有为每个端口创建"用户空间代理"
$ root@VM-8-11-ubuntu:~# docker run --name=mynginx --net=host -d nginx
3553c45f3846a67156e0b35fe698f8b5bb757690923972d9c9e5d65e5005c232
$ root@VM-8-11-ubuntu:~# docker exec -it mynginx cat /etc/hosts
#
127.0.1.1 localhost.localdomain VM-8-11-ubuntu
127.0.0.1 localhost
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
这时查看容器链路接口,与主机是一致的。而且我们访问端口也是可以访问的了
container 网络模式
container 网络模式:可以将两个容器放在同一个网络命名空间内,让两个业务通过localhost即可实现访问。
此模式下新创建的容器不会创建自己的网卡,配置自己的Ip,而是和一个指定的容器共享IP、端口范围等。同样的两个容器除了网络方面相同之外,其它的如文件系统,进程列表等都是隔离的。
主要作用:
将两个容器放到同一网络空间中,可以直接通过localhost本地访问
使用命令:
–net container: 已运行的容器名称|ID 或者 --network container:已运行的容器名称| ID
$root@VM-8-11-ubuntu:~# docker run -it --name=mybusy -d busybox
$root@VM-8-11-ubuntu:~# docker run -it --name=mybusy02 -d --net=container:mybusy busybox
# 查看容器02的ip地址
$root@VM-8-11-ubuntu:~# docker exec -it mybusy02 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
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@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 宿主的ip地址
$root@VM-8-11-ubuntu:~# docker exec -it mybusy ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
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@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
我们可以发现容器 mybusy02 直接用了 mybusy的网卡信息,这时我们看看暂停宿主容器mybusy
$root@VM-8-11-ubuntu:~# docker stop mybusy
mybusy
$root@VM-8-11-ubuntu:~# docker exec -it mybusy02 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
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
这时我们发现mybusy02的容器就只剩下 lo了。当重启mybusy容器后,就又可以获得网卡信息了。
总结
常用网络模式 | 作用 | 业务场景 |
---|---|---|
null网络空间模式 | 不提供任何容器网络 | 处理一些保密数据,处于安全考虑,需要一个隔离的网络环境执行一些纯计算任务 |
bridge桥接模式 | 使得容器和容器之间网络可以互通 | 容器需要实现网络通信或者提供网络服务 |
host主机网络模式 | 让容器内的程序可以使用到主机的网络 | 容器需要控制主机网络或者用主机网络提供服务 |
container网络模式 | 将两个容器放到同一网络空间中,可以直接通过localhost本地访问 | 两个容器之间需要直接通过localhost通信,一般用于网络接管或者代理外部请求 |
- 所有的容器不指定网络的情况下,都是docker 0路由的,docker会给我们的容器分配一个默认的可用IP.
- docker 常使用的是linux的桥接,宿主机中是一个Docker容器的网桥 docker 0