记录生活中的点点滴滴

0%

Docker学习6:Docker网络

接下来是Docker的网络部分,主要写的是怎样做到将多个容器之间能够互相连通!

理解Docker0

我们接下来启动一个tomcat镜像,然后看看 ip addr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 启动一个tomcat
[root@localhost mycentos]# docker run -d tomcat:9.0
b7e1e9081c736d6713507f59880d9219ca70164c6bf72b30542d5c91359a2908

[root@localhost mycentos]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b7e1e9081c73 tomcat:9.0 "catalina.sh run" 7 seconds ago Up 6 seconds 8080/tcp hardcore_lamport

# 执行容器内的 ip addr 命令
[root@localhost mycentos]# docker exec -it b7e1e9081c73 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
100: eth0@if101: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever

# 用本机去ping一下容器内的ip,可以ping通
[root@localhost mycentos]# 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.111 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.037 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.037 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.036 ms
^C
--- 172.17.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 0.036/0.055/0.111/0.032 ms
[root@localhost mycentos]#

原理

1、我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡 docker 0 桥接模式,使用的技术是 evth-pair 技术!

会发现在原来的网卡上又新添加了一个网卡,它与tomcat容器内的网卡,一个100,一个101,是一对!

2、再启动一个tomcat,发现又多了一对网卡!

1
2
3
4
# 我们发现这个容器带来的网卡,都是一对一对的!
# evth-pair 就是一对虚拟的设备接口,它们都是成对出现的,一段连着协议,一段彼此相连
# 正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备
# Docker容器之间的连接,都是使用 evth-pair 技术!

3、我们测试下 这两个 tomat 之间能不能 ping 通:

1
2
3
4
5
[root@localhost mycentos]# docker exec -it b7e1e9081c73 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.214 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.038 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.042 ms

发现可以 ping 通!

画一个网络拓扑图就明白了,它们是通过 docker0 (相当于路由器),互相 ping 通的!

结论:所有的容器不指定网络的情况下,都是 docker 0路由,docker会给我们的容器分配一个可用的IP!

总结

Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥 docker 0!

Docker中的所有的网络接口都是虚拟的,虚拟的转发效率高!

只要容器删除,对应的一对网桥就没有了!

思考这样一个场景:我们编写了一个微服务,用ip互相访问,但是如果ip换掉了,我们希望处理这个问题,可以用名字来访问容器吗?

下面我们还是创建两个tomcat容器,tomcat01和tomcat02,让它们ping:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 创建两个tomcat容器
[root@localhost mycentos]# docker run -d --name=tomcat01 tomcat:9.0
e24c0808d48946298fef99299564a5f5c5b88130589ecf5263efe89fa62bbff1
[root@localhost mycentos]# docker run -d --name=tomcat02 tomcat:9.0
bd75262253da1d60d4bbc8e59bb085619ab43360d98f9ce4589cb218d3cb0a33

# 查看这两个容器
[root@localhost mycentos]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bd75262253da tomcat:9.0 "catalina.sh run" 4 seconds ago Up 4 seconds 8080/tcp tomcat02
e24c0808d489 tomcat:9.0 "catalina.sh run" 8 seconds ago Up 7 seconds 8080/tcp tomcat01

# 查看 tomcat01 的ip
[root@localhost mycentos]# 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
104: eth0@if105: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever

# tomcat02 通过 ip 去 ping tomcat01,能 ping 通!
[root@localhost mycentos]# 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.142 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.061 ms
^C
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.061/0.101/0.142/0.041 ms

# tomcat02 通过 容器名 去 ping tomcat01,不能 ping 通!
[root@localhost mycentos]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known

如何解决呢?可以通过 –link 来解决

1
2
3
4
5
6
7
8
9
10
# 再创建一个tomcat03,--link连接到tomcat01
[root@localhost mycentos]# docker run -d --name=tomcat03 --link tomcat01 tomcat:9.0
818c69db0f76f4212e8a2a41bc6f4b2e4d6285e0956b3bd8a3ec4b569bde8e13

