企业运维容器之 docker 数据卷

Posted 123坤

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了企业运维容器之 docker 数据卷相关的知识,希望对你有一定的参考价值。

1. Docker 数据卷管理

  • 为什么要用数据卷
    docker 分层文件系统:性能差、生命周期与容器相同
    docker 数据卷:mount到主机中,绕开分层文件系统;和主机磁盘性能相同,容器删除后依然保留;仅限本地磁盘,不能随容器迁移
  • docker 提供了两种卷:
    bind mount
    docker managed volume
  1. bind mount
    是将主机上的目录或文件 mount 到容器里;使用起来直观高效,易于理解;
    使用 -v 选项指定路径,格式 < host path>:< container path>
    bind mount 默认权限是读写rw,可以在挂载时指定为只读ro;
    -v 选项指定的路径,如果不存在,挂载时会自动创建。
[root@server2 ~]# docker run -it --rm -v /data1:/data1 -v /data2:/data2:ro busybox
/ # ls
bin    data2  etc    proc   sys    usr
data1  dev    home   root   tmp    var
/ # cd data1/
/data1 # touch zxkfile
/data1 # cd ..
/ # cd data2/
/data2 # touch zxkfile111
touch: zxkfile111: Read-only file system
/data2 # 
[root@server2 ~]# cd /data1/
[root@server2 data1]# ls
zxkfile
[root@server2 data1]# cd /data2/
[root@server2 data2]# ls
  1. docker managed volume
    bind mount 必须指定 host 文件系统路径,限制了移植性;
    docker managed volume 不需要指定 mount 源,docker 自动为容器创建数据卷目录;
    默认创建的数据卷目录都在 /var/lib/docker/volumes 中。
    如果挂载时指向容器内已有的目录,原有数据会被复制到volume中。
