一、容器的网络基础
docker守护进程就是通过docker0为docker容器提供网络连接的各种服务。docker0实质事Linux的虚拟网桥。
在linux系统中,可以使用ifconfig命令查看docker0网桥信息:
网桥是在OSI七层模型的数据链路层的网络设备,通过mac地址对网络进行划分,并且在不同网络直接传递数据,对于Linux的虚拟网桥:
(1)可以设置IP地址;
(2)相当于拥有一个隐藏的虚拟网卡。
docker守护进程在一个容器启动时,实际上要创建网络连接的两端;一端是在容器中的网络设备,另一端在运行docker容器的宿主机上,打开一个veth*的一个接口,用来实现docker0网桥与容器的网络通信。
例:我们启动一个nginx容器,查看是否产生新的网桥接口:
[docker@docker ~]$ docker run --name nginx -P docker.io/nginx
使用ifconfig命令查看是否产生新的网桥接口:
上图最后红色的圈起来的信息就是我们启动容器产生的网络接口。
我们可以对docker0网桥IP、子网掩码等进行修改,命令格式为:
ifconfig docker0 IP netmask NETMASK
我们当前的docker0IP为172.17.0.1,netmask为255.255.0.0,我们将其修改为IP为172.1.1.1,netmask为255.255.255.0:
ifconfig docker0 172.1.1.1 netmask 255.255.255.0
使用ifconfig命令可以看到docker0网桥信息已经按照我们的命令修改了。
但是这样使用命令修改网桥IP的话,只要一重启docker服务,网桥的IP又变回默认的172.17.0.1了,所以更彻底地修改网桥IP的方式为修改daemon.json配置文件:
[root@docker ~]# vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://z11csm7d.mirror.aliyuncs.com"],
"bip":"192.168.55.1/24"
}
在该文件中加上标黄的"bip":“192.168.55.1/24”,保存修改,然后重启docker服务,再次查看docker0的IP:
[root@docker ~]# systemctl restart docker
[root@docker ~]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.55.1 netmask 255.255.255.0 broadcast 0.0.0.0
ether 02:42:84:02:95:bb txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
二、创建自定义网络
docker提供三种自定义网络驱动:bridge,overlay,macvlan,其中overlay和macvlan用于创建跨主机的网络,所以本次主要学习bridge。
创建bridge网络命令格式为:
docker network create --driver bridge name
其中name是自己定义的网络名称,例如,新建一个名称为mynet的bridge网络:
[root@docker ~]# docker network create --driver bridge mynet
c1889b381f4852989db8e95b1349ee63b15a106adacf7a064b723e26ce386f2e
[root@docker ~]#
以上,mynet网络就创建完成,使用brctl show 命令查看网桥信息,出现了br-c1889b381f48这个网桥,interfaces对应的值为空的,说明还没有容器使用此网桥。
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-c1889b381f48 8000.02421b372633 no
docker0 8000.0242579d6bb5 no vethff4147d
使用 docker network inspect mynet 查看mynet网络自动获取的IP段:
[root@docker ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "c1889b381f4852989db8e95b1349ee63b15a106adacf7a064b723e26ce386f2e",
"Created": "2019-08-08T19:20:36.176677209+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
}
]
以上可以看出,自动获取的IP段为172.18.0.0/16。
除了自动获取,我们也可以在创建网络时手动指定该网桥的IP网段,命令格式为:
[root@docker ~]# docker network create --driver bridge --subnet 172.19.0.0/16 --gateway 172.19.0.1 name
aeb83677bb933ce8c73d64167be595d683258e08f9c34b4dd09c4a8c2312843e
例如,创建一个mynet2网络:
[root@docker ~]# docker network create --driver bridge --subnet 172.19.0.0/16 --gateway 172.19.0.1 mynet2
aeb83677bb933ce8c73d64167be595d683258e08f9c34b4dd09c4a8c2312843e
[root@docker ~]#
同样使用brctl show查看网桥信息,新出现了br-aeb83677bb93,interfaces同样显示无容器使用该网络:
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-aeb83677bb93 8000.024260522e23 no
br-c1889b381f48 8000.02421b372633 no
docker0 8000.0242579d6bb5 no vethff4147d
三、自定义容器网络
我们创建了mynet和mynet2两个网络,现在我们使用–network=name指定nginx的容器分别使用两个网络:
[root@docker ~]# docker run --name nginx --network=mynet -P -d docker.io/nginx
37773b729b9b204102c07a4d78906e7575bd2f801a022c712da37f4329b74266
[root@docker ~]# docker run --name nginx2 --network=mynet2 -P -d docker.io/nginx
ad356866b0c59562b3d7f19162b4b750366c82eb72de854c978e1a229babdb2e
两个容器启动后,可以使用docker inspect nginx和docker inspect nginx2查看各自的IP:
[root@docker ~]# docker inspect nginx2
"NetworkID": "aeb83677bb933ce8c73d64167be595d683258e08f9c34b4dd09c4a8c2312843e",
"EndpointID": "cfa132b41284859a714ccd154291fbde5bc669dbff5066c922a2141adacbe38e",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:13:00:02"
[root@docker ~]# docker inspect nginx2
"NetworkID": "c1889b381f4852989db8e95b1349ee63b15a106adacf7a064b723e26ce386f2e",
"EndpointID": "f010563c45c047147d9d67ee0f66e020d72e44ca7d2f571e66018ed1214ae8d7",
"Gateway": "172.19.0.1",
"IPAddress": "172.19.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:12:00:02"
我们再启动一个nginx3容器,使其和nginx2使用同一个网络:
[root@docker ~]# docker run --name nginx3 --network=mynet2 -P -d docker.io/nginx
[root@docker ~]# docker inspect nginx3
"NetworkID": "aeb83677bb933ce8c73d64167be595d683258e08f9c34b4dd09c4a8c2312843e",
"EndpointID": "d47e39352b22385db5b2e29776a1170a077bef68dfed02e835fc723cdd4ef5e0",
"Gateway": "172.19.0.1",
"IPAddress": "172.19.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:13:00:03"
这样我们的nginx2和nginx3处于同一网段,是可以互通的:
root@ad356866b0c5:/# curl 172.19.0.3
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
</body>
</html>
但是nginx容器与nginx2和nginx3不处于同一网段,该怎么通信呢?
四、容器的互通
首先查看操作系统的路由表:
[root@docker ~]# ip r
default via 192.168.0.1 dev eth0 proto dhcp metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.18.0.0/16 dev br-c1889b381f48 proto kernel scope link src 172.18.0.1
172.19.0.0/16 dev br-aeb83677bb93 proto kernel scope link src 172.19.0.1
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.187 metric 100
172.18.0.0和172.19.0.0两个网络都定义好了。
再查看操作系统是否打开了ip forwarding:
[root@docker ~]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
ip_forward已经是打开的,再查看iptables防火墙规则:
[root@docker ~]# iptables-save
-A DOCKER-ISOLATION -i br-c1889b381f48 -o br-aeb83677bb93 -j DROP
-A DOCKER-ISOLATION -i br-aeb83677bb93 -o br-c1889b381f48 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-aeb83677bb93 -j DROP
-A DOCKER-ISOLATION -i br-aeb83677bb93 -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-c1889b381f48 -j DROP
-A DOCKER-ISOLATION -i br-c1889b381f48 -o docker0 -j DROP
以上内容可以看出iptables DROP掉了网桥docker0和其他网桥之间的流量,而且从DOCKER-ISOLATION规则的命名上就可以看出,docker在设计上就是为了隔离不同network上的容器,那么接下来:如何才能让nginx与nginx2和3之间通信呢?
答案是:为nginx增加一块mynet2的网卡,或者为nginx2和3增加一块mynet的网卡,具体操作如下:
先查看nginx容器的ID
[root@docker ~]# docker ps
CONTAINER ID NAMES
5aa9f8bcb07f nginx3
ad356866b0c5 nginx2
37773b729b9b nginx
为该容器添加网卡:
[root@docker ~]# docker network connect mynet2 37773b729b9b
查看容器是否获取到新的IP
[root@docker ~]# docker inspect nginx
"NetworkID": "c1889b381f4852989db8e95b1349ee63b15a106adacf7a064b723e26ce386f2e",
"EndpointID": "ec53251b60176b207cfc578c8759f4d708b0114724fc220d4ae015897327bd56",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.2",
……
"Gateway": "172.19.0.1",
"IPAddress": "172.19.0.4",
上,我们的nginx容器当前有两个网卡,所以有两个IP,现在应该能互通了:
root@37773b729b9b:/# curl 172.19.0.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
</body>
</html>