# 发现通过名字去ping,可以ping通!
[root@localhost mycentos]# docker exec -it tomcat03 ping tomcat01
PING tomcat01 (172.17.0.2) 56(84) bytes of data.
64 bytes from tomcat01 (172.17.0.2): icmp_seq=1 ttl=64 time=0.101 ms
64 bytes from tomcat01 (172.17.0.2): icmp_seq=2 ttl=64 time=0.044 ms
64 bytes from tomcat01 (172.17.0.2): icmp_seq=3 ttl=64 time=0.044 ms

这样可以解决,但是其实有很多坑!

反向可以 ping 通吗?

1
2
3
# 反向ping,发现ping不通!
[root@localhost mycentos]# docker exec -it tomcat01 ping tomcat03
ping: tomcat03: Name or service not known

原理探究

我们通过查看 tomcat03 的 hosts 文件就能看出其中的猫腻:

1
2
3
4
5
6
7
8
9
[root@localhost mycentos]# 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.2 tomcat01 e24c0808d489
172.17.0.4 818c69db0f76

发现其实这里面把我们去 ping tomcat01 写死了,把 ip 写死了,ping tomcat01 其实就是 ping 172.17.0.2

这其实就是挂羊头卖狗肉!

再学习一下docker网络的命令

docker网络也是有对应的命令的,我们可以通过这些命令去查看网络的一些信息,很方便!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost mycentos]# docker network --help

Usage: docker network COMMAND

Manage networks

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

Run 'docker network COMMAND --help' for more information on a command.

OK,先看看 ls 命令:

1
2
3
4
5
[root@localhost mycentos]# docker network ls
NETWORK ID NAME DRIVER SCOPE
44697ad6f30f bridge bridge local
0c97d436b293 host host local
91f13ca9e915 none null local

