Docker理解
问题:docker如何处理容器网络访问的?如容器与容器之间,宿主机与容器之间能否ping通
通过ip addr查看本地ip地址,我们发现除了本机回环地址和阿里云的内网地址外,还多了一个网卡:Docker0,这是Docker服务启动后自动生成的
测试如下:
// 启动tomcat容器并查看tomcat1中的ip
[root@us4ci6jaxom1jjz2 tomcat]# docker run -d -P --name tomcat01 tomcat:9
df6b5e81ac59dda7d9e9f68ea446c4cf8ed3df51844a149634cdf095cac10ba5
[root@us4ci6jaxom1jjz2 tomcat]# docker exec -it tomcat01 ip addr
tomcat1中的网络:158:enth0@if159
宿主机上查看,发现多了个网卡,159:enth0@if158
都是一对一的,这是Docker为其自动分配的
// 知道ip后测试主机和容器之间是否能ping通
[root@us4ci6jaxom1jjz2 tomcat]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.100 ms
...可以ping通容器内部
//测试tomcat01和tomcat02是否可以ping通
[root@us4ci6jaxom1jjz2 tomcat]#docker run -d -P --name tomcat02 tomcat
[root@us4ci6jaxom1jjz2 tomcat]# docker exec -it tomcat02 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.109 ms
...可以ping通容器内部
原理
1、linux可以ping通docker容器内部,因为docker0的ip地址为172.17.0.1,容器为172.17.0.2。
2、Docker使用的是Linux的桥接,我们每启动一个docker容器,docker就会给docker容器分配一个默认可用的ip,我们只要安装了docker,就会有一个网卡docker0桥接模式【桥接到真实物理网络上】,使用的技术是evth-pair技术!【evth-pair就是一对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连,充当一个桥梁】
正因为有这个特性,evth-pair充当一个桥梁,连接着各种虚拟网络设备的
OpenStack,Docker容器之间的连接,OVS的连接,都是使用的evth-pair技术
3、docker中的所有网络接口都是虚拟的 ,转发效率高。删除容器后,对应的网桥也随之删除。
4、Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥docker0,所有容器不指定网络的情况下,都是docker0转接的,docker会给我们的容器分配一个默认可用的ip
结论:tomcat01和tomcat02是共同用一个交换机,docker0
所有容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用ip
–link
场景思考:我们编写一个微服务其连接了数据库,如果数据库ip换掉了,我们希望不用换ip而是通过容器名进行访问容器从而正常运行项目,如何解决呢? 在容器启动命令中加入选项:–link,即可根据容器名访问容器。
docker run -d -P --link 容器名/id 镜像名/id
//通过容器名无法ping通
[root@us4ci6jaxom1jjz2 ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
[root@us4ci6jaxom1jjz2 ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
ca7a4887868f17f3c92de628612bed1e65a6e0ae7edf9e3a7be4edc95c6446e1
[root@us4ci6jaxom1jjz2 ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.100 ms
....ping成功
//--link的设置是单向的,tomcat3能ping通tomcat2,而tomcat2不能ping通3
[root@us4ci6jaxom1jjz2 ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
//查看tomcat03的网络情况,发现tomcat03的host文件中写了tomcat02的ip映射,所以可以ping通
[root@us4ci6jaxom1jjz2 ~]# 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.17.0.3 tomcat02 fa0e92f1732f //发现其包含了tomcat02名字与ip的映射
172.17.0.4 ca7a4887868f
[root@us4ci6jaxom1jjz2 ~]#
–link就是在hosts配置中将域名和ip地址直接绑定在了一起,而tomcat02的host文件中没有配置,所以tomcat02无法ping通tomcat03
这种绑定网络的方式太繁琐了,不推荐使用,一般是自定义网络
自定义网络
//查看docker的网络情况
##
网络模式
bridge:桥接docker(默认,自己创建也是用bridge模式)
none:不配自网络(特定场景使用,比如,高安全环境,随机生成字符串的功能,那么这个容器就可以用none)
host:和宿主机共享的网络
container:容器网络连通!(用的少,局限大)
##
[root@us4ci6jaxom1jjz2 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0516cf2f35f9 bridge bridge local //bridge就是docker0
c0106ffe0a08 host host local
b320f8de1c23 none null local
[root@us4ci6jaxom1jjz2 ~]# docker network inspect 0516cf2f35f9 //查看docker0中的网络情况
[
{
"Name": "bridge",
....
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1" #docker0
}
....
如下docker0网络中还有其配置的容器信息
docker run -d -P --name tomcat01 tomcat #该命令默认参数–net bridge
docker run -d -P --name tomcat01 --net bridge tomcat
docker run 命令默认带有一个参数–-net bridge,此处的bridge指的就是docker0。(docke0特点,默认,域名不能访问,–link可以打通连接或自定义网络)
可以使用docker network create 命令创建一个网络,然后将容器连接到网络中
测试
# 我们可以自定义一个网络
# --dirver bridge
# --subnet 192.168.0.0/16 子网
# -- geteway 192.168.0.1 #网关
[root@us4ci6jaxom1jjz2 ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
40b2744053d99b7d372cd42583ec6d4f455f05293939c445bbc2947d5953756b
///我们不仅在docker network ls命令下发现了这个新创建的网络newnet,还可以使用docker network inspect命令查看其详细信息,包括了我们创建时定义的子网ip和网关
[root@us4ci6jaxom1jjz2 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0516cf2f35f9 bridge bridge local
c0106ffe0a08 host host local
40b2744053d9 mynet bridge local
b320f8de1c23 none null local
//我们自己的网络就创建好了,以后可以自己将服务挂到上面
[root@us4ci6jaxom1jjz2 ~]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
775d1ec746a61787a85e8cd3739f2f96082af06d2453b7af517522230c87c90c
[root@us4ci6jaxom1jjz2 ~]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
b3797ebf069b7e1c920db35956d101f6a3e2f086a1c95a39d025b6ee465e4c50
[root@us4ci6jaxom1jjz2 ~]# docker network inspect mynet
可看到容器添加到了该网络下:
主要是让容器之间从默认走docker0的方式(无法直接通过容器名链接),改变到将两个容器都放在一个局域网内,使两个容器可通信
#再次测试,可以直接ping通
[root@us4ci6jaxom1jjz2 ~]# 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.089 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.070 ms
我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络!
好处:
redis 集群,mysql集群,不同的集群使用不同的网络,保证集群的安全和健康的
网络连通
如下,不同网段之间无法连通,如何让一个网段中的一个容器访问到另一个网段的容器?
Docker0和mynet两网卡之间不能打通,而是将一个容器连到目的网络上
查看帮助信息可看到docker network connect可将容器连接到一个网络上
#测试打通 tomcat01 - mynet
//由于tomcat01和mynet两个网段不同,不能彼此ping通,此时可通过docker network connect命令打通容器与网络之间的连接
[root@us4ci6jaxom1jjz2 ~]# docker network connect mynet tomcat01
[root@us4ci6jaxom1jjz2 ~]# docker network inspect mynet
容器连到自定义网络后,发现实际是将tomcat01的配置到了mynet中
一个容器两个ip!,阿里云服务器公网ip,私网络ip
//01连通成功
[root@us4ci6jaxom1jjz2 ~]# 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.082 ms
...
[root@us4ci6jaxom1jjz2 ~]# docker start tomcat02
tomcat02
//02由于没有加入mynet中,依旧打不通
[root@us4ci6jaxom1jjz2 ~]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
[root@us4ci6jaxom1jjz2 ~]#
连接之后,指定的容器与指定的网络下的所有容器都是互联的
相当于把当前容器加到某个已经设置好的局域网中