Docker 存储与卷管理深度解析
1. 主机日志访问与共享存储卷备份
从主机系统访问
http://localhost:5000
并进行 POST 操作后,会生成日志。这些日志可在主机系统的
/home/serverlogs
目录中访问,该目录映射到 Docker 容器内的
/var/log/nginx
。操作步骤如下:
$ cd serverlogs/
$ ls
access.log error.log
$ cat access.log
172.17.42.1 - - [20/Jan/2017:14:57:41 +0000] "GET / HTTP/1.1" 200 612 "-"
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101
Firefox/50.0" "-"
Docker 卷插件允许挂载共享存储后端,其主要优势在于,当主机出现故障时,由于数据由共享存储支持,用户不会遭受数据丢失。在传统方法中,迁移容器时卷不会随之迁移,但借助外部 Docker 卷插件(如 Flocker 和 Convoy),可以实现卷的可移植性,便于跨主机迁移容器及其卷,同时保护数据,因为数据不依赖于主机文件系统。
2. Flocker 卷插件
Flocker 广泛用于运行需要持久存储的容器化有状态服务和应用程序。Docker 仅提供基本的卷管理视图,而 Flocker 通过提供卷的持久性、故障转移和高可用性来增强这一功能。它既可以与 Docker Swarm 和 Compose 手动部署,也可以借助 CloudFormation 模板在 AWS 上轻松设置。
2.1 在 AWS 上部署 Flocker 的步骤
- 登录 AWS 账户,在 Amazon EC2 中创建密钥对。
- 从 AWS 主页选择 CloudFormation。
-
使用以下链接,借助 AWS S3 存储中的模板启动 Flocker 云形成堆栈:
https://s3.amazonaws.com/installer.downloads.clusterhq.com/flocker-cluster.cloudformation.json - 选择创建堆栈,然后选择第二个选项并指定 Amazon S3 模板 URL。
-
在下一个屏幕上,为账户指定堆栈名称、
AmazonAccessKeyID和AmazonSecretAccessKey。 - 提供键值对来标记此 Flocker 堆栈,并在需要时为此堆栈提供 IAM 角色。
- 查看详细信息并启动 Flocker 云形成堆栈。
-
堆栈部署完成后,从输出选项卡获取客户端节点和控制节点的 IP 地址。使用 Flocker 堆栈部署开始时生成的键值对通过 SSH 登录到客户端节点。设置以下参数:
bash $ export FLOCKER_CERTS_PATH=/etc/flocker $ export FLOCKER_USER=user1 $ export FLOCKER_CONTROL_SERVICE=<ControlNodeIP> # 不是 ClientNodeIP! $ export DOCKER_TLS_VERIFY=1 $ export DOCKER_HOST=tcp://<ControlNodeIP>:2376 $ flockerctl status # 应列出两个正在运行的服务器(节点) $ flockerctl ls # 此时应无数据集显示 $ docker info |grep Nodes # 应输出 "Nodes: 2"
如果
flockerctl status
和
flockerctl ls
命令成功运行,则表明 Docker Swarm 和 Flocker 已在 AWS 上成功设置。
2.2 Flocker 卷的使用
可以轻松设置 Flocker 卷,并创建一个在容器或容器主机生命周期之外仍能持久存在的容器:
$ docker run --volume-driver flocker -v flocker-volume:/cont-dir --name=testing-container
这样会创建并挂载一个外部存储块,容器目录将与之绑定。即使容器被删除或主机崩溃,数据仍能得到安全保护。可以在第二个主机上使用相同命令启动替代容器,并访问共享存储。
2.3 本地测试 Flocker
考虑一个包含两个 Docker Swarm 节点和一个 Flocker 客户端节点的用例。在 Flocker 客户端节点上:
1. 创建
docker-compose.yml
文件,定义
redis
和
clusterhq/flask
容器,并提供相应的 Docker 镜像、名称、端口和数据卷配置:
yaml
web:
image: clusterhq/flask
links:
- "redis:redis"
ports:
- "80:80"
redis:
image: redis:latest
ports:
- "6379:6379"
volumes: ["/data"]
2. 创建
flocker-deploy.yml
文件,定义将部署在同一节点(node - 1)上的两个容器,暂时将 Swarm 集群中的 node - 2 留空:
yaml
"version": 1
"nodes":
"node-1": ["web", "redis"]
"node-2": []
3. 使用上述
.yml
文件部署容器,只需运行以下命令:
bash
$ flocker-deploy control-service flocker-deploy.yml docker-compose.yml
部署完成后,可在
http://node - 1
上访问应用程序,它将显示网页的访问计数。
若要将容器迁移到 node - 2,需重新创建部署文件:
"version": 1
"nodes":
"node-1": ["web"]
"node-2": ["redis"]
然后运行以下命令进行迁移:
$ flocker-deploy control-service flocker-deploy-alt.yml docker-compose.yml
迁移完成后,SSH 到 node - 2 并列出正在运行的 Redis 容器,访问
http://node2
,可以看到计数仍然保留,并且每次访问时会递增。
3. Convoy Docker 卷插件
Convoy 是另一个广泛用于提供存储后端的 Docker 卷插件,用 Go 语言编写,其主要优点是可以独立部署。Convoy 作为 Docker 卷扩展运行,类似于中间容器。其初始实现利用 Linux 设备,为卷提供以下四种 Docker 存储功能:
- 精简配置卷
- 跨主机恢复卷
- 对卷进行快照
- 将卷备份到外部对象存储(如 Amazon EBS、虚拟文件系统(VFS)和网络文件系统(NFS))
3.1 使用 Convoy 卷插件的步骤
- 验证 Docker 版本是否高于 1.8。
-
本地下载插件 tar 文件并提取:
bash $ wget https://github.com/rancher/convoy/releases/download/v0.5.0/convoy.tar.gz $ tar xvf convoy.tar.gz convoy/ convoy/convoy-pdata_tools convoy/convoy convoy/SHA1SUMS $ sudo cp convoy/convoy convoy/convoy-pdata_tools /usr/local/bin/ $ sudo mkdir -p /etc/docker/plugins/ $ sudo bash -c 'echo "unix:///var/run/convoy/convoy.sock" > /etc/docker/plugins/convoy.spec' -
使用文件支持的循环设备作为伪设备,使文件可作为块设备访问,以演示 Convoy 设备映射器驱动程序:
bash $ truncate -s 100G data.vol $ truncate -s 1G metadata.vol $ sudo losetup /dev/loop5 data.vol $ sudo losetup /dev/loop6 metadata.vol -
设置好数据和元数据设备后,启动 Convoy 插件守护进程:
bash sudo convoy daemon --drivers devicemapper --driver-opts dm.datadev=/dev/loop5 --driver-opts dm.metadatadev=/dev/loop6 -
在另一个终端实例中,创建一个使用 Convoy 卷
test_volume并挂载到容器内/sample目录的 busybox Docker 容器:
bash $ sudo docker run -it -v test_volume:/sample --volume-driver=convoy busybox -
在挂载目录中创建示例文件:
bash / # cd sample/ / # cat > test testing /sample # exit -
使用 Convoy 作为卷驱动程序启动另一个容器,并挂载相同的 Convoy 卷:
bash $ sudo docker run -it -v test_volume:/sample --volume-driver=convoy --name=new-container busybox -
在新容器中查看之前创建的文件:
bash / # cd sample/ /sample # ls lost+found test /sample # exit
Convoy 可用于持久数据,如 WordPress 的 MySQL 数据库:
$ docker run --name wordpressdb --volume-driver=convoy -v test_volume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=wordpress -d mysql:5.7
$ docker run -e WORDPRESS_DB_PASSWORD=password -d --name wordpress --link wordpressdb:mysql wordpress
4. Docker 存储驱动程序性能
Docker 支持多种文件系统,如 aufs、btrfs、devicemapper、vfs、zfs 和 overlayfs。可插拔的存储驱动程序架构和灵活的卷挂载方式是容器化环境和生产用例的最佳选择。
4.1 UFS 基础知识
Docker 使用 UFS 实现只读分层方法,将多个层组合成单个镜像。UFS 递归地将多个目录合并为单个虚拟视图,其基本需求是有一个只读文件系统和一个可写覆盖层,通过写时复制(copy - on - write)实现文件系统的读写访问错觉。UFS 操作的是目录而非驱动器,底层文件系统无关紧要,它可以组合来自不同底层文件系统的目录。
4.2 UFS 术语
- 分支(Branches) :UFS 中合并的文件系统,可具有不同的访问权限(如只读、读写等)。UFS 是可堆叠的文件系统,分支还可以分配优先级,决定对文件系统执行操作的顺序。
- 复制向上(Copy - up) :将文件复制到可写层以更新文件的现象。当尝试删除文件时,由于需要从下到上删除所有副本,可能会在只读层出现错误。在这种情况下,文件从可写层删除,但仍存在于下面的只读层中。
4.3 UFS 存在的问题
- 底层文件系统支持 :UFS 需要在源代码中添加对底层文件系统的支持,尽管底层文件系统本身不会改变,但 UFS 必须为每个文件系统添加支持。
-
空白文件(Whiteouts)
:删除文件后创建的空白文件会污染文件系统命名空间,降低
rmdir性能。 - 复制向上的缺点 :首次更新时性能会降低,因为需要将完整的文件和目录层次结构复制到可写层,并且需要决定目录复制的时间,有两种选择(更新时复制整个目录层次结构或在打开目录时复制),各有优缺点。
4.4 AuFS
AuFS 是另一种 UFS,它从 UFS 文件系统派生而来,受到开发者的关注,目前在功能上领先于 UFS。AuFS 支持 UFS 的所有功能,在 Ubuntu 上使用 AuFS 命令需要安装
aufs - tools
包,更多信息可在 AuFS 手册页中找到。
4.5 Device Mapper
Device Mapper 是 Linux 内核组件,用于将物理块设备映射到虚拟块设备,这些映射设备可作为逻辑卷使用。它维护一个表来定义设备映射,表中包含起始位置、长度、映射类型和映射参数等信息。
Docker 使用 Device Mapper 的精简配置和快照功能,允许在同一数据卷上存储多个虚拟设备。使用两个单独的设备分别存储数据和元数据,Docker 创建一个大的块设备并在其上创建一个薄池,然后创建一个基础块设备,每个镜像和容器都是该基础设备的快照。
4.6 BTRFS
BTRFS 是一种有潜力取代当前默认 Linux 文件系统(EXT3/EXT4)的文件系统,它是一种写时复制(CoW)文件系统,每次更新数据时都会创建新副本,因此需要更多的存储空间,并且存在碎片化问题。
BTRFS 的主要设计目标是开发一种适用于各种用例和工作负载的通用文件系统,它支持快照、克隆和 RAID(级别 0、1、5、6、10)。其布局由 B - 树表示,类似于 B - 树森林,并且具有复杂的空间回收机制和垃圾回收器,使用引用计数回收未使用的磁盘空间,同时使用校验和确保数据完整性。
可以通过在
dockerd
命令行中传递
--storage - driver
选项或在
/etc/default/docker
文件中设置
DOCKER_OPTS
选项来选择存储驱动程序:
$ dockerd --storage-driver=devicemapper &
4.7 性能分析
使用微基准测试工具(如 fio)对 Docker 的
commit
、
build
、
rm
和
rmi
命令在不同文件系统上的性能进行分析。测试结果表明,AuFS 和 BTRFS 在 Docker 命令中表现出色,但 BTRFS 容器进行大量小写入时,会导致 BTRFS 块使用效率低下,最终可能导致 Docker 主机空间不足,并且由于 BTRFS 的日志记录技术,顺序写入性能会受到影响,可能会使性能减半。因此,使用 BTRFS 存储驱动程序时需要密切监控 BTRFS 文件系统的可用空间。
Docker 存储与卷管理深度解析
5. 存储驱动性能对比
为了更直观地了解不同存储驱动在 Docker 中的性能表现,下面通过表格形式对之前提到的几种主要存储驱动(AuFS、BTRFS、Device Mapper)在不同 Docker 命令下的性能进行对比:
| 存储驱动 | commit 命令 | build 命令 | rm 命令 | rmi 命令 | 其他特点 |
| — | — | — | — | — | — |
| AuFS | 表现良好 | 表现良好 | - | - | 从 UFS 派生,功能领先,操作目录,支持写时复制 |
| BTRFS | 表现良好 | 表现良好 | - | - | 写时复制文件系统,支持快照、克隆、RAID,有空间回收机制,但大量小写入可能导致空间不足,顺序写入性能受影响 |
| Device Mapper | - | - | - | - | 利用 Linux 内核组件,支持精简配置和快照,使用数据和元数据设备 |
以下是一个 mermaid 流程图,展示不同存储驱动在 Docker 操作中的选择逻辑:
graph LR
A[选择存储驱动] --> B{是否需要写时复制特性}
B -- 是 --> C{是否对空间使用和顺序写入性能要求高}
C -- 是 --> D[选择 AuFS]
C -- 否 --> E[选择 BTRFS]
B -- 否 --> F{是否需要精简配置和快照功能}
F -- 是 --> G[选择 Device Mapper]
F -- 否 --> H[根据其他需求选择 vfs、zfs 等]
6. 不同场景下的存储驱动选择建议
根据不同的应用场景和需求,合理选择 Docker 存储驱动至关重要。以下是一些具体的场景及对应的存储驱动选择建议:
-
开发和测试环境
-
特点
:对性能要求相对较低,更注重快速部署和灵活性。
-
建议
:可以选择 AuFS 或 vfs。AuFS 功能丰富,易于使用;vfs 简单直接,适合快速搭建测试环境。
-
生产环境 - 大量小文件读写
-
特点
:需要高效的文件读写性能,对数据的持久性和可靠性要求高。
-
建议
:优先考虑 AuFS,它在处理大量小文件时表现出色,且具有较好的兼容性。
-
生产环境 - 数据备份和恢复需求高
-
特点
:需要支持快照和克隆功能,以便快速备份和恢复数据。
-
建议
:BTRFS 是不错的选择,它原生支持快照和克隆,能够满足数据备份和恢复的需求。
-
生产环境 - 对存储资源管理要求高
-
特点
:需要对存储资源进行精细管理,如精简配置和动态分配。
-
建议
:Device Mapper 提供了强大的存储资源管理功能,适合这种场景。
7. 总结与最佳实践
通过对 Docker 存储驱动和卷管理的深入探讨,我们可以总结出以下最佳实践:
-
卷管理方面
-
选择合适的卷插件
:根据实际需求选择 Flocker 或 Convoy 等卷插件。如果需要在 AWS 等云环境中实现容器和卷的迁移,Flocker 是一个不错的选择;如果希望独立部署并实现卷的共享,Convoy 更合适。
-
数据持久化
:对于重要的数据,如数据库,使用支持持久化的卷插件,确保数据在容器或主机故障时不会丢失。
-
存储驱动选择方面
-
评估应用需求
:在选择存储驱动之前,充分评估应用的读写模式、数据量、性能要求等因素。
-
监控和优化
:使用 BTRFS 存储驱动时,密切监控文件系统的可用空间,避免出现空间不足的问题。定期对存储系统进行性能测试和优化,确保 Docker 环境的稳定运行。
8. 未来展望
随着 Docker 技术的不断发展,存储驱动和卷管理也将不断演进。未来可能会出现更高效、更灵活的存储驱动,以满足日益增长的容器化应用需求。例如,可能会有新的文件系统被集成到 Docker 中,提供更好的性能和功能。同时,卷插件的功能也将不断增强,实现更便捷的跨云、跨数据中心的容器和卷迁移。
总之,深入了解 Docker 的存储驱动和卷管理知识,选择合适的技术方案,并不断关注行业的发展动态,将有助于我们更好地构建和管理容器化应用。
超级会员免费看
861

被折叠的 条评论
为什么被折叠?



