Docker 网络实现的原理

Docker 使用Linux桥接,在宿主机虚拟一个Docker容器网桥(dockere),docker启动一个容器时会根据

docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。

因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

Docker容器网络就很好地利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做veth pair)。

第九节  Docker的5种网络及实验_docker

Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络时无法寻址到的,这也意味着外部网络无法直接通过
Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主机(端口映射),即docker run
创建容器的时候通过-p或-P参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。

随机映射端口
docker run-d--name test1-P nginx:latest
指定映射端口
docker run-d--name test2-p 1212:80 nginx:latest

【容器内部更新----以nginx镜像为例】
docker exec -it nginx01 /bin/bash # 进入容器内部
apt update # 列出更新apt的下载源
apt upgrade # 更新apt的下载源
apt install -y iputils-ping #安装ping
apt install -y iproute2 #安装ipaddr
apt install -y net-tools #安装ifconfig
exit # 安装完成之后,退出容器
docker commit nginx01 custom-nginx:1.0 # 使用docker commit创建自定义镜像
docker run -d -P --name nginx02 custom-nginx:1.0 # 使用自定义的镜像创建容器
docker exec -it nginx02 ping www.baidu.com # 容器直接ping百度域名

第九节  Docker的5种网络及实验_docker_02

docker的网络模式汇总后有以下5种

①Bridge:默认这个模式,此模式会为每一个容器分配Ip(docker 0 虚拟网卡),并且将容器连接到一个docker虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机的通信

②host:容器不会配置Ip,虚拟网卡,而是使用宿主机的Ip和端口

③None:可以说单机自己玩了,关闭网络功能

④Container:创建的容器不会创建自己的网卡,配置IP,而是和一个指定的容器共享IP,端口范围

⑤自定义网络:自定义网络,其实就是bridge的升级版

一、Bridge 桥接模式

bridge模式是docker默认的,也是开发者最常使用的网络模式。在这种模式下,docker为容器创建独立的网络栈,保证容器内的进程使用独立的网络环境,实现容器之间、容器与宿主机之间的网络栈隔离。同时,通过宿主机上的dockere网桥,容器可以与宿主机乃至外界进行网络通信。

其网络模型可以参考下图:

第九节  Docker的5种网络及实验_nginx_03

第九节  Docker的5种网络及实验_IP_04

从上面的网络模型可以看出,容器从原理上是可以与宿主机乃至外界的其他机器通信的。

同一宿主机上,容器之间都是连接掉docker0这个网桥上的,它可以作为虚拟交换机使容器可以相互通信。

然而,由于宿主机的IP地址与容器veth 的IP地址均不在同一个网段,故仅仅依靠veth 和namespace的技术

还不足以使宿主机以外的网络主动发现容器的存在。为了使外界可以方位容器中的进程,docker采用了端口绑定

的方式,也就是通过iptables的NAT,将宿主机上的端口端口流量转发到容器内的端口上。

第九节  Docker的5种网络及实验_nginx_05

-net=bridge
 默认网络,docker启动之后也会创建一个docker0 网桥,默认创建的容器也是添加到这个网桥
 docker run -itd --name=nginx-test -p 80:80 nginx:1.26
 
在宿主机上,可以通过iptables -t nat -L -n,查到一条DNAT规则:
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80

第九节  Docker的5种网络及实验_docker_06

第九节  Docker的5种网络及实验_nginx_07

上面的172.17.0.2即为bridge模式下,创建的容器IP。

很明显,bridge模式的容器与外界通信时,必定会占用宿主机上的端口,从而与宿主机竞争端口资源,

从而与宿主机竞争端口资源,对宿主机端口的管理会是一个比较大的问题。同时,

由于容器与外界通信是基于三层上iptables NAT,性能和效率上的损耗是可以预见的。

获取有关Docker镜像 nginx:1.26 的详细信息
docker inspect nginx:1.26

第九节  Docker的5种网络及实验_IP_08

二、Host通信模式

docker run -itd --name=test  --net=host busybox

host模式:使用--net=host 指定

容器不会获得一个独立的network namespace,而是与宿主机共用一个。
这就意味着容器不会有自己的网卡信息,而是使用宿主机的。
容器除了网络,其他都是隔离的。相当于VMware中的桥接模式,
与宿主机在同一个网络中,但是没有独立IP地址。

