基于 Docker18.09.0
本文将和大家分享关于 Docker 用户自定义网络的基本命令的使用,有如下命令:
- docker network create
- docker network ls
- docker network inspect
- docker network connect
- docker network disconnect
- docker network rm
1. 创建网络
除了默认的名为 docker0
的 bridge
网络 , 还可以创建自己的 bridge
网络或 overlay
网络。
bridge
网络用于在本机内容器之间的互通overlay
网络用于在不同主机内的容器之间的互通
本文主要针对 bridge
网络进行演示说明, overlay
网络会在以后单独进行讨论。
1.1 创建一个 bridge
网络
运行命令
docker network -d
指定要创建什么类型的网络。
假如不使用-d
参数,会创建bridge
网络
$ docker network create -d bridge my-net
# 或者
$ docker network create my-net
查看网络源数据
$ docker network inspect my-net
[
{
"Name": "my-net",
"Id": "67b19436a9e361c8b9da4034c5903c4903444cecd3ecdbde62bbaf70828d49d9",
"Created": "2018-12-10T07:22:53.2694852Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
Doker 会为自定义的网络自动分配一个子网(
"Subnet": "172.18.0.0/16"
)。
1.2 创建一个 bridge
网络并指定子网
创建一个网络并指定子网为 172.20.0.0/16
$ docker network create --subnet=172.20.0.0/16 my-net_172_20
$ docker network inspect my-net_172_20
[
{
"Name": "my-net_172_20",
"Scope": "local",
...略...
"Config": [
{
"Subnet": "172.20.0.0/16"
}
]
},
...略...
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
1.3 创建一个网络使用 --label
添加元数据
在创建一个网络的时候使用 --label
为此网络指定一些元数据信息。
比如下面示例是创建 my-net_label
,并指定网络名称为 my-net_label
,项目名为 LB_nginx
。
$ docker network create \
> --label network_name=my-net_label \
> --label project=LB_nginx \
> my-net_label
83744cec9eef04ae0ba59709041194f4ec7e10714a212086d11df6518295273c
查看元数据,部分数据已截断
$ docker network inspect --format='' my-net_label
"Labels": {
"network_name": "my-net_label",
"project": "LB_nginx"
}
更多的选项和参数请执行命令
docker network create --help
2. 把容器连接到网络
您可以将现有容器连接到一个或多个网络。
容器可以连接到使用不同网络驱动程序的网络,比如连接到 bridge
网络或者 overlay
网络。
连接后,容器可以使用其他容器的IP地址或名称进行通信。
2.1 简单容器网络的连接示例
说明:
- 上图中表明的意思是,在一台 Docker 主机
Dokcer Host
上有三个容器 。- 三个容器分别连接到两个不同的网络中。
- 容器
container1
连接到默认的桥接网络bridge
- 容器
container2
连接到默认的网络的bridge
,同时它还连接到自定义的桥接网络my-net
中。- 容器
container3
也连接到自定义的桥接网络my-net
接下来我们就来实际操作一下,并观察各个容器网络的配置情况以及两个网桥的情况。
1.首先,创建并运行两个容器,container1
和 container2
:
$ docker run -itd --rm --name=container1 busybox
368a503800d4007627d0b63946ef495ae8d5cc225fb7dd265fac62e40268b5f2
# shark @ SharkAir in ~/docker_files/mysql-docker/5.7 on git:mysql-server x [20:59:43]
$ docker run -itd --rm --name=container2 busybox
8a83b0d89c2005f488d00e5dc4d46812a2aeb7f1bcec9f061d9762f6c901275e
2.2 创建一个隔离的桥接网络 my-net
下面在创建网络的时候,使用了 --subnet
为此网络指定了一个子网 172.20.0.0/16
# shark @ SharkAir in ~/docker_files/mysql-docker/5.7 on git:mysql-server x [21:01:47] C:1
$ docker network create -d bridge --subnet 172.20.0.0/16 my-net
124cb50f08a8ec2a0af44365505e16b3f77b5671373639a1e23f8535a9054d0a
注意现在
container1
和container2
都被自动连接在默认的桥接网络bridge
上
# 部分内容
"Containers": {
"368a503800d4007627d0b63946ef495ae8d5cc225fb7dd265fac62e40268b5f2": {
"Name": "container1",
"EndpointID": "d02b2ab691e5940a74de77ec6a68d35d52c8800014a96f830f04890971587ce2",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"8a83b0d89c2005f488d00e5dc4d46812a2aeb7f1bcec9f061d9762f6c901275e": {
"Name": "container2",
"EndpointID": "2e330964b4cc2b5897eeb9fac15dbc03e4326cc47c087e0276de88509f64a0ac",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
}
},
2.3 现在将 container2 加入到
my-net` 网络中
$ docker network connect my-net container2
查看 my-net
网络,以验证
# shark @ SharkAir in ~/docker_files/mysql-docker/5.7 on git:mysql-server x [21:07:16]
$ docker network inspect my-net
[
{
"Name": "my-net",
"Id": "124cb50f08a8ec2a0af44365505e16b3f77b5671373639a1e23f8535a9054d0a",
"Created": "2018-12-11T13:02:03.0854486Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/16"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"8a83b0d89c2005f488d00e5dc4d46812a2aeb7f1bcec9f061d9762f6c901275e": {
"Name": "container2",
"EndpointID": "2663b56686a331e68de1a0c5955d9f3b8ef102653547e43f5d9ef8891d84ffd2",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
2.4 运行第三个容器并指定网络。
下面我们运行第三个容器 container3
,并且同时使用 --network
指定其加入网络 my-net
, 还使用了 --ip
来指定分配给容器的具体 IP 地址。
$ docker run -itd --rm --name=container3 --network=my-net --ip=172.20.0.100 busybox
db4ef2529e81e20508e029ade69ffae08df6dcc538d426b49ca1d9b830d7f0c7
注意:
只要为容器指定的IP地址是网络子网中的一部分,连接到网络时就可以使用--ip
或--ip6
标记将IPv4或IPv6地址分配给容器。
在使用用户定义的网络时以这种方式指定IP地址时,配置将作为容器配置的一部分保留,并在重新加载容器时应用。
使用非用户定义的网络时,不会保留分配的IP地址,无法保证在Docker守护程序重新启动时容器的子网不会更改。
2.5 查看容器三的源数据网络部分
部分内容已截断
$ docker inspect container3
"Networks": {
"my-net": {
"IPAMConfig": {
"IPv4Address": "172.20.0.100" # 指定分配的地址
},
"Links": null,
"Aliases": [
"db4ef2529e81"
],
"NetworkID": "124cb50f08a8ec2a0af44365505e16b3f77b5671373639a1e23f8535a9054d0a",
"EndpointID": "ec7774f1936d056ff4b39a862972e11c102d53c61669e5c230e47be35d65ca08",
"Gateway": "172.20.0.1",
"IPAddress": "172.20.0.100",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:14:00:64",
"DriverOpts": null
}
}
2.6 再来查看容器二的元数据网络部分
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "8a5f470ffe774f4f96a712642ed361fbeb0d8e66018e1d629ab44cfdf3e42a05",
"EndpointID": "2e330964b4cc2b5897eeb9fac15dbc03e4326cc47c087e0276de88509f64a0ac",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
},
"my-net": {
"IPAMConfig": {},
"Links": null,
"Aliases": [
"8a83b0d89c20"
],
"NetworkID": "124cb50f08a8ec2a0af44365505e16b3f77b5671373639a1e23f8535a9054d0a",
"EndpointID": "2663b56686a331e68de1a0c5955d9f3b8ef102653547e43f5d9ef8891d84ffd2",
"Gateway": "172.20.0.1",
"IPAddress": "172.20.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:14:00:02",
"DriverOpts": null
}
}
可以发现
container2
同时加入了两个网络bridge
和my-net
,并且有两个地址172.17.0.3
和172.20.0.2
2.7 进入容器 container2
中,查看网卡信息
# shark @ SharkAir in ~ [21:40:45]
$ docker exec -it container2 /bin/sh
/ # ip -4 a
1: lo: mtu 65536 qdisc noqueue qlen 1
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
97: eth0@if98: mtu 1500 qdisc noqueue
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
100: eth1@if101: mtu 1500 qdisc noqueue
inet 172.20.0.2/16 brd 172.20.255.255 scope global eth1
valid_lft forever preferred_lft forever
container2
有两个网络接口卡,分别分配了 IP地址。
这是因为,我们一开始运行这个容器的时候,被连接到默认的网络上,后来我们又执行了docker network connect
命令,把它连接到了my-net
网络上了,所以这使其有两个网络,并且有两个网卡。
2.8 尝试利用容器名进行通信测试
Docker嵌入式DNS服务器可以为连接到给定网络的容器启用名称解析。
也就是说目前在 container2
中可以使用容器名和 container3
进行通信。
但是由于默认的网络 bridge
只支持通过 IP
地址通信,所以当 container2
和 container3
互相通信时,只能通过彼此的 IP
地址了。
# shark @ SharkAir in ~ [22:19:51]
$ docker exec -it container2 /bin/sh
/ # ping -w 2 container3
PING container3 (172.20.0.100): 56 data bytes
64 bytes from 172.20.0.100: seq=0 ttl=64 time=0.406 ms
64 bytes from 172.20.0.100: seq=1 ttl=64 time=0.176 ms
--- container3 ping statistics ---
3 packets transmitted, 2 packets received, 33% packet loss
round-trip min/avg/max = 0.176/0.291/0.406 ms
/ # ping -w 2 container1
ping: bad address 'container1'
/ # ping -w 2 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.246 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.162 ms
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 2 packets received, 33% packet loss
round-trip min/avg/max = 0.162/0.204/0.246 ms
/ # exit # 退出容器
# shark @ SharkAir in ~ [22:25:11]
$
注意:
container3
和container1
并没有任何共同的网络,所以他们是无法通信的。
# shark @ SharkAir in ~ [22:29:52]
$ docker exec -it container3 /bin/sh
/ # ping -w 2 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
/ #
其实即使容器未运行,您也可以将容器连接到网络。但是,docker network inspect仅显示有关正在运行的容器的信息。
3. 使用容器别名
容器的别名只能在自定义网络中有效。
容器的别名只在其针对的网络中有效。
3.1 一个容器可以在不同的网络中分别使用不同的容器别名
a. 创建另一个名为local_alias
的桥接网络
$ docker network create local_alias
ade171853dd89d36411bff45f2b1356fc622fa1e74e6d6df338df4f129b58aac
b. 运行一个新的容器 container4
, 并加入到网络 local_alias
, 同时使用 --network-alias
指定这个容器在此网络中的别名为 auto_git
。
$ docker run -itd --rm --name=container4 --network=local_alias --network-alias=auto_git busybox
fab547bb39669c3b9d9f8d4816fe9c637a0b1835516296a6d645229a51fb423e
c. 把容器 container4
加入到网络 my-net
, 同时使用 --alias
指定容器在这个网络中的别名为 auto_ansible
。
$ docker network connect --alias auto_ansible my-net container4
d. 分别进入容器 container3
和 container4
中进行连通性测试。
container3
可以看到同一个容器有多个别名时,每个别名只能在当时绑定到那个网络中有效。
从上图中也不难发现,同一个容器有多个别名时,每个别名会被解析为其对应网络中的地址。
3.2 多个容器在相同的网络中可以使用一个别名
a. 运行容器 container5
和 container6
且加入到网络 my-net
, 并且使用 --network-alias
指定一样的容器别名为 multiapps
。
$ docker run -itd --rm --name=container5 --network='my-net' --network-alias=multiapps busybox
f25abbc871c9c513fc20bdbc0b8e620e3ed0a658ec84fea44d5bddc832d8034f
$ docker run -itd --rm --name=container6 --network='my-net' --network-alias=multiapps busybox
bd7372233e9092ddb758db65724b496ba2e48724a339cd8ed11fe261b786499e
b. 查看 my-net
网络的元数据
以下是部分内容
"bd7372233e9092ddb758db65724b496ba2e48724a339cd8ed11fe261b786499e": {
"Name": "container6",
"EndpointID": "ec9483fce8f580bdd3d2ea05c17ea3cd7245a8a5c0c51c66074ca50a6f3d2254",
"MacAddress": "02:42:ac:14:00:05",
"IPv4Address": "172.20.0.5/16",
"IPv6Address": ""
},
"db4ef2529e81e20508e029ade69ffae08df6dcc538d426b49ca1d9b830d7f0c7": {
"Name": "container3",
"EndpointID": "ec7774f1936d056ff4b39a862972e11c102d53c61669e5c230e47be35d65ca08",
"MacAddress": "02:42:ac:14:00:64",
"IPv4Address": "172.20.0.100/16",
"IPv6Address": ""
},
"f25abbc871c9c513fc20bdbc0b8e620e3ed0a658ec84fea44d5bddc832d8034f": {
"Name": "container5",
"EndpointID": "9e0d28500b688d30443be25ef253cdba684f46221f57dcfe590b2eb44aa7cf74",
"MacAddress": "02:42:ac:14:00:04",
"IPv4Address": "172.20.0.4/16",
"IPv6Address": ""
},
可以看到当前网络中
container5
的地址是172.20.0.4/16
container6
的地址是172.20.0.5/16
c. 进入到容器 container3
中持续 ping
容器的别名 multiapps
。
$ docker exec -it container3 /bin/sh
/ # ping multiapps
PING multiapps (172.20.0.5): 56 data bytes
64 bytes from 172.20.0.5: seq=0 ttl=64 time=0.186 ms
64 bytes from 172.20.0.5: seq=1 ttl=64 time=0.176 ms
64 bytes from 172.20.0.5: seq=2 ttl=64 time=0.175 ms
d. 打开另一终端,断开容器 container6
到网络 my-net
的连接。
$ docker network disconnect my-net container6
e. 再次会到原来在 container3
中持续 ping
的终端中
发现应无法 ping
通原来解析的地址的,因为下 container6
已经从 my-net
网络中断开了。
但是我们仍然可以再次使用 multiapps
这个别名和另外的容器 (cotainer5
) 继续通信。
按 Ctrl + c
组合结束当前的 ping
, 重新 ping
multiapps
可以发现
multiapps
被解析为容器container5
的 IP 地址172.20.0.4
了
4. 从网络中断开一个容器的连接
docker network disconnect 网络名 容器名
5. 删除一个自定义的网络
docker network rm 网络名