Docker网络实现

《docker入门与实践》笔记
Docker的网络其实是利用Linux上的网络命名空间和虚拟网络设备(veth pair)实现的。

一、基本原理

  • 直观上看,要实现网络通信,机器需要至少一个网络接口(物理网络接口或虚拟网络接口)与外界相通,并可以收发数据包;此外,如果要实现不同子网之间的通信,需额外配置路由。
  • Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高。这是因为Linux通过内核中进行数据复制来实现虚拟接口之间的数据转发,即发送接口的发送缓存中的数据包将被直接复制到接收皆苦的接受缓存中,无需通过外部物理网络设备进行交换。这个拷贝实在内核态直接完成,不需要两态切换。
  • Docker容器网络很好的利用了Linux的虚拟网络技术,它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连同。
Docker的网络实现

二、网络创建过程

  1. 创建一对虚拟接口,分别放到本地主机和新容器的命名空间中。
// 创建一个容器
docker run -it --rm busybox 
  1. 本地主机一端的虚拟接口连接到默认的docker0网桥或指定的网桥上,并具有一个以veth开头的唯一名字,如:veth22f630c
// 查看主机分配的veth接口
ifconfig 或者ip addr show
ifconfig
// 查看veth22f630c接口连接到docker0网桥上
brctl show
brctl show
  1. 容器一端的虚拟接口将放到新创建的容器中,并修改名字为eth0。这个接口只有容器的命名空间可见。
ifconfig
  1. 从网桥可用地址段中获取一个空闲的地址分配给容器的eth0(例如: 172.17.0.2/16),并配置默认网关为docker0网卡的内部接口docker0的IP地址(例如:172.17.0.1/16)
// 查看docker0的IP
ifconfig docker0
ifconfig docker0
// 查看容器的IP,网关
docker inspect fc8da94bafdd(containerid)
docker inspect containerid
  1. 完成这些之后,容器就可以使用eth0虚拟网卡来连接其他容器和访问外部网络了。

三、网络配置

docker运行的时候通过--net参数指定容器的网络配置,有4个可选值bridge、host、container、none:

  • --net=bridge:默认值,在Docker网桥上为容器创建新的网络栈。
  • --net=host:告诉 Docker不要将容器网络放到隔离的命名空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机其他root进程一样打开低范围的端口,可以访问本地网络服务比如D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用-- privileged=true参数,
    容器甚至会被允许直接配置主机的网络堆栈。
  • --net=container:让Docker将新建容器的进程放到一个已存在容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已存在的容器共享IP地址和端口等网络资源,两者进程可以直接通过lo环回接口通信。
  • --net=none:让Docker将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自己进行配置。

四、网络配置细节

用户使用--net=none后,Docker将不对容器网络进行配置。下面,将手动完成配置网络的整个过程。

  1. --net=none创建一个容器:
// 创建容器(containerid:fc1f71546394)
docker run -it --rm --net=none busybox
  1. 在本地主机查找容器的进程id,并为它创建网络命名空间:
// 查看容器的进程id
docker inspect -f "{{.State.Pid}}" fc1f71546394
docker inspect -f "{{.State.Pid}} fc1f71546396"
// 为容器创建网络命名空间
pid=58930
mkdir -p /var/run/netns
ln -s /proc/$pid/ns/net /var/run/netns/$pid
  1. 查看桥接网卡的IP和子网掩码信息:
```
ip addr show docker0
```
ip addr show docker0
  1. 创建一对"veth pair"接口veth_host和veth_container,绑定veth_host到网桥docker0,并启动veth_host:
// 创建一对veth pair
sudo ip link add veth_host type veth peer name veth_container
// 将veth_host接口添加到docker0网桥上
sudo brctl addif docker0 veth_host
// 激活veth_host接口
sudo ip link set veth_host up
// 查看veth_host接口信息
ifconfig veth_host
// 查看docker0情况
brctl show
创建veth pair
  1. 将veth_container接口放到容器的网络命名空间,命名为eth0,启动它并配置一个可用IP(172.17.0.3/16)和默认网关(172.17.0.1):
// 将veth_container接口放到容器的网络命名空间
sudo ip link set veth_container netns $pid
// veth_container 设置容器内的别名eth0
sudo ip netns exec $pid ip link set dev veth_container name eth0
// 激活容器内的eth0接口 
sudo ip netns exec $pid ip link set eth0 up
 // 给容器内的eth0设置ip
sudo ip netns exec $pid ip addr add 172.17.0.3/16 dev eth0
 // 给容器内的设置默认网关
sudo ip netns exec $pid ip route add default via 172.17.0.1
设置veth_container
  1. 以上就是Docker配置网络的具体过程
    当容器终止后,Docker会清空容器,容器内的网络接口会随着网络命名空间一起被清除,veth_host 接口也会自动从docker0卸载并清除。

你可能感兴趣的:(Docker网络实现)