Docker网络

Docker0 Docker 容器间互通

Docker使用Linux桥接(参考《Linux虚拟网络技术》),在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。

我们在容器内部创建的服务,网络可以互相访问,类似于局域网;

测试:

使用tomcat01—->ping tomcat02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@iZwz94khotag1q066igytrZ /]# docker exec tomcat01 ping tomcat02
PING tomcat02 (172.17.0.2) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.2): icmp_seq=1 ttl=64 time=0.107 ms
64 bytes from tomcat02 (172.17.0.2): icmp_seq=2 ttl=64 time=0.096 ms
64 bytes from tomcat02 (172.17.0.2): icmp_seq=3 ttl=64 time=0.094 ms
^C
[root@iZwz94khotag1q066igytrZ /]# docker exec tomcat01 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
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.108 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.099 ms
^C
[root@iZwz94khotag1q066igytrZ /]# docker exec tomcat01 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.027 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.039 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.038 ms
^C

使用tomcat2—->ping tomcat1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@iZwz94khotag1q066igytrZ /]# docker exec 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.028 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.041 ms
^C
[root@iZwz94khotag1q066igytrZ /]# docker exec tomcat02 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.122 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.114 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.068 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.065 ms
^C
[root@iZwz94khotag1q066igytrZ /]#

我们可以知道,这两个是通的;但是我们不可以使用容器名ping,所以我们需要使用 –link来实现我们的使用容器名字来ping

1
docker run -d -it --name tomcat01 --link tomcat02 tomcat

在启动的时候,我们就指定我们要链接的模式,实现二者的互通;

原理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@iZwz94khotag1q066igytrZ /]# docker exec -it  tomcat01 /bin/bash
root@1754afecd1bc:/usr/local/tomcat# lll
bash: lll: command not found
root@1754afecd1bc:/usr/local/tomcat# ls
BUILDING.txt LICENSE README.md RUNNING.txt conf logs temp webapps.dist
CONTRIBUTING.md NOTICE RELEASE-NOTES bin lib native-jni-lib webapps work
root@1754afecd1bc:/usr/local/tomcat# cd
root@1754afecd1bc:~# cd ..
root@1754afecd1bc:/# cd etc
root@1754afecd1bc:/etc# cat 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 tomcat02 7c064e4efced
172.17.0.3 1754afecd1bc
root@1754afecd1bc:/etc#

就是类似于我们修改windows下面的etc/host一样,当我们使用名字ping的时候,他会自动转到我们的ip地址;

–link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式

自定义网络

