Docker 网络实现的原理
Docker 使用Linux桥接,在宿主机虚拟一个Docker容器网桥(dockere),docker启动一个容器时会根据
docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。
因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker容器网络就很好地利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做veth pair)。
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种
①Bridge:默认这个模式,此模式会为每一个容器分配Ip(docker 0 虚拟网卡),并且将容器连接到一个docker虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机的通信
②host:容器不会配置Ip,虚拟网卡,而是使用宿主机的Ip和端口
③None:可以说单机自己玩了,关闭网络功能
④Container:创建的容器不会创建自己的网卡,配置IP,而是和一个指定的容器共享IP,端口范围
⑤自定义网络:自定义网络,其实就是bridge的升级版
一、Bridge 桥接模式
bridge模式是docker默认的,也是开发者最常使用的网络模式。在这种模式下,docker为容器创建独立的网络栈,保证容器内的进程使用独立的网络环境,实现容器之间、容器与宿主机之间的网络栈隔离。同时,通过宿主机上的dockere网桥,容器可以与宿主机乃至外界进行网络通信。
其网络模型可以参考下图:
从上面的网络模型可以看出,容器从原理上是可以与宿主机乃至外界的其他机器通信的。
同一宿主机上,容器之间都是连接掉docker0这个网桥上的,它可以作为虚拟交换机使容器可以相互通信。
然而,由于宿主机的IP地址与容器veth 的IP地址均不在同一个网段,故仅仅依靠veth 和namespace的技术
还不足以使宿主机以外的网络主动发现容器的存在。为了使外界可以方位容器中的进程,docker采用了端口绑定
的方式,也就是通过iptables的NAT,将宿主机上的端口端口流量转发到容器内的端口上。
-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
上面的172.17.0.2即为bridge模式下,创建的容器IP。
很明显,bridge模式的容器与外界通信时,必定会占用宿主机上的端口,从而与宿主机竞争端口资源,
从而与宿主机竞争端口资源,对宿主机端口的管理会是一个比较大的问题。同时,
由于容器与外界通信是基于三层上iptables NAT,性能和效率上的损耗是可以预见的。
获取有关Docker镜像 nginx:1.26 的详细信息
docker inspect nginx:1.26
二、Host通信模式
docker run -itd --name=test --net=host busybox
host模式:使用--net=host 指定
容器不会获得一个独立的network namespace,而是与宿主机共用一个。
这就意味着容器不会有自己的网卡信息,而是使用宿主机的。
容器除了网络,其他都是隔离的。相当于VMware中的桥接模式,
与宿主机在同一个网络中,但是没有独立IP地址。
三、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
四、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
五、自定义模式
升级版本的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 inspect networktest3
docker exec -it networktest1 /bin/sh
ping networktest3
docker 可以自定义网络,指定自己的IP、网关,在创建容器的时候可以把容器指定到自己创建的网络中 在创建的容器中,容器的IP地址都是自己定义地址的地址池来分配的自己创建的网络模式中,容器之间可以通过容器名字来访问,如ping networktest3
# 自定义网络
docker network create --driver bridge --subnet 192.168.20.0/24 --gateway 192.168.20.1 mynet
# 使用自定义网络创建容器
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是通的
我们把net-test3加入到我们创建的网络mynet中再来试试
docker network connect mynet net-test3
容器互联如何实现
---link 用于在容器之间建立一条专门的网络通信隧道,即在源容器和接受容器之间建立一条隧道,接受容器就可以看到源容器的指定信息
---link能够实现容器之间通过容器名通信,共享环境变量
注意:这里的环境变量是共享源容器的环境变量,连接的容器的环境变量不会被看到
---link 主要用于解决两个容器通过ip地址连接地址会变的问题
docker run -itd --name=test01 busybox
docker run -itd --name=test02 busybox
docker inspect test01
docker inspect test02
测试实验能否通
创建一个test03 link test01
docker run -itd --name=test03 --link test01 busybox
docker exec -it test03 /bin/sh
ping test01
结果------test03是ping不通test02的容器名的,只能通IP地址
六、博客测试
创建启动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
登录宿主机的80
192.168.80.25:80