[root@server2 ~]# docker volume create website
website
[root@server2 ~]# docker volume  ls
DRIVER              VOLUME NAME
local               website
[root@server2 ~]# docker volume inspect website 
[
    {
        "CreatedAt": "2021-05-29T10:42:33+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/website/_data",
        "Name": "website",
        "Options": {},
        "Scope": "local"
    }
]
[root@server2 ~]# docker run -d --name demo -v website:/usr/share/nginx/html nginx
c4f8a6668323f110954f9d01adc6f55d0ebdaa3b2cc5fdace9a25e2a20122e22
[root@server2 ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
c4f8a6668323        nginx               "/docker-entrypoint.…"   25 seconds ago      Up 25 seconds       80/tcp              demo
[root@server2 ~]# cd /var/lib/docker/volumes/website/_data
[root@server2 _data]# ls		##会将容器中的数据挂载到目录上
50x.html  index.html
[root@server2 _data]# echo www.westos.org > index.html 
[root@server2 _data]# curl 172.17.0.2	##访问运行容器分配到的IP 
www.westos.org
[root@server2 _data]# docker inspect demo

        "Mounts": [
            {
                "Type": "volume",
                "Name": "website",
                "Source": "/var/lib/docker/volumes/website/_data",
                "Destination": "/usr/share/nginx/html",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }

bind mount与docker managed volume对比
相同点:两者都是 host 文件系统中的某个路径。
不同点:

在这里插入图片描述
可以在挂载时将 bind mountdocker managed volume 结合起来;

[root@server2 _data]#  docker run -d --name demo -v website:/usr/share/nginx/html:ro nginx
230ae47cb89d33be3444600f09f1f6f1348e0fcea2376f04a23135fa9200248f

此时的:ro是容器内的权限。

2. 卷插件简介

docker 卷默认使用的是 local 类型的驱动,只能存在宿主机,跨主机的volume就需要使用第三方的驱动,可以查看以下链接:
https://docs.docker.com/engine/extend/legacy_plugins/#volume-plugins
docker官方只提供了卷插件的 api,开发者可以根据实际需求定制卷插件驱动。
https://docs.docker.com/engine/extend/plugins_volume/#volume-plugin-protocol

Docker Plugin 是以 Web Service 的服务运行在每一台 Docker Host上的,通过HTTP协议传输RPC风格的JSON数据完成通信;
Plugin 的启动和停止,并不归Docker管理,Docker Daemon依靠在缺省路径下查找Unix Socket文件,自动发现可用的插件;
当客户端与Daemon交互,使用插件创建数据卷时,Daemon会在后端找到插件对应的 socket 文件,建立连接并发起相应的API请求,最终结合Daemon自身的处理完成客户端的请求。

3. convoy卷插件

  • convoy 卷插件实现
    支持三种运行方式:devicemapper、NFS、EBS。
    以下实验使用nfs方式。
    下载软件:https://github.com/rancher/convoy/releases/download/v0.5.0/ convoy.tar.gz
    在所有节点提前挂载NFS存储。

在第一台主机上安装 NFS 存储,然后将其共享;

[root@server1 ~]# yum install -y nfs-utils.x86_64 
[root@server1 ~]# mkdir /mnt/nfs
[root@server1 ~]# ll -d /mnt/nfs
drwxr-xr-x 2 root root 6 May 29 11:27 /mnt/nfs
[root@server1 ~]# chmod 777 /mnt/nfs
[root@server1 ~]# vim /etc/exports
[root@server1 ~]# cat /etc/exports	##不转换 root 用户身份
/mnt/nfs	*(rw,no_root_squash)
[root@server1 ~]# systemctl start nfs
[root@server1 ~]# showmount -e
Export list for server1:
/mnt/nfs *

在第二台主机上将共享的进行挂载;然后挂载之后写入文件,看其是否挂载完整;

[root@server2 ~]# docker volume rm website 
website
[root@server2 ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@server2 ~]# docker volume prune 		##清除不用的卷
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B
[root@server2 ~]# yum install nfs-utils.x86_64 -y
[root@server2 ~]# mkdir /mnt/nfs
[root@server2 ~]# mount 172.25.15.1:/mnt/nfs/ /mnt/nfs/
[root@server2 ~]# df
Filesystem            1K-blocks    Used Available Use% Mounted on
/dev/mapper/rhel-root  17811456 1796500  16014956  11% /
devtmpfs                1011444       0   1011444   0% /dev
tmpfs                   1023468       0   1023468   0% /dev/shm
tmpfs                   1023468   16988   1006480   2% /run
tmpfs                   1023468       0   1023468   0% /sys/fs/cgroup
/dev/vda1               1038336  135088    903248  14% /boot
tmpfs                    204696       0    204696   0% /run/user/0
172.25.15.1:/mnt/nfs   17811456 5452288  12359168  31% /mnt/nfs
[root@server2 ~]# cd /mnt/nfs/
[root@server2 nfs]# touch file1
[root@server2 nfs]# touch zxkfile1
[root@server2 nfs]# ll
total 0
-rw-r--r-- 1 root root 0 May 29 11:30 file1
-rw-r--r-- 1 root root 0 May 29 11:30 zxkfile1

在第一台主机上查看写入的内容,说明挂载没有问题;

[root@server1 ~]# cd /mnt/nfs/
[root@server1 nfs]# ls
file1  zxkfile1
[root@server1 nfs]# ll
total 0
-rw-r--r-- 1 root root 0 May 29 11:30 file1
-rw-r--r-- 1 root root 0 May 29 11:30 zxkfile1
  • convoy卷插件安装:
    可以从官网下载,此处直接将已经下载好的包来解压;
[root@server1 ~]# tar zxf convoy.tar.gz
[root@server1 ~]# ls
base-debian10.tar  convoy  convoy.tar.gz  docker  harbor  harbor-offline-installer-v1.10.1.tgz  rhel7.tar
[root@server1 ~]# cd convoy/
[root@server1 convoy]# ls
convoy  convoy-pdata_tools  SHA1SUMS
[root@server1 convoy]# cp convoy* /usr/local/bin/
	##将二进制程序复制到系统环境中
[root@server1 convoy]# mkdir -p /etc/docker/plugins/
 ##创建插件目录
[root@server1 convoy]# convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs &
[root@server1 convoy]# ps ax

26180 pts/0    Sl     0:00 convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs

[root@server1 convoy]# cd /var/run/convoy/
[root@server1 convoy]# ls	##会有一个sock 文件,
convoy.sock
[root@server1 convoy]# echo "unix:var/run/convoy/convoy.sock" > /etc/docker/plugins/convoy.spec
	##创建默认扫描文件。命名规则为卷名称加.spec
[root@server1 convoy]# cat /etc/docker/plugins/convoy.spec
unix:var/run/convoy/convoy.sock
[root@server1 convoy]# docker volume ls 	
##此时查看时会看到新建的卷信息
DEBU[0348] Handle plugin activate: POST /Plugin.Activate  pkg=daemon
DEBU[0348] Response:  {
	"Implements": [
		"VolumeDriver"
	]
}  pkg=daemon
DEBU[0348] Handle plugin list volume: POST /VolumeDriver.List  pkg=daemon
DEBU[0348] Successfully got volume list for docker.      pkg=daemon
DEBU[0348] Response:  {}                                 pkg=daemon
DRIVER              VOLUME NAME
local               7c342c18f10f6dbd21b2a4b5cc3247524a34b7c121619b5d5f18c575195ae305
local               16e4cf77380b6e44a1d303aff980c9a5fa2c92f370d6a06502a9804130e79419
local               880e08098df4d779af609547d7a6566f024959308f68b14e5a2c97eba94ecf3e
local               5448e97b5787e41257959201c8fd2e9fd29b872006e81425a8d319012629c935
local               ac6099385cca02031765fc2592c7a4fcbb63e502aaa76017b753d8da02737348
local               bafd00a8486bde75e887c2c2b60fee74b2f841d00f76829714f26f98606b93c7
local               ced83e3b56c21f1e868a747a30f9f3080a4f23b25a49953c31ceae3e59ea9b78
local               dbf67c39bc5c2f0be328650845a00b61a436f6bad71e58d1ff98a33074f66b16
local               fa34e96e88bbfd3d373f011b006bb2c94640ec7347a3e3038814705273bf94e3
local               ff365d32c54fe53501d2e147e2f5583be699d631f12df758fa7dd7e9e15ad79c

创建卷
在第一台主机上创建卷;

[root@server1 convoy]# convoy create vol1
DEBU[0409] Calling: POST, /volumes/create, request: POST, /v1/volumes/create  pkg=daemon
DEBU[0409]                                               event=create object=volume opts=map[PrepareForVM:false Size:0 BackupURL: VolumeName:vol1 VolumeDriverID: VolumeType: VolumeIOPS:0] pkg=daemon reason=prepare volume=vol1
DEBU[0409] Created volume                                event=create object=volume pkg=daemon reason=complete volume=vol1
DEBU[0409] Response:  vol1                               pkg=daemon
vol1

[root@server1 convoy]# convoy list
{
	"vol1": {
		"Name": "vol1",
		"Driver": "vfs",
		"MountPoint": "",
		"CreatedTime": "Sat May 29 11:42:23 +0800 2021",
		"DriverInfo": {
			"Driver": "vfs",
			"MountPoint": "",
			"Path": "/mnt/nfs/vol1",
			"PrepareForVM": "false",
			"Size": "0",
			"VolumeCreatedAt": "Sat May 29 11:42:23 +0800 2021",
			"VolumeName": "vol1"
		},
		"Snapshots": {}
	}
}
[root@server1 convoy]# docker volume ls 
##再次查看时会有
convoy              vol1

使用卷
在第二台主机上使用卷;

[root@server2 ~]# cd /etc/docker/
[root@server2 docker]# ls
certs.d  daemon.json  key.json  plugins
[root@server2 docker]# cd plugins
[root@server2 plugins]# ls
convoy.spec
[root@server2 plugins]# cat convoy.spec
unix:var/run/convoy/convoy.sock
[root@server2 plugins]# cd /usr/local/bin/
[root@server2 bin]# ls
convoy  convoy-pdata_tools
[root@server2 nfs]# convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs &
[root@server2 nfs]# ps ax

 5849 pts/0    Sl     0:00 convoy daemon --drivers vfs --driver-opts vf

[root@server2 nfs]# convoy list
{
	"vol1": {
		"Name": "vol1",
		"Driver": "vfs",
		"MountPoint": "",
		"CreatedTime": "Sat May 29 11:42:23 +0800 2021",
		"DriverInfo": {
			"Driver": "vfs",
			"MountPoint": "",
			"Path": "/mnt/nfs/vol1",
			"PrepareForVM": "false",
			"Size": "0",
			"VolumeCreatedAt": "Sat May 29 11:42:23 +0800 2021",
			"VolumeName": "vol1"
		},
		"Snapshots": {}
	}
}
[root@server2 ~]# cd /mnt/nfs/
[root@server2 nfs]# ls
config  vol1		

在 vol1 卷中写入数据,会自动存储到物理主机中;

[root@server1 docker]# docker run -it --rm -v vol1:/data busybox

/ # cd /data/
/data # ls
/data # touch file
/data # touch zxkfile

[root@server1 docker]# cd /mnt/nfs/vol1/
[root@server1 vol1]# ls
file  zxkfile

在第二台主机上用相同的指令,来运行容器,会看到数据;基础的逻辑还是 nfs 系统;

[root@server2 ~]# docker run -it --rm -v vol1:/data busybox

/ # cd /data/
/data # ls
file     zxkfile
/data # 

当在一个结点回收卷时,所有结点都会回收;

[root@server2 ~]# convoy delete vol1
DEBU[0446] Calling: DELETE, /volumes/, request: DELETE, /v1/volumes/  pkg=daemon
DEBU[0446]                                               event=delete object=volume pkg=daemon reason=prepare volume=vol1
DEBU[0446] Cleaning up /mnt/nfs/vol1 for volume vol1     pkg=vfs
DEBU[0446]                                               event=delete object=volume pkg=daemon reason=complete volume=vol1
[root@server2 ~]# convoy list
{}
[root@server1 ~]# convoy list
{}

当不需要插件信息时,删除过程如下:

[root@server2 ~]# cd /etc/docker/plugins/
[root@server2 plugins]# ls
convoy.spec
[root@server2 plugins]# rm -f convoy.spec
[root@server2 plugins]# ls
[root@server2 ~]# ps ax

[root@server2 ~]# kill 5849	##结束进程
[root@server2 ~]# systemctl restart docker
	##此时在重启时会非常慢,可以删除数据再次启动就快了
[root@server2 ~]# cd /var/lib/docker/volumes/
[root@server2 volumes]# ls
metadata.db
[root@server2 volumes]# rm -f metadata.db
[root@server2 volumes]# systemctl restart docker
##删除之后此时再次启动就快了

对于第一台主机上的删除,此时也可以需要同样的操作来结束进程。

4. 总结

对于 docker 数据卷的管理,以及第三方的卷插件的使用进行了学习,以下为一些常用的命令:

  • convoy卷插件子命令;
  • convoy list 列出卷;
  • convoy delete 删除卷;
  • convoy snapshot create 创建快照;
  • convoy snapshot delete 删除快照;
  • convoy backup create 创建备份;
  • convoy create res1 --backup < url> 还原备份

以上是关于企业运维容器之 docker 数据卷的主要内容,如果未能解决你的问题,请参考以下文章

Linux企业运维——Docker数据卷

企业运维容器之 docker 网络

企业运维容器之 docker 安全

企业运维容器之 docker仓库

企业运维容器之 docker 三剑客swarm

企业运维容器之 docker 镜像