0x00 docker网络模式——bridge
30个人用各自的电脑和电脑屏幕看电影
Docker服务默认会创建一个docker0网桥(其上有一个docker0内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker默认指定了docker0接口的IP地址和子网掩码,让主机和容器之间可以通过docker0网桥相互通信。
docker network inspect bridge | tail -n 20
docker network inspect bridge | grep name
1、Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Dcoker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信
2、Docker run的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是eth0,在宿主机可以看到docker0和自己create的network(后面讲)eth0、eth1、eth2...代表网卡一,网卡二,网卡三....,lo代表本地回环。
3、网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配
3-1、整个宿主机的网桥模式都是docker0,类似于一个交换机有一堆接口(veth),在本地主机和容器内分别创建一个虚拟接口,并让他们彼此接通。(这样一对接口叫veth pair)
3-2、每个容器实例内部也有一块网卡,每个网卡接口叫eth0
3-3、docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都链接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的IP,此时两个容器的网络就是互通的。
1、演示
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker ps - n 2
进入其中一个容器,再次查看自己的网卡。
2、bridge总结
宿主机——veth
容器网卡——eth0
两两匹配,veth统一由docker0接管
0x01 Host模式
30个人,在电影院中看一个大屏幕
直接使用宿主机的IP地址与外界进行匹配,不再需要额外进行网桥NAT转换。
容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace,容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
我们可以通过docker network inspect
来查看
案例
docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8 #这样的写法不正确,因为host模式默认使-p无效
为什么不被推荐呢?docker启动时指定--network=host
或-net=host
,如果还指定了-p
映射端口,那这个时候就会有此警告。并且通过-p设置的参数将不会起到任何作用。端口号会以主机端口号为主,重复时递增。可以看到下图,就是没有任何的端口映射关系。
解决:解决的办法就是使用docker的其他网络模式,例如--network=bridge
,这样就可以解决问题,或者直接无视。。。
那么问题来了,没有-p设置的端口,如何访问启动的tomcat??
在CentOS里面用默认的火狐浏览器访问容器内的tomcat83看到访问成功,因为此时容器的IP借用主机的,所以容器共享宿主机网络IP,这样的好处就是外部主机与容器可以直接通信。
#去掉了-p参数
docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8
#访问http://宿主机ip:8080,即可访问到tomcat
0x02 none 模式
30个人不看电影,用自己的电脑看还是去电影院看,没有定下来。
在none模式下,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo,需要我们自己为Docker容器添加网卡
禁用了网络设置,只有lo标识。
docker network inspect
docker run -d -p 8084:8080 --network none --name=tomcat84 billygoo/tomcat8-jdk8
0x03 container模式
30个人用各自电脑、各自电脑屏幕来看电影,突然有一个人的电脑坏了,和旁边的人一起看。
说白了,我借用别人的。两张嘴共用一个吸管喝奶茶。
新建的容器和已经存在的一个容器共享一个网络IP配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP。而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
案例
docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8
docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8
但是当我们输入完成后,会发现出现了问题,这是一个坑!
相当于tomcat86和85公用同一个IP同一个端口,导致冲突,本案例使用tomcat演示不合适。
我这里有一个问题,就是为什么bridge的时候,开两个tomcat没有冲突?
这就涉及到了一个IP多个端口的问题了。当时在学习建立网站的时候,一个IP可以建立多个网站,使用不同的端口即可。那么bridge,每个容器都有自己独立的IP,当然就不会冲突了。
换一个镜像演示:Alpine
Alpine Linux是一款独立的、非商业的通用Linux发行版,专为追求安全性、简单性和资源效率的用户而涉及,可能很多人没听说过这个Linux发行版,但是经常用Docker的朋友可能都用过,因为他小,简单、安全而著称。所以作为基础镜像是一个非常好的选择,可谓是麻雀虽小五脏俱全,镜像非常小巧,不到6M的大小,所以特别适合容器打包。
docker search alpine --limit 5
docker pull alpine
docker run -it --name=alpine1 alpine /bin/sh #NOTICE!!!!IS /bin/sh!!
docker run -it --network container:alpine1 --name=alpine2 alpine /bin/sh
当alpine1停掉后,alpine2的网直接就没了
0x04 自定义网络
docker link,是一个过时的技术。不用管了。已经被自定义网络替代了。
我们都知道了,Docker网络默认三种配置,但是为什么要有自定义网络呢?
希望所有的容器分门别类,井井有条,在各自的网络里面和谐共存,并且能够完成网络之间的通信。之前的问题:1、容器间的互联和通信以及端口映射 2、容器IP变动的时候可以通过服务名直接网络通信而不受到影响。
1、使用自定义网络前
1、运行两个tomcat容器,默认网络bridge
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
docker exec -it tomcat81 bash
docker exec -it tomcat82 bash
2、两个机器互相ping,能够ping通,没任何毛病
3、ping服务名,失败。
这就是不使用自定义网络的问题,无法ping通服务名。可能会有人说了:谁TM ping服务名啊,ping IP不行么?
问题
之前我们试验过,docker环境中的各种主机IP是会发生变化的,即当此容器坏了,再启动一个容器,IP地址是会变的。所以我们必须保证服务能够ping通。
2、使用自定义网络之后
1、自定义桥接网络,自定义网络默认使用的是桥接网络bridge
2、新建自定义网络
docker network ls
docker network create zzyy_network
3、新建容器加入上一步新建的自定义网络
docker run -d -p 8081:8080 --network zzyy_network --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --network zzyy_network --name tomcat82 billygoo/tomcat8-jdk8
4、互相ping测试,成功
docker exec -it tomcat81 bash
docker exec -it tomcat82 bash
ping tomcat82
ping tomcat 81
在工作上一定要写死服务名,不能写死IP,除非你能保证地球不爆炸,IP不会变。多个docker服务群一定要写死服务名。
但是为什么加入自定义就能ping通服务名?
老师没有解释这个,但是看了一条弹幕说的挺有道理:
自定义网桥的容器会开启自己的dns,把名称和IP的对应关系发送到docker维护的dns里,docker里有了dns信息,自然可以做地址转换了,就这么easy
3、结论
重要的事情说三遍:
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名即服务名都能通)
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名即服务名都能通)
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名即服务名都能通)