再通过 inspect 具体查看某一网络:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
[root@localhost mycentos]# docker network inspect 44697ad6f30f
[
{
"Name": "bridge",
"Id": "44697ad6f30fda6da2f63b8776a92a99df538c2a30b8fe6b972eb1aa1ef0e835",
"Created": "2021-01-15T18:50:18.671863706+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"818c69db0f76f4212e8a2a41bc6f4b2e4d6285e0956b3bd8a3ec4b569bde8e13": {
"Name": "tomcat03",
"EndpointID": "0477b31e5071462199cb23cfc78c9e360d0227d2aba91caa8d68660c9ed44d3e",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
},
"bd75262253da1d60d4bbc8e59bb085619ab43360d98f9ce4589cb218d3cb0a33": {
"Name": "tomcat02",
"EndpointID": "1995cf28c0c782f5b529edea98e84221a72705e89c416fbe4965875a8facb486",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"e24c0808d48946298fef99299564a5f5c5b88130589ecf5263efe89fa62bbff1": {
"Name": "tomcat01",
"EndpointID": "e6c8264685f133173725e97c3ba325af3f6baa98f057af4dd3727a60e5736df1",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.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": {}
}
]

这就是我们的 docker 0,上面网络相关的情况写的清清楚楚!

当然之前我们的 docker inspect 其实也有我们对应容器的网络信息,例如我们查看一下tomcat03容器的信息:

1
[root@localhost mycentos]# docker inspect tomcat03

网络的网关、ip什么的,都是很详细的!

总结

现在docker已经不建议使用 --link 了!

那么怎样解决容器之间的网络访问呢?通过自定义网络解决!

自定义网络

查看所有的docker网络

1
2
3
4
5
[root@localhost mycentos]# docker network ls
NETWORK ID NAME DRIVER SCOPE
44697ad6f30f bridge bridge local
0c97d436b293 host host local
91f13ca9e915 none null local

网络模式

bridge:桥接docker(默认,自己创建也使用bridge模式)

none:不配置网络

host:和宿主机共享网络

container:容器网络连通!(用的少!局限大!)

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 我们直接启动的命令, --net bridge,而这个是我们的docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat02 --net bridge tomcat

# docker 0特点: 默认!域名不能访问!--link可以打通连接

# 我们可以自定义网络 mynet
# --driver bridge
# --subnet 192.168.0.0/16 子网掩码
# --gateway 192.168.0.1 网关
[root@localhost mycentos]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
e184ccd5c94c68458cf8614d712232d1cecbbab8f13d81548a8a244804e8d5d1

[root@localhost mycentos]# docker network ls
NETWORK ID NAME DRIVER SCOPE
44697ad6f30f bridge bridge local
0c97d436b293 host host local
e184ccd5c94c mynet bridge local
91f13ca9e915 none null local
[root@localhost mycentos]#

这样我们就创建好了我们自定义的网络,下面我们就使用这个网络创建容器:

1
2
3
4
5
6
7
8
9
10
11
# 创建tomcat
[root@localhost ~]# docker run -d --net mynet --name tomcat01 tomcat:9.0
243988e4d5274e4cd726bdd0b9d2d441ffcec1a8d7fa0b4ae04f8b72e828898a

[root@localhost ~]# docker run -d --net mynet --name tomcat02 tomcat:9.0
6d5096952295d6629b4732209920f522a2d5c5ae6e36655de30cc35b3f408b97

[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6d5096952295 tomcat:9.0 "catalina.sh run" 8 seconds ago Up 5 seconds 8080/tcp tomcat02
243988e4d527 tomcat:9.0 "catalina.sh run" 15 seconds ago Up 13 seconds 8080/tcp tomcat01

接着用 docker network inspect mynet 查看一下自定义网络的信息:

接下来我们测试看能不能ping通:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost ~]# docker exec -it tomcat02 ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=12.1 ms
^C
--- 192.168.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 12.124/12.124/12.124/0.000 ms
[root@localhost ~]# docker exec -it tomcat02 ping tomcat01
PING tomcat01 (192.168.0.2) 56(84) bytes of data.
64 bytes from 243988e4d527 (192.168.0.2): icmp_seq=1 ttl=64 time=0.017 ms
64 bytes from 243988e4d527 (192.168.0.2): icmp_seq=2 ttl=64 time=0.029 ms
^C
--- tomcat01 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.017/0.023/0.029/0.006 ms

发现都能ping通!

我们自定义网路docker都已经帮助我们维护好了对应的关系,推荐我们平时使用自定义网络!

后续我们可以设置针对不同的应用,比如mysql、redis等设置不同的子网,保证集群都是高效健康运行!(联想到了这学期学习的计算机网络实验,设置网关掩码等,公司的网络设置,不同部分之间的设置等等)

网络连通

看下面的情况:

docker0 下面的 tomcat01 如果想要访问 tomcat-net-01,就要求我们将 tomcat01 容器和 mynet 进行打通。

先看看帮助信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# docker network connect --help

Usage: docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container

为了验证上面的情况,我们再创建一个 tomcat03,让它默认在 docker0 下面:

1
2
[root@localhost ~]# docker run -d --name tomcat03 tomcat:9.0
e88c3dcc0f7226faa10a894abf532df40443b26a9ad1939a17563a46ddff879f

然后用connect连接:

1
2
3
4
5
[root@localhost ~]# docker network connect mynet tomcat03

# 连通之后就是将 tomcat03 放到了 mynet 网络下

# 一个容器两个ip,类似于阿里云服务器,两个ip:公网ip和私网ip

通过 docker network inspect mynet 查看 mynet 的信息:

查看 tomcat03的 ip addr 就能发现它除了本机环回,还有两个网卡,其实就分别是docker0和mynet。

下面测试看 tomcat03 能不能ping通 tomcat01:

1
2
3
4
[root@localhost ~]# docker exec -it tomcat03 ping tomcat01
PING tomcat01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.068 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.045 ms

OK,是可以的!

结论:假设需要跨网络操作别人,就需要使用 docker network connect 连通!