文章目录
- 理解Docker0
- Docker 是如何处理容器网络访问的?
- Docker0网络模型图
- 容器互联--Link
- 自定义网络
- 网络连通
理解Docker0
查看本机IP
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
default 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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state
UP group default qlen 1000
link/ether 00:16:3e:30:27:f4 brd ff:ff:ff:ff:ff:ff
inet 172.17.90.138/20 brd 172.17.95.255 scope global dynamic eth0
valid_lft 310954997sec preferred_lft 310954997sec
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state
UP group default
link/ether 02:42:bb:71:07:06 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
valid_lft forever preferred_lft forever
有三个网络
lo 127.0.0.1 #本机回环地址
eth0 172.17.90.138 #阿里云的私有IP
docker0 172.18.0.1 #docker网桥
Docker 是如何处理容器网络访问的?
我们实际场景中,我们开发了很多微服务项目,那些微服务项目都要连接数据库,需要指定数据库的url地
址,通过ip。但是我们用Docker管理的话,假设数据库出问题了,我们重新启动运行一个,这个时候数
据库的地址就会发生变化,docker会给每个容器都分配一个ip,且容器和容器之间是可以互相访问的。
我们可以测试下容器之间能不能ping通
启动tomcat01
docker run -d -P --name tomcat01 tomcat
查看tomcat01的ip地址,docker会给每个容器都分配一个ip!
docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
default 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
122: eth0@if123: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
state UP group default
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever
思考,我们的linux服务器是否可以ping通容器内的tomcat ?
ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.070 ms # 可以ping通!
原理
每一个安装了Docker的linux主机都有一个docker0的虚拟网卡。这是个桥接网卡,使用了veth-pair技术!
我们再次查看主机的 ip addr
ip addr
原来我们有三个网络,我们在启动了个tomcat容器之后,多了一个123的网络!
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
default 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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state
UP group default qlen 1000
link/ether 00:16:3e:30:27:f4 brd ff:ff:ff:ff:ff:ff
inet 172.17.90.138/20 brd 172.17.95.255 scope global dynamic eth0
valid_lft 310954997sec preferred_lft 310954997sec
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state
UP group default
link/ether 02:42:bb:71:07:06 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
valid_lft forever preferred_lft forever
123: vethc8584ea@if122: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
noqueue master docker0 state UP group default
link/ether 0a:4b:bb:40:78:a7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
我们启动了一个tomcat01,主机的ip地址多了一个 123: vethc8584ea@if122
每启动一个容器,linux主机就会多了一个虚拟网卡
然后我们在tomcat01容器中查看容器的ip是 122: eth0@if123
我们再启动一个tomcat02观察
docker run -d -P --name tomcat02 tomcat
然后发现linux主机上又多了一个网卡 125: veth021eeea@if124:
我们看下tomcat02的容器内ip地址是 124: eth0@if125:
docker exec -it tomcat02 ip addr
观察现象
tomcat — linux主机 vethc8584ea@if122 ---- 容器内 eth0@if123
tomcat — linux主机 veth021eeea@if124 ---- 容器内 eth0@if125
相信到了这里,大家应该能看出点小猫腻了吧!只要启动一个容器,就有一对网卡veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。
正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!
“Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等,以此构建出非常复杂的虚拟网络
结构,比如 OpenStack Neutron。
我们来测试下tomcat01和tomcat02容器间是否可以互相ping通
docker exec -it tomcat02 ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.110 ms
结论:容器和容器之间是可以互相访问的。
Docker0网络模型图
结论
tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动默认都是docker0网络。
docker默认会给容器分配一个可用ip。
小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并
让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中
进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容
器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
容器互联–Link
思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们
能不能使用服务名访问呢?
jdbc:mysql://mysql:3306,这样的话哪怕mysql重启,我们也不需要修改配置了!docker提供了 --link的操作!
我们使用tomcat02,直接通过容器名ping tomcat01,不使用ip
docker exec -it tomcat02 ping tomcat01
发现ping不通
ping: tomcat01: Name or service not known
我们再启动一个tomcat03,但是启动的时候连接tomcat02
docker run -d -P --name tomcat03 --link tomcat02 tomcat
这个时候,我们就可以使用tomcat03 ping通tomcat02 了
docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.18.0.3): icmp_seq=1 ttl=64 time=0.093 ms
64 bytes from tomcat02 (172.18.0.3): icmp_seq=2 ttl=64 time=0.066 ms
再来测试,tomcat03 是否可以ping tomcat01 失败
docker exec -it tomcat03 ping tomcat01
ping: tomcat01: Name or service not known
再来测试,tomcat02 是否可以ping tomcat03 反向也ping不通
docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
思考,这个原理是什么呢?我们进入tomcat03中查看下host配置文件
docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3 tomcat02 b80da266a3ad # 发现tomcat2直接被写在这里
172.18.0.4 a3a4a17a2b70
所以这里其实就是配置了一个 hosts 地址而已!
原因:–link的时候,直接把需要link的主机的域名和ip直接配置到了hosts文件中了。
–link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式
自定义网络
基本命令查看
查看所有网络
docker network ls
NETWORK ID NAME DRIVER SCOPE
4eb2182ac4b2 bridge bridge local
ae2b6209c2ab host host local
c037f7ec7e57 none null local
所有网路模式
网络模式 | 配置 | 说明 |
---|---|---|
bridge模式 | –net=bridge | 默认值,在Docker网桥docker0上为容器创建新的网络栈 |
none模式 | –net=none | 不配置网络,用户可以稍后进入容器,自行配置 |
container模式 | –net=container:name/id | 容器和另外一个容器共享Network namespace。kubernetes中的pod就是多个容器共享一个Networknamespace。 |
host模式 | –net=host | 容器和宿主机共享Network namespace |
用户自定义 | –net=自定义网络 | 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络 |
查看一个具体的网络的详细信息
docker network inspect 4eb2182ac4b2
[
{
"Name": "bridge",
"Id":
"4eb2182ac4b23487e1eb6e06df56c71ab6f0adc7ccc0962b4747d0eed5ad6690",
"Created": "2020-05-11T15:44:20.131441544+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
// 默认docker0是管理这个子网范围内的。0~16,也就是 255*255,去掉0个255,我们有65534可以分配的ip
// docker0网络默认可以支持创建6万多个容器ip不重复
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
//自定义网卡
//1、删除原来的所有容器
"Containers": {
"a3a4a17a2b707766ad4f2bb967ce1d94f658cd4cccef3bb8707395cdc71fa1e7": {
"Name": "tomcat03",
"EndpointID":
"5fe62d0be3a1343aa74f6bb77885d3657b191210cafad200e5054e1bdfe56be9",
"MacAddress": "02:42:ac:12:00:04",
"IPv4Address": "172.18.0.4/16",
"IPv6Address": ""
},
"b80da266a3ad85fcc874c5f0d3c897246ebc40533cb745bb24180237cc3167b1": {
"Name": "tomcat02",
"EndpointID":
"6232cac0c4e7fed30c9fa5eebc9238f9fc44f548f257344b5440d6d486825256",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"f38239e2b405bccf8c93bd1052f336f661033b9b27ef9b3f99a018c108e06f87": {
"Name": "tomcat01",
"EndpointID":
"31dc174b8f3f15f217acdc3ac7e8a235a03d59438f863706c0143b4426772c5e",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
自定义网卡
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
default 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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state
UP group default qlen 1000
link/ether 00:16:3e:30:27:f4 brd ff:ff:ff:ff:ff:ff
inet 172.17.90.138/20 brd 172.17.95.255 scope global dynamic eth0
valid_lft 310951436sec preferred_lft 310951436sec
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state
DOWN group default
link/ether 02:42:bb:71:07:06 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
valid_lft forever preferred_lft forever
接下来我们来创建容器,但是我们知道默认创建的容器都是docker0网卡的
我们可以让容器创建的时候使用自定义网络
接下来我们来创建容器,但是我们知道默认创建的容器都是docker0网卡的
默认我们不配置网络,也就相当于默认值 --net bridge 使用的docker0
docker run -d -P --name tomcat01 --net bridge tomcat
docker0网络的特点
- 它是默认的
- 域名访问不通
- –link 域名通了,但是删了又不行
我们可以让容器创建的时候使用自定义网络
自定义创建的默认default “bridge” 自定义创建一个网络网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
docker network ls
NETWORK ID NAME DRIVER SCOPE
4eb2182ac4b2 bridge bridge local
ae2b6209c2ab host host local
09bd09d8d3a6 mynet bridge local
c037f7ec7e57 none null local
查看网络详细信息
docker network inspect mynet
[
{
"Name": "mynet",
"Id":
"09bd09d8d3a6b33e6d19f49643dab551e5a45818baf4d5328aa7320c6dcfc236",
"Created": "2020-05-13T13:29:33.568644836+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
# 我们来启动两个容器测试,使用自己的 mynet!
docker run -d -P --name tomcat-net-01 --net mynet tomcat
065f82e947c760c63539ab4c0de0d683787ec7ac6d0dcaa71f64e191319f9fe7
docker run -d -P --name tomcat-net-02 --net mynet tomcat
2e85d71afe87c87166786b0bbae2d90eefb969d716fcd78a21173add5956cb12
docker ps
CONTAINER ID IMAGE PORTS NAMES
2e85d71afe87 tomcat 0.0.0.0:32772->8080/tcp tomcat-net-02
065f82e947c7 tomcat 0.0.0.0:32771->8080/tcp tomcat-net-01
# 再来查看下
docker network inspect mynet
[
{
"Name": "mynet",
"Id":
"09bd09d8d3a6b33e6d19f49643dab551e5a45818baf4d5328aa7320c6dcfc236",
............
"Containers": {
"065f82e947c760c63539ab4c0de0d683787ec7ac6d0dcaa71f64e191319f9fe7": {
"Name": "tomcat-net-01",
"EndpointID":
"d61cef1bc294d7f10fb6d9b728735fc87bed79e4e02f5298374f0fab3e9b2da6",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"2e85d71afe87c87166786b0bbae2d90eefb969d716fcd78a21173add5956cb12": {
"Name": "tomcat-net-02",
"EndpointID":
"adbc37a20526c2985c3589382998a3d106ef722662c7b296a57d8a7c8f449f38",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
我们来测试ping容器名和ip试试,都可以ping通
docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.093 ms
docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64
time=0.063 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64
time=0.066 ms
发现,我们自定义的网络docker都已经帮我们维护好了对应的关系
所以我们平时都可以这样使用网络,不使用–link效果一样,所有东西实时维护好,直接域名 ping通。
聊了这么多,我们现在应该可以深刻理解docker的网络了!
网络连通
docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:
大家公司项目部署的业务都非常多,假设我们有一个商城,我们会有订单业务(操作不同数据),会有
订单业务购物车业务(操作不同缓存)。如果在一个网络下,有的程序猿的恶意代码就不能防止了,所
以我们就在部署的时候网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库,redis,mq,全
部业务 都在order-net网络下)其他业务在其他网络。
那关键的问题来了,如何让 tomcat-net-01 访问 tomcat1?
# 启动默认的容器,在docker0网络下
docker run -d -P --name tomcat01 tomcat
bcd122e0dcf6bf8c861eaa934911f98a5497a4954f3fde9575e496160bd23287
docker run -d -P --name tomcat02 tomcat
6183aaeca003a3e5a3549a37f9c1040551320ae358807b4aaad547a986afb887
# 查看当前的容器 docker ps
CONTAINER ID IMAGE PORTS NAMES
6183aaeca003 tomcat 0.0.0.0:32774->8080/tcp tomcat02
bcd122e0dcf6 tomcat 0.0.0.0:32773->8080/tcp tomcat01
2e85d71afe87 tomcat 0.0.0.0:32772->8080/tcp tomcat-
net-02
065f82e947c7 tomcat 0.0.0.0:32771->8080/tcp tomcat-
net-01
我们来查看下network帮助,发现一个命令 connect
docker network --help
Commands:
connect Connect a container to a network # 连接一个容器到一个网络
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
我们来测试一下!打通mynet-docker0
# docker network connect [OPTIONS] NETWORK CONTAINER
docker network connect mynet tomcat01
//docker network inspect mynet
[
{
......
"Containers": {
"065f82e947c760c63539ab4c0de0d683787ec7ac6d0dcaa71f64e191319f9fe7": {
"Name": "tomcat-net-01",
"EndpointID":
"d61cef1bc294d7f10fb6d9b728735fc87bed79e4e02f5298374f0fab3e9b2da6",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"2e85d71afe87c87166786b0bbae2d90eefb969d716fcd78a21173add5956cb12": {
"Name": "tomcat-net-02",
"EndpointID":
"adbc37a20526c2985c3589382998a3d106ef722662c7b296a57d8a7c8f449f38",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
},
// 发现我们的tomcat01就进来这里了,tomcat01拥有了双ip
"bcd122e0dcf6bf8c861eaa934911f98a5497a4954f3fde9575e496160bd23287": {
"Name": "tomcat01",
"EndpointID":
"b2bf2342948e17048d872a4d5603c77e90d0e032439d510e86c10a1acc3928d9",
"MacAddress": "02:42:c0:a8:00:04",
"IPv4Address": "192.168.0.4/16",
"IPv6Address": ""
}
},
......
}
]
tomcat01 可以ping通了
docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64
time=0.071 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64
time=0.067 ms
tomcat02 依旧ping不通,大家应该就理解了
docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORKCONTAINER 连接