我们先查看我们刚刚部署的网络:

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
[root@iZwz94khotag1q066igytrZ /]# docker network ls
NETWORK ID NAME DRIVER SCOPE
792301ca29a4 bridge bridge local
ab45058093b3 host host local
30427e45134c none null local
[root@iZwz94khotag1q066igytrZ /]# docker network inspect 792301ca29a4
[
{
"Name": "bridge",
"Id": "792301ca29a4b692a35d56dd094e39641569fd9eb45272e8dc1e9d0ea387617d",
"Created": "2020-11-30T21:53:10.295778567+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": {
"1754afecd1bc8ca03257a622dc25bdb8cb52de8b10fc4f1aa39206ff809d97f4": {
"Name": "tomcat01",
"EndpointID": "a7738d2aee7d6c32be2959621bbb773d8b06356acdd2030ded082e5c3a8a4b1b",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"7c064e4efced691f955fa9c4a2bfbd24bdc69212e572b5f228020f565ada7948": {
"Name": "tomcat02",
"EndpointID": "601b92a9d09b78e65eb1551bd3d3b7ff8d0689c81e16dc0cdd1eb35bda0bb6a0",
"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": {}
}
]

网络配置:

1
2
3
4
5
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}

容器的网络连接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"Containers": {
"1754afecd1bc8ca03257a622dc25bdb8cb52de8b10fc4f1aa39206ff809d97f4": {
"Name": "tomcat01",
"EndpointID": "a7738d2aee7d6c32be2959621bbb773d8b06356acdd2030ded082e5c3a8a4b1b",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"7c064e4efced691f955fa9c4a2bfbd24bdc69212e572b5f228020f565ada7948": {
"Name": "tomcat02",
"EndpointID": "601b92a9d09b78e65eb1551bd3d3b7ff8d0689c81e16dc0cdd1eb35bda0bb6a0",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}

发现在这个网络下面有一个名为tomcat01和tomcat02的容器的网络的IP地址;所以,我们要自己创建一个网络的话,如果在后面的container里面显示了我们的网络,子网,我们就部署成功;

第一步,先创建一个属于自己的网络

1
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

第二步、启动容器服务时使用 –net +网络名绑定网络

1
2
docker run -d -it --net saxon --name tomcat01 tomcat
docker run -d -it --net saxon --name tomcat02 tomcat

第三步查看网络状态:

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
[root@iZwz94khotag1q066igytrZ docker]# docker network inspect saxon
[
{
"Name": "saxon",
"Id": "ae4d1b67843db37b2b257228148ae45badf5874c72ed677673eac90b3ab7200b",
"Created": "2020-12-01T13:41:52.55206052+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": {
"5e5d7b74d8bd426e151f6af2fb6aca8330077894be5385faa118b7a9c34f278b": {
"Name": "tomcat01",
"EndpointID": "e96e3d6a90310960972d569613d19ab97422e13fd55ac5c8847780538df40f49",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
},
"c438c62aa2dafa22619f712d69c95a09c95dd3c93fac74b7348897c794620f04": {
"Name": "tomcat02",
"EndpointID": "2780e88e6ff8244c72747294326004d5688049d9be28163d75872e4eb21916d0",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]

发现和我们的Docker0属性一样,我们再在容器内部ping一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#Tomcat1 ping tomcat2 测试通过
[root@iZwz94khotag1q066igytrZ docker]# docker exec -it tomcat01 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=0.157 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.108 ms
64 bytes from 192.168.0.2: icmp_seq=3 ttl=64 time=0.106 ms
^C
--- 192.168.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 35ms
rtt min/avg/max/mdev = 0.106/0.123/0.157/0.026 ms

#tomcat2 ping tomcat1 测试通过
[root@iZwz94khotag1q066igytrZ docker]# docker exec -it tomcat02 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.115 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.111 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.113 ms
^C
--- 192.168.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 50ms
rtt min/avg/max/mdev = 0.111/0.113/0.115/0.001 ms

到此,我们自己新建的网络成功使用;

实战:搭建redis集群

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
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done


#逐一启动镜像
[root@iZwz94khotag1q066igytrZ redis]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
01994e162878 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 8 seconds ago Up 7 seconds 0.0.0.0:6371->6379/tcp, 0.0.0.0:16371->16379/tcp redis-1
[root@iZwz94khotag1q066igytrZ redis]# docker run -p 6371:6379 -p 16371:16379 --name redis-1 -v /mydata/redis/node-1/data:/data -v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
e8f73a2f5b6955842c2c293d06c38da046049fb736d1a39ab3d440cd0739700d
docker: Error response from daemon: Address already in use.
[root@iZwz94khotag1q066igytrZ redis]# docker run -p 6372:6379 -p 16372:16379 --name redis-2 -v /mydata/redis/node-2/data:/data -v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker: Error response from daemon: Conflict. The container name "/redis-2" is already in use by container "e8f73a2f5b6955842c2c293d06c38da046049fb736d1a39ab3d440cd0739700d". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.
[root@iZwz94khotag1q066igytrZ redis]# docker rm -f redis-2
redis-2
[root@iZwz94khotag1q066igytrZ redis]# docker run -p 6372:6379 -p 16372:16379 --name redis-2 -v /mydata/redis/node-2/data:/data -v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
efab199dc4d9abfdc0ba37e100894c50cdd4ec470b5a3b61b7184070ccb1036d
[root@iZwz94khotag1q066igytrZ redis]# docker run -p 6373:6379 -p 16373:16379 --name redis-3 -v /mydata/redis/node-3/data:/data -v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
c579a0b63d04a874758a7309c8187c248b3a6383d2a76b90d2f2acbe2fc3fdfd
[root@iZwz94khotag1q066igytrZ redis]# docker run -p 6374:6379 -p 16374:16379 --name redis-4 -v /mydata/redis/node-4/data:/data -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
3e33d8a8b1eb767f1eb0a8bc2b9ca4c6c4f7e65303f7ba18c3baf769b3185b10
[root@iZwz94khotag1q066igytrZ redis]# docker run -p 6375:6379 -p 16375:16379 --name redis-5 -v /mydata/redis/node-5/data:/data -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
1e2080f42235f1b134714f82f7b5555336cb4e87777781bba02e653282018bb3
[root@iZwz94khotag1q066igytrZ redis]# docker run -p 6376:6379 -p 16376:16379 --name redis-6 -v /mydata/redis/node-6/data:/data -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
35c59360d6fde0b51b0a72d8a4eae5660df75739b43356423b842454455a3288
[root@iZwz94khotag1q066igytrZ redis]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
35c59360d6fd redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:6376->6379/tcp, 0.0.0.0:16376->16379/tcp redis-6
1e2080f42235 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 32 seconds ago Up 31 seconds 0.0.0.0:6375->6379/tcp, 0.0.0.0:16375->16379/tcp redis-5
3e33d8a8b1eb redis:5.0.9-alpine3.11 "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:6374->6379/tcp, 0.0.0.0:16374->16379/tcp redis-4
c579a0b63d04 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:6373->6379/tcp, 0.0.0.0:16373->16379/tcp redis-3
efab199dc4d9 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 0.0.0.0:6372->6379/tcp, 0.0.0.0:16372->16379/tcp redis-2
01994e162878 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 5 minutes ago Up 5 minutes 0.0.0.0:6371->6379/tcp, 0.0.0.0:16371->16379/tcp redis-1

搭建集群:

1
2
3
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379
172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --
cluster-replicas 1

结果:

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
[root@iZwz94khotag1q066igytrZ redis-6.0.9]# redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 98d2901b86c5d11dddcd0134a9932b34f0c73f71 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: ae4526fbe1ead0860de11af4ceb505090545c7df 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: c013d07adf4956f0d97a88933ea81daa92ce27c2 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 112777ebdd54a7899c5316f0e037378b827dbee7 172.38.0.14:6379
replicates c013d07adf4956f0d97a88933ea81daa92ce27c2
S: 8ca411149d57455bee0d1f2480195b96e75e9dab 172.38.0.15:6379
replicates 98d2901b86c5d11dddcd0134a9932b34f0c73f71
S: 92d1fb43542e1f7d0a869a57da757d5aaf051079 172.38.0.16:6379
replicates ae4526fbe1ead0860de11af4ceb505090545c7df
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
....
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 98d2901b86c5d11dddcd0134a9932b34f0c73f71 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: ae4526fbe1ead0860de11af4ceb505090545c7df 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
M: c013d07adf4956f0d97a88933ea81daa92ce27c2 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 112777ebdd54a7899c5316f0e037378b827dbee7 172.38.0.14:6379
slots: (0 slots) slave
replicates c013d07adf4956f0d97a88933ea81daa92ce27c2
S: 92d1fb43542e1f7d0a869a57da757d5aaf051079 172.38.0.16:6379
slots: (0 slots) slave
replicates ae4526fbe1ead0860de11af4ceb505090545c7df
S: 8ca411149d57455bee0d1f2480195b96e75e9dab 172.38.0.15:6379
slots: (0 slots) slave
replicates 98d2901b86c5d11dddcd0134a9932b34f0c73f71
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

查看一个客户端里面的集群信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=172.38.0.1,port=6379,state=online,offset=140,lag=1
master_replid:975f974a938905b155fa316b0d0f57e795e57cca
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:140
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:140

发现创建集群成功;

这个集群于哨兵模式不一样的是,一个主机对应一个从机,但是我们的从机也具有写的权限;

我们在设置值的时候:

1
2
3
127.0.0.1:6379> set k1 v1
-> Redirected to slot [12706] located at 172.38.0.13:6379
OK

同样的,当主机挂掉以后,我们的从机会变成主机,主机也会变成从机;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@iZwz94khotag1q066igytrZ redis-6.0.9]# docker exec -it redis-3 /bin/sh
/data # redis-cli
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:172.38.0.14
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:1173
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:b5c59e51eb3cd20d10b4eddc83dd3fb444501479
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1173
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1104
repl_backlog_histlen:70
127.0.0.1:6379>

我们把原来的主机挂掉,然后在创建一个容器,再用同样的办法创建一个主机,发现主机变成从机;