第九节  Docker的5种网络及实验_IP_09

三、none 模式

使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。

这个Docker容器没有网卡、IP、路由等信息。这种网络模式下容器只有lo回环网络,没有其他网卡。

这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

-net=none获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。

docker run -itd --net=none busybox:latest

docker exec -it ce759c584a6 /bin/sh

第九节  Docker的5种网络及实验_nginx_10

第九节  Docker的5种网络及实验_IP_11

四、Container模式

在理解了Host 模式后,这个模式也就好理解了。
这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace
(网络命名空间),而不是和宿主机共享。
新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。
同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
两个容器的进程可以通过10网卡设备通信。

Container
-net=container:Name/ID与指定的容器使用同一个network namespace,
具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的。

docker run -itd  --net=container:nginx-test busybox
docker exec -it fa4f6b91a1e3 /bin/sh

第九节  Docker的5种网络及实验_IP_12

第九节  Docker的5种网络及实验_IP_13

五、自定义模式

升级版本的bridge
docker 的bridge模式,无法指定IP,需要规定的docker的网络 地址就需要自己去定义docker的网络地址段

docker network create network-test
docker network ls
docker run -itd --name=networktest1 --net=network-test busybox

docker run -itd --name=networktest3 --net=network-test busybox

第九节  Docker的5种网络及实验_IP_14

docker inspect networktest3

第九节  Docker的5种网络及实验_IP_15

docker exec -it networktest1 /bin/sh

ping networktest3

第九节  Docker的5种网络及实验_docker_16

docker 可以自定义网络,指定自己的IP、网关,在创建容器的时候可以把容器指定到自己创建的网络中 在创建的容器中,容器的IP地址都是自己定义地址的地址池来分配的自己创建的网络模式中,容器之间可以通过容器名字来访问,如ping networktest3


# 自定义网络

docker network create --driver bridge --subnet 192.168.20.0/24 --gateway 192.168.20.1 mynet

第九节  Docker的5种网络及实验_docker_17

# 使用自定义网络创建容器

docker run -itd --name=net-test1 --network mynet busybox

docker run -itd --name=net-test2 --network mynet busybox


默认创建的容器是无法ping通这两个容器的

docker run -itd --name=net-test3 busybox

而net-test1 ping net-test2是通的

第九节  Docker的5种网络及实验_nginx_18

我们把net-test3加入到我们创建的网络mynet中再来试试

docker network connect mynet net-test3

第九节  Docker的5种网络及实验_docker_19

第九节  Docker的5种网络及实验_nginx_20

容器互联如何实现

---link 用于在容器之间建立一条专门的网络通信隧道,即在源容器和接受容器之间建立一条隧道,接受容器就可以看到源容器的指定信息

---link能够实现容器之间通过容器名通信,共享环境变量

注意:这里的环境变量是共享源容器的环境变量,连接的容器的环境变量不会被看到

---link 主要用于解决两个容器通过ip地址连接地址会变的问题



docker run  -itd --name=test01 busybox

docker run  -itd --name=test02 busybox

docker inspect test01

docker inspect test02

第九节  Docker的5种网络及实验_docker_21

第九节  Docker的5种网络及实验_docker_22

第九节  Docker的5种网络及实验_nginx_23

测试实验能否通

第九节  Docker的5种网络及实验_IP_24

创建一个test03 link test01

docker run -itd --name=test03  --link test01 busybox

docker exec -it test03 /bin/sh

ping test01

结果------test03是ping不通test02的容器名的,只能通IP地址

第九节  Docker的5种网络及实验_nginx_25

六、博客测试

创建启动MySQL容器
docker run  -itd    --name db   --restart=always    -e  MYSQL_ROOT_PASSWORD=redhat   -e  MYSQL_DATABASE=blog  mysql:5.6

创建启动源容器word press
docker run  -itd  --name myblog  --restart=always   -v /web:/var/www/html   -p 80:80   --link   db:mysql   wordpress

第九节  Docker的5种网络及实验_docker_26

登录宿主机的80

192.168.80.25:80

第九节  Docker的5种网络及实验_docker_27