3.docker网络以及数据持久化
Docker网络管理
本节主要是介绍docker默认的网络行为,包含创建的默认网络类型以及如何创建用户自定义网络,也会介绍如何在单一主机或者跨主机集群上创建网络的资源需求。
一. 网络驱动(Network drivers)
docker网络子系统使用驱动程序来进行插件设计,默认情况下存在几个驱动程序,它们提供核心网络功能:
- bridge:默认的网络驱动程序。如果未指定驱动程序,创建的就是这种网络类型,当你的应用运行在独立的容器中,并需要网络通信时,通常选择这种网络类型。
- host:对于独立的容器,直接使用主机的网络,容器和主机之间没有网络隔离;
- overlay:覆盖网络将多个Docker守护程序连接在一起,并使群集服务能够相互通信;
- macvlan:Macvlan网络允许您为容器分配MAC地址,使其在网络上显示为物理设备。Docker守护程序通过其MAC地址将流量路由到容器。
- none:对于这样的容器,禁用所有联网。通常与自定义网络驱动程序一起使用。
网络选择建议
- 当您需要多个容器在同一Docker主机上进行通信时,最好使用用户定义的网桥网络。
- 当网络堆栈不应与Docker主机隔离时,但您希望容器的其他方面隔离时,主机网络是最佳选择。
- 当您需要在不同Docker主机上运行的容器进行通信时,或者当多个应用程序使用集群服务一起工作时,覆盖网络是最好的。
- 从VM设置迁移或需要容器看起来像网络上的物理主机时,Macvlan网络是最好的,每个主机都有唯一的MAC地址。
- 第三方网络插件使您可以将Docker与专用网络堆栈集成。
二. 网络类型原理
当你安装了docker,它自动创建了3个网络,可以使用docker network命令来查看
[root@nextcloud ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
6ae630a60420 bridge bridge local
90ae88ff8547 host host local
dc10f0907833 none null
这三个网络被docker内建。当你运行一个容器的时候,可以使用–network参数来指定你的容器连接到哪一个网络。
1. bridge网络
默认连接到docker0这个网桥上。
[root@nextcloud ~]# ip addr show docker0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:34:1d:06:91 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
[root@nextcloud ~]# brctl show docker0
bridge name bridge id STP enabled interfaces
docker0 8000.0242341d0691 no
注:brctl 命令在centos中可以使用
yum install bridge-utils
来安装启动并运行一个容器
[root@nextcloud ~]# docker run -itd --name test01 nginx:latest
d3487007f1965a4e93efb851115a2c975db890b6fd3623c08af33dab193db834
root@d3487007f196:/# apt-get update
root@d3487007f196:/# apt-get install net-tools iproute2 -y
root@d3487007f196:/# ip addr show
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
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
可以看到test01容器已经获取了一个地址172.17.0.3,和主机的docker0接口地址在同一网络,并将主机的docker0接口地址设置为了网关。
root@d3487007f196:/# ip route show
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
在物理主机上,查看网桥docker0,可以看到已经多了一个接口
[root@nextcloud ~]# brctl show docker0
bridge name bridge id STP enabled interfaces
docker0 8000.0242341d0691 no veth3d69c3f
Docker 容器默认使用 bridge 模式的网络。其特点如下:
- 使用一个 linux bridge,默认为 docker0
- 使用 veth 对,一头在容器的网络 namespace 中,一头在 docker0 上
- 该模式下Docker Container不具有一个公有IP,因为宿主机的IP地址与veth pair的 IP地址不在同一个网段内
- Docker采用 NAT 方式,将容器内部的服务监听的端口与宿主机的某一个端口port 进行“绑定”,使得宿主机以外的世界可以主动将网络报文发送至容器内部
- 外界访问容器内的服务时,需要访问宿主机的 IP 以及宿主机的端口 port
- NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。
- 容器拥有独立、隔离的网络栈;让容器和宿主机以外的世界通过NAT建立通信效果是这样的: 示意图如下:
在物理主机上查看iptables的nat表,可以看到在POSTROUTING链中做了地址伪装:MASQUERADE动作,这样容器就可以通过源地址转换NAT访问外部网络了。通过iptables -t nat -vnL命令查看到:
[root@nextcloud ~]# iptables -t nat -vnL
....略...
Chain POSTROUTING (policy ACCEPT 354 packets, 25260 bytes)
pkts bytes target prot opt in out source destination
35 2141 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
363 25887 POSTROUTING_direct all -- * * 0.0.0.0/0 0.0.0.0/0
363 25887 POSTROUTING_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
363 25887 POSTROUTING_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
...略...
可以使用docker network inspect bridge命令来查看bridge网络情况:
[root@nextcloud ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "6ae630a60420afd6675443258c4391750db463c8ab90145539ad779cbdfffd0f",
"Created": "2020-12-14T09:26:05.149953821+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": {
"d3487007f1965a4e93efb851115a2c975db890b6fd3623c08af33dab193db834": {
"Name": "test01",
"EndpointID": "1205b528d1722adb7695b7ca0abce8d2cbccc8432751916b714bd4bf093f006c",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/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": {}
}
]
2. none网络模式:
网络模式为 none,即不为Docker容器构造任何网络环境,不会为容器创建网络接口,一旦Docker容器采用了none网络模式,那么容器内部就只能使用loopback网络设备,不会再有其他的网络资源。Docker Container的none网络模式意味着不给该容器创建任何网络环境,容器只能使用127.0.0.1的本机网络。
启动一个容器,设为none网络
[root@nextcloud ~]# docker run -itd --network none --name test02 centos:latest
3549f096f41195c043c7f6d34fb28bbfc92f6272123e59d4c1cb032f0f511612
进入容器,查看网络情况:
[root@nextcloud ~]# docker exec -it test02 /bin/bash
[root@3549f096f411 /]# ip addr show
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
[root@3549f096f411 /]# ip route show
3. host网络模式
Host模式并没有为容器创建一个隔离的网络环境。而之所以称之为host模式,是因为该模式下的Docker 容器会和host宿主机共享同一个网络namespace,故Docker Container可以和宿主机一样,使用宿主机的eth0,实现和外界的通信。换言之,Docker Container的IP地址即为宿主机 eth0的IP地址。
其特点包括:
- 这种模式下的容器没有隔离的 network namespace
- 容器的 IP 地址同 Docker host 的 IP 地址
- 需要注意容器中服务的端口号不能与 Docker host 上已经使用的端口号相冲突
- host 模式能够和其它模式共存
示意图:
例如,我们在192.168.1.102/24 的机器上用 host 模式启动一个含有 web 应用的 Docker 容器,监听 tcp 80 端口。当我们在容器中执行任何类似 ifconfig 命令查看网络环境时,看到的都是宿主机上的信息。而外界访问容器中的应用,则直接使用192.168.1.102:80 即可,不用任何 NAT 转换,就如直接跑在宿主机中一样。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。启动容器前,查看物理主机的httpd进程
[root@nextcloud ~]# pgrep httpd
[root@nextcloud ~]#
启动一个容器:
[root@nextcloud ~]# docker run -itd --privileged --name web01 --network host centos:latest init
201429428e727520310cd250303aaa642675cf6e62ea9be430acab9b818c1177
进入容器,安装httpd服务,并启动
[root@nextcloud ~]# docker exec -it web01 /bin/bash
[root@nextcloud /]# yum install httpd -y
[root@nextcloud /]# systemctl start httpd
[root@nextcloud /]# echo 'test docker host network' > /var/www/html/index.html
退出容器,再次查看httpd进程
[root@nextcloud /]# exit
exit
[root@nextcloud ~]# pgrep httpd
8712
8713
8714
8715
8716
访问主机的80端口,可以访问到容器test7中的网站服务:
注意防火墙:
[root@nextcloud ~]# firewall-cmd --add-port=80/tcp
success
4. container 模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
Container 网络模式是 Docker 中一种较为特别的网络的模式。这两个容器之间不存在网络隔离,而这两个容器又与宿主机以及除此之外其他的容器存在网络隔离。
注意:因为此时两个容器要共享一个network namespace,因此需要注意端口冲突情况,否则第二个容器将无法被启动。
示意图:
运行一个容器:查看容器的IP
[root@nextcloud ~]# docker run -itd --name test03 centos:latest
ba2c8a9ad8b5123ae4558e7f3f340e046ed65d75aa24d129957661b01db8be91
[root@nextcloud ~]# docker exec -it test03 /bin/bash
[root@ba2c8a9ad8b5 /]# ip add show
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
4: eth0@if5: <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
启动另外一个容器,使用test03容器的网络
[root@nextcloud ~]# docker run -itd --name test04 \
> --network container:test03 \
> centos:latest
72a3f6ed22bb7a847ddb23850756dd8e9f2eef64963137c21ceb12824ec7c85d
进入容器test04,查看网络情况,可以看到两个容器地址信息相同,是共享的
[root@nextcloud ~]# docker exec -it test04 /bin/bash
[root@ba2c8a9ad8b5 /]# ip addr show
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
4: eth0@if5: <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
[root@ba2c8a9ad8b5 /]#
三. 外部访问容器
通过上面的docker网络学习,已经可以实现容器和外部网络通信了,但是如何让外部网络来访问容器呢?
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。
- 当使用–P(大写)标记时,Docker 会随机映射一个随机的端口到内部容器开放的网络端口。
注:-P使用时需要指定–expose选项或dockerfile中用expose指令容器要暴露的端口,指定需要对外提供服务的端口。
下载nginx镜像并启动一个容器:
[root@nextcloud ~]# docker run -itd -P --name web02 nginx:latest
7989036e8288c5144f29a7c1b26ea7688f81a919d333760052065ea44eb84b20
[root@nextcloud ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7989036e8288 nginx:latest "/docker-entrypoint.…" 11 seconds ago Up 10 seconds 0.0.0.0:32768->80/tcp web02
[root@nextcloud ~]# docker port web02
80/tcp -> 0.0.0.0:32768
可以看到容器的80端口被随机映射到主机的32768端口;
访问主机IP地址的32768端口,就可以访问到容器的http服务
- -p(小写)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有:
- ip:hostPort:containerPort
- ip::containerPort
- hostPort:containerPort
注意:容器有自己的内部网络和 ip 地址(使用docker inspect 可以获取所有的变量。);-p 标记可以多次使用来绑定多个端口
[root@nextcloud ~]# docker run -itd -p 8000:80 --name web03 nginx:latest
6dc831d65d5847af16ab9acc98504c1132c02d5bd31812639b8c943d2dd450dd
[root@nextcloud ~]# docker port web03
80/tcp -> 0.0.0.0:8000
[root@nextcloud ~]#
##可以看到主机的8000端口已经和容器web03容器的80端口做了映射
docker端口映射实质上是在iptables 的nat表中添加了DNAT规则
[root@nextcloud ~]# iptables -t nat -vnL
....略....
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:32768 to:172.17.0.3:80
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8000 to:172.17.0.4:80
....略....
并在防火墙中自动放行了这些流量
[root@nextcloud ~]# iptables -nvL
....略....
Chain DOCKER (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.3 tcp dpt:80
0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.4 tcp dpt:80
....略....
四. 用户自定义网络(User-defined networks)
建议使用用户定义的桥接网络来控制容器之间彼此通信,用户定义的网桥网络优于默认bridge 网络:
- 用户定义的网桥可在容器之间提供自动DNS解析,缺省桥接网络上的容器只能通过IP地址相互访问,除非您使用传统的–link选项;在用户定义的网桥网络上,容器可以通过名称或别名相互解析。
- 用户定义的网桥可提供更好的隔离。所有未指定–network的容器都将连接到默认网桥网络,这可能是一种风险;
- 容器可以随时随地从用户定义的网络连接和分离。在容器的生存期内,您可以即时将其与用户定义的网络连接或断开连接。要从默认网桥网络中删除容器,您需要停止容器并使用其他网络选项重新创建它;
- 每个用户定义的网络都会创建一个可配置的网桥。
- 默认网桥网络上的链接容器共享环境变量。
docker网络管理命令如下:
- docker network create
- docker network connect
- docker network ls
- docker network rm
- docker network disconnect
- docker network inspect
- 默认创建的是bridge网络:
[root@docker01 ~]# docker network create simple-network
b3e3c58a844e486644e0bd44a67fc983532a36e854208e8256cbb0e164f50480
[root@docker01 ~]# docker network inspect simple-network
[
{
"Name": "simple-network",
"Id": "b3e3c58a844e486644e0bd44a67fc983532a36e854208e8256cbb0e164f50480",
"Created": "2018-01-04T16:53:21.071813651+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
- 当你创建了一个网络,默认会创建一个不重叠的子网,使用–subnet选项可以直接指定子网络,在bridge网络中只可以指定一个子网络,而在overlay网络中支持多个子网络。
$ docker network create --driver=bridge --subnet=192.168.0.0/16 br0
- 除了
--subnet
,还可以指定:--gateway
,--ip-range
,--aux-address
等选项。
$ docker network create \
--driver=bridge \
--subnet=172.28.0.0/16 \
--ip-range=172.28.5.0/24 \
--gateway=172.28.5.254 \
br0
-
创建自定义网络时,可以向驱动程序传递附加选项,bridge驱动接受以下选项:
选项 等效于 描述 com.docker.network.bridge.name – 创建Linux网桥时要使用的网桥名称 com.docker.network.bridge.enable_ip_masquerade –ip-masq 启用IP伪装 com.docker.network.bridge.enable_icc –icc 启用或禁用容器间连接 com.docker.network.bridge.host_binding_ipv4 –ip 绑定容器端口时的默认IP com.docker.network.driver.mtu –mtu 设置容器网络MTU com.docker.network.container_interface_prefix – 为容器接口设置自定义前缀 -
可以将以下参数传递给docker network create任何网络驱动程序:
参数 等效于 描述 –gateway – 主子网的IPv4或IPv6网关 –ip-range –fixed-cidr 分配的IP范围 –internal – 限制外部访问网络 –ipv6 –ipv6 启用IPv6网络 –subnet –bip 网络子网 -
例如,使用-o或者–opt指定发布端口时绑定的IP地址:
[root@nextcloud ~]# docker network create -o \
> "com.docker.network.bridge.host_binding_ipv4"="192.168.154.136" \
> my-network
4c76caa683adb07847193f7112146e61cb709fae242de842186cd898726eb31f
[root@nextcloud ~]# docker network inspect my-network
[
{
"Name": "my-network",
"Id": "4c76caa683adb07847193f7112146e61cb709fae242de842186cd898726eb31f",
"Created": "2020-12-20T08:12:43.813056658+08:00",
"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": { ##这里是选项配置的结果
"com.docker.network.bridge.host_binding_ipv4": "192.168.154.136"
},
"Labels": {}
}
]
- 启动一个容器并发布端口:可以看到绑定的地址
[root@nextcloud ~]# docker run -itd -P --network my-network --name web008 nginx:latest
1ab2ed1cdf2eb7da4f42c84461b4eb64c12fa79eacda0e920f294312092eaa29
[root@nextcloud ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1ab2ed1cdf2e nginx:latest "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 192.168.154.136:32768->80/tcp web008
- 可以连接已存在的容器到一个或者多个网络中。一个容器可以连接到多个不同网络驱动的网络中。
- 当连接一旦建立,容器便可以和其他的容器通讯,通过IP或者容器名称。
- 对于支持多主机连接的overlay网络或者自定义插件,连接到同一个多主机网络的不同主机上的容器,也可以用这种方式通信。
基本容器网络示例:
- 首先,创建和运行两个容器:container1和container2;
[root@nextcloud ~]# docker run -itd --name continer1 centos:latest
e0e9b4dc9423165ee41a659f6af677919d4782cd41f268b98b6f46c8bb0bcdb5
[root@nextcloud ~]# docker run -itd --name continer2 centos:latest
72c32ac162594c6c2ae1dbfb675d5c3fcc1070bd91b61d766c225a45c0b52919
- 创建一个用户自定义网络bridge网络isolated_nw;
[root@nextcloud ~]# docker network create -d bridge --subnet 172.25.0.0/16 \
> --gateway 172.25.0.1 isolated_nw
5404c88e0ccf2652af06ebe5458dfb6f53fdde33d09d0b077b4ae04797538237
- 连接continer2容器到这个新创建的网络,并inspect这个网络,检查网络的连接;
[root@nextcloud ~]# docker network connect isolated_nw continer2
[root@nextcloud ~]# docker network inspect isolated_nw
[
{
"Name": "isolated_nw",
"Id": "5404c88e0ccf2652af06ebe5458dfb6f53fdde33d09d0b077b4ae04797538237",
"Created": "2020-12-20T08:24:38.291128747+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.25.0.0/16",
"Gateway": "172.25.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"72c32ac162594c6c2ae1dbfb675d5c3fcc1070bd91b61d766c225a45c0b52919": {
"Name": "continer2",
"EndpointID": "e26a7fde962cd4b43c06c64ec26aa21769a588b7d397bb26fab31bf5bdf206d8",
"MacAddress": "02:42:ac:19:00:02",
"IPv4Address": "172.25.0.2/16", ##获取到自定义网络的IP地址
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
- 创建容器continer3,并分配一个固定IP172.25.3.3;
[root@nextcloud ~]# docker run -itd --name continer3 --network isolated_nw --ip=172.25.3.3 centos:latest
a2bff343556b83f75ccff4f64a79452e035567fd553356f0cc8e1c9906492bb3
- 检查continer3的网络资源;
[root@nextcloud ~]# docker inspect continer3
[
{
....略.....
"Networks": {
"isolated_nw": {
"IPAMConfig": {
"IPv4Address": "172.25.3.3"
},
"Links": null,
"Aliases": [
"a2bff343556b"
],
"NetworkID": "5404c88e0ccf2652af06ebe5458dfb6f53fdde33d09d0b077b4ae04797538237",
"EndpointID": "fe7d8f13520a7edec541a3e3bb79562fd1c02514264c56984e1191757b3b079a",
"Gateway": "172.25.0.1",
"IPAddress": "172.25.3.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:19:03:03",
"DriverOpts": null
}
}
}
}
]
- 检查continer2的网络:
[root@nextcloud ~]# docker inspect continer2
[
{
...........略..............
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "0363fa1fec426ee394fbb16c29c6e7373b16a40e6b2eaeb861ae241f049faf78",
"EndpointID": "90a323b89f46db594621a61a5ed91322f3b8d7bf6fe0fc1f401314ff873605e3",
"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
},
"isolated_nw": {
"IPAMConfig": {},
"Links": null,
"Aliases": [
"72c32ac16259"
],
"NetworkID": "5404c88e0ccf2652af06ebe5458dfb6f53fdde33d09d0b077b4ae04797538237",
"EndpointID": "e26a7fde962cd4b43c06c64ec26aa21769a588b7d397bb26fab31bf5bdf206d8",
"Gateway": "172.25.0.1",
"IPAddress": "172.25.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:19:00:02",
"DriverOpts": {}
}
}
}
}
]
- 现在continer2属于两个网络:
- 进入容器continer2,并尝试和continer3及continer1通信;
[root@nextcloud ~]# docker exec -it continer2 /bin/bash
[root@72c32ac16259 /]# ip addr show
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
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
12: eth1@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:19:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.25.0.2/16 brd 172.25.255.255 scope global eth1
valid_lft forever preferred_lft forever
[root@72c32ac16259 /]# ip route show
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
172.25.0.0/16 dev eth1 proto kernel scope link src 172.25.0.2
- 有两个IP,网关是连接到的第一个网络的网关。docker内嵌了DNS服务,意思是链接到同一个网络的容器,可以使用容器名进行通信。
[root@72c32ac16259 /]# ping -c 3 continer3
PING continer3 (172.25.3.3) 56(84) bytes of data.
64 bytes from continer3.isolated_nw (172.25.3.3): icmp_seq=1 ttl=64 time=0.063 ms
64 bytes from continer3.isolated_nw (172.25.3.3): icmp_seq=2 ttl=64 time=0.195 ms
64 bytes from continer3.isolated_nw (172.25.3.3): icmp_seq=3 ttl=64 time=0.094 ms
--- continer3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 0.063/0.117/0.195/0.057 ms
- 默认的bridge网络是不可以使用名称通信的,IP可以
[root@72c32ac16259 /]# ping -c 3 continer1
ping: continer1: Name or service not known
[root@72c32ac16259 /]# ping -c 3 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.056 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.068 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.173 ms
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2ms
rtt min/avg/max/mdev = 0.056/0.099/0.173/0.052 ms
- 如果想让默认网络中,也可以使用容器名进行通信呢?
- 使用link的特性(传统方式),这是唯一推荐使用link的场景。应该使用自定义的网络来替代它的。
- 在默认网络中使用link增加了一下特性:
- 解析容器名到IP地址
- 定义网络别名:–link=CONTAINER-NAME:ALIAS
- 增强网络连接的安全性
- 环境变量注入
[root@nextcloud ~]# docker run -itd --name container4 --link continer1:c1 centos:latest /bin/bash
5326bd282fa7800dfbfeb143c340a6949de7415b0440b1bb18f7ba4fa800c0c8
[root@nextcloud ~]# docker exec -it container4 /bin/bash
[root@5326bd282fa7 /]# ping -c 2 continer1
PING c1 (172.17.0.2) 56(84) bytes of data.
64 bytes from c1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.063 ms
64 bytes from c1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.149 ms
--- c1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1ms
rtt min/avg/max/mdev = 0.063/0.106/0.149/0.043 ms
[root@5326bd282fa7 /]# ping -c 2 c1
PING c1 (172.17.0.2) 56(84) bytes of data.
64 bytes from c1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.071 ms
64 bytes from c1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.154 ms
--- c1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 2ms
rtt min/avg/max/mdev = 0.071/0.112/0.154/0.042 ms
- 取消网络连接
[root@nextcloud ~]# docker network disconnect isolated_nw continer2
[root@nextcloud ~]# docker network disconnect isolated_nw continer3
- 删除网络
[root@nextcloud ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0363fa1fec42 bridge bridge local
90ae88ff8547 host host local
5404c88e0ccf isolated_nw bridge local
4c76caa683ad my-network bridge local
dc10f0907833 none null local
[root@nextcloud ~]# docker network rm isolated_nw
isolated_nw
[root@nextcloud ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0363fa1fec42 bridge bridge local
90ae88ff8547 host host local
4c76caa683ad my-network bridge local
dc10f0907833 none null local
在Docker中管理数据
默认情况下,在容器内创建的所有文件都存储在可写容器层上。这意味着:
- 当该容器不再存在时,数据将不会持久保存,并且如果另一个进程需要它,则可能很难从容器中取出数据。
- 容器的可写层与运行容器的主机紧密耦合,您不能轻易地将数据移动到其他地方。
- 写入容器的可写层需要 存储驱动程序来管理文件系统。存储驱动程序支持联合文件系统,需要使用Linux内核。与使用直接写入主机文件系统的数据卷相比,这种额外的抽象降低了性能 。
如何希望容器停止后文件也可以持久存储,docker提供了2种方式:
- volumes
- bind mounts
如果你是在Linux上运行docker,还可以选择tmpfs mount,如果你是在Windows上运行docker,你也可以使用named pipe(命名管道)。
无论您选择使用哪种类型,容器中的数据看起来都是相同的。它在容器的文件系统中显示为目录或单个文件。
- volumes: 数据存储在由docker管理的主机文件系统的一部分上(默认位置//var/lib/docker/volumes/,对于linux系统来说),非Docker进程不应修改文件系统的这一部分。volumes是在Docker中持久保存数据的最佳方法。
- bind mounts: 可以存储在主机系统上的任何位置。它们甚至可能是重要的系统文件或目录。Docker主机上的非Docker进程或一个Docker容器可以随时对其进行修改。
- tmpfs mount:仅存储在主机系统的内存中,并且永远不会写入主机系统的文件系统中。
一. 使用 volumes
卷是将数据持久存储在Docker容器和服务中的首选方法。
当启动一个容器时,使用了一个新创建的volumes,如果容器的目录中有内容,则该目录中的内容会被复制到volumes里面,然后容器挂载并使用volumes,其它使用该volumes的容器也可以访问预填充的内容。
1. volumes使用场景
卷的一些用例包括:
- 在多个运行中的容器之间共享数据。如果未显式创建卷,则在首次将卷安装到容器中时将创建该卷。当该容器停止或卸下时,该卷仍然存在。多个容器可以同时装载相同的卷(可读写或只读)。仅在显式删除卷时才将它们删除。
- 当您要将容器的数据存储在远程主机或云提供商上,而不是在本地时,可以使用volumes;
- 当您需要将数据从一台Docker主机备份,还原或迁移到另一台Docker主机时,卷是一个更好的选择。停止使用该卷的容器,然后备份该卷的目录(例如/var/lib/docker/volumes/)。
2. volumes的优点:
- 与bind mounts相比,卷更易于备份或迁移。
- 可以使用Docker CLI命令或Docker API管理卷。
- 卷在Linux和Windows容器上均可工作。
- 可以在多个容器之间更安全地共享卷。
- 卷驱动程序使您可以将卷存储在远程主机或云提供程序上,以加密卷内容或添加其他功能。
- 可以通过容器预填充新卷的内容。
3. volumes的使用
创建和管理volumes
与bind mounts不同,您可以在任何容器范围之外创建和管理卷。
- 创建一个volumes
[root@python-study ~]# docker volume create my-vol
my-vol
- 列出volumes
[root@python-study ~]# docker volume ls
DRIVER VOLUME NAME
local my-vol
- 检查volumes的详细信息
[root@python-study ~]# docker volume inspect my-vol
[
{
"CreatedAt": "2020-09-01T10:38:34+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
- 移除一个volumes
[root@python-study ~]# docker volume rm my-vol
my-vol
启动容器时使用volumes
启动容器时,如果想使用volumes,可以使用-v 或 –mount 选项。如果指定的volumes不存在,则启动的时候会自动创建。
- -v or –volume:用于独立的容器管理卷,使用冒号分隔;
- 第一个字段是卷的名称;
- 第二个字段是容器中的文件或目录路径;
- 第三个字段是可选的,并且是用逗号分隔的选项列表,例如
ro
。
$ docker run -d \
--name devtest \
-v myvol2:/app \
nginx:latest
- –mount:从docker 17.06 版本后,可以用于集群也可以用于独立容器。包含多个键值对,以逗号分隔,每个键值对都由一个 元组组成。
<key>=<value>
- type:指定挂载的类型,可以是bind,volume,tmpfs;
- source或src:指定volume的名字;
- destination或者dst或target:指定容器中的文件或目录路径;
- readonly:只读;
- volume-opt:指定多个key-value对可用选项;
$ docker run -d \
--name devtest \
--mount source=myvol2,target=/app \
nginx:latest
可以使用docker inspect devtest命令查看容器详细信息,在Mounts
部分可以看到卷的信息:
"Mounts": [
{
"Type": "volume",
"Name": "myvol2",
"Source": "/var/lib/docker/volumes/myvol2/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
删除卷
删除卷是一个独立的步骤,删除容器并不能移除卷。
$ docker container stop devtest
$ docker container rm devtest
$ docker volume rm myvol2
4. 备份、还原和迁移数据卷
volumes对于备份、还原和迁移来说是很有用的,创建一个新容器时,可以使用–volumes-from来挂载这些volumes。
备份一个容器
- 为了演示,先创建一个新的容器,名字为dbstore:
[root@python-study ~]# docker run -itd -v /dbdata --name dbstore ubuntu /bin/bash
490d16687f0a2e61e88b4157251a33ee5acea0991b36d2ae4a2e47fe1c3e50f6
- 进入容器,在容器内的/dbdata目录中创建一些文件,用于测试
[root@python-study ~]# docker exec -it dbstore /bin/bash
root@490d16687f0a:/# cd /dbdata/
root@490d16687f0a:/dbdata# echo 'this is backup test!' > file1.txt
root@490d16687f0a:/dbdata# ls
file1.txt
- 然后执行备份命令
- 启动一个新容器挂载容器dbstore的volumes
- 挂载本地的主机目录到容器内部/backup目录
- 执行tar命令打包备份/dbdata目录中的内容到/backup目录,文件名为backup.tar
[root@python-study ~]# docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
tar: Removing leading `/' from member names
/dbdata/
/dbdata/file1.txt
- 查看主机目录,验证备份文件已经存在
[root@python-study ~]# ls backup.tar
backup.tar
[root@python-study ~]# tar -tf backup.tar
dbdata/
dbdata/file1.txt
从备份还原到容器
可以将备份文件还原到相同的容器中或在其他位置的另一个容器中。
- 例如创建一个新的容器dbstore2。
[root@python-study ~]# docker run -itd -v /dbdata --name dbstore2 ubuntu /bin/bash
17b5e3d2c85d79338c705bf5880a4078106a7167b58827c1a34c67e30a4d0157
- 还原操作:将备份文件解压缩到新容器的数据卷中:
[root@python-study ~]# docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu \
> bash -c 'cd /dbdata && tar xvf /backup/backup.tar --strip 1'
dbdata/file1.txt
- 进入新容器进行检查
[root@python-study ~]# docker exec -it dbstore2 ls /dbdata
file1.txt
5. 删除volumes
删除容器后,Docker数据卷仍然存在。
- 删除命名卷:需要在删除容器时,指示Docker Engine将其删除
- 命名卷:可以使用
docker volume
管理命令删除
##此命令创建一个匿名/foo卷。删除容器后,Docker Engine会删除该/foo卷,但不会删除该awesome卷。
docker run --rm -v /foo -v awesome:/bar busybox top
- 删除所有卷
[root@python-study ~]# docker volume prune
二. 使用 bind mounts
自Docker诞生以来,bind mounts就已经存在。与volumes相比,bind mounts安装的功能有限。使用bind mounts时,会将主机上的文件或目录安装到容器中。
- -v或者–volume:由三个字段组成,以冒号(:)分隔
- 第一个字段是主机上文件或目录的路径
- 第二个字段是文件或目录在容器中的安装路径。
- 第三个字段是可选的,并且是用逗号分隔的选项,诸如列表ro,consistent,delegated,cached,z,和Z。
##主机上如果不存在目录,会自动创建目录
$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app \
nginx:latest
- –mount:包含多个键值对,以逗号分隔,每个键值对都由一个元组组成。
<key>=<value>
- type:其值可以是bind,volume,tmpfs;
- source: 主机上文件或者目录的路径;
- destination:容器中的文件或目录的路径,也可以是dst,target;
- readonly:只读形式
- bind-propagation:绑定传播,可以是rprivate(默认), private,rshared,shared,rslave,slave;
$ docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
nginx:latest
注意:如果容器中的目录为非空目录,则会被主机目录中的内容覆盖。
- 原文作者:老鱼干🦈
- 原文链接://www.tinyfish.top:80/post/Docker%E5%AE%B9%E5%99%A8%E6%8A%80%E6%9C%AF/3.-docker%E7%BD%91%E7%BB%9C%E5%8F%8A%E6%95%B0%E6%8D%AE%E6%8C%81%E4%B9%85%E5%8C%96/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。