Docker Volume学习笔记

发布时间 2023-08-18 16:48:55作者: Chinor

Docker存储

默认情况下, docker的文件存储在可写的容器层, 这可能会有以下问题

  • 如果容器被删了, 那么数据也会随着容器一起被删除
  • 写入到容器文件系统需要存储驱动的中间层, 这个抽象的中间层会影响容器文件系统的性能

docker通过两种方式把文件持久化存储: volumebind mounts
volume方式即把文件持久化存储在由docker管理的宿主机文件系统中(linux默认存储在/var/lib/docker/volumes), 非docker的进程不应该修改该文件系统. Volume是docker中持久化数据的最佳方式. 通过docker volume create volume_name 创建. 一个volume可以同时挂载到多个容器中.
Bind mounts: 把宿主机的任意目录或者文件直接挂载到容器中去, 宿主机上非docker的进程和容器可以同时使用挂载的文件系统.

如果挂载宿主机的目录到容器的指定路径上时(bind mounts), 容器已经存在该目录/文件, 那么容器上原来的文件会被屏蔽. 例如容器原来有/etc/nginx/conf.d/目录, 该目录下包含默认的配置文件default.conf, 如果把宿主机上空的conf.d目录挂载到容器里, 容器里原来的/etc/nginx/conf.d/default.conf 就会变得不再可见. 这种方式适用于覆盖默认配置文件, 写入自己的数据
如果使用volume方式挂载, 容器中挂载目录下的内容会写到docker volume中, 然后volume再挂载到容器中. 这种方式可以用来持久化容器中数据

Volumes

volumes的方式持久化就以下好处:

  • 便于备份和迁移
  • 可以用docker命令行或者docker api管理
  • linux和Windows下都可用
  • 更安全地在多个容器共享文件
  • 存储驱动可以挂载远程主机的磁盘或者云服务的磁盘
  • 容器中的文件可以填充到磁盘中, 这点与bind mount相反. bind mount的时候, 容器中的目录会被屏蔽
  • docker desktop环境下, volumes比bind mount性能更高.

挂载磁盘一般会使用-v/--volume 和 --mount参数. 如果需要指定磁盘驱动, 那就使用--mount参数

-v / --volume, 包含三个字段, 用冒号分隔开.
第一部分是volume的名称或者宿主机的本地路径,
第二部分是容器中的路径
第三部分是用逗号隔开的挂载选项, 例如ro使用只读方式挂载

--mount 参数包含多个键值对, 用逗号隔开
type: 可以是bind, volume或者tmpfs
source/src: 挂载源, 磁盘名称或者路径
destination/dst/target: 挂载到的容器的路径
readonly/ro: 以只读方式挂载到容器中
volume-opt: 接收键值对参数, 指定磁盘的挂载选项, 可以使用多次

如果volume驱动接收逗号分割的列表作为参数. 参考如下方式在双引号中使用单引号

docker service create \
    --mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"'
    --name myservice \
    <IMAGE>

使用service的时候, 只支持使用--mount, 不支持使用-v

使用volume,在命令行启动容器

docker run -d \
  --name devtest \
  --mount source=myvol2,target=/app \
  nginx:latest

在docker compose中使用volume

services:
  frontend:
    image: node:lts
    volumes:
      - myapp:/home/node/app
volumes:
  myapp:
    external: true
    # external 表示docker compose中使用docker volume create创建的磁盘, docker compose中不再额外创建磁盘.

在swarm service中使用volume

docker service create -d \
  --replicas=4 \
  --name devtest-service \
  --mount source=myvol2,target=/app \
  nginx:latest

volume驱动

使用volume驱动可以在多个节点的多个容器上使用同一份文件. 例如同时挂载nfs / s3文件等.
以下的例子使用ssh挂载文件

# 由于docker目录已经迁移到/data/docker目录, 创建软链接, 否则安装失败
ln -s /data/docker /var/lib/docker
# 安装docker volume驱动
docker plugin install --grant-all-permissions vieux/sshfs DEBUG=1

# 使用volume ssh驱动创建一个volume
docker volume create --driver vieux/sshfs \
  -o sshcmd=chino@localhost:/home/chino/volumetest \
  -o password=xxxxxxxxxx \
  localsshvolume
# 创建的volume挂载到容器中
docker run -d -v localsshvolume:/app nginx:latest

# 使用--mount创建磁盘
docker run -d \
  --name sshfs-container \
  --volume-driver vieux/sshfs \
  --mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
  nginx:latest

volume的备份

在volume已经挂载到容器中时, 可以再新建一个容器, 把改磁盘和备份目录挂载过去, 在新的容器中执行备份, 参考以下命令

docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

volume 删除

volume分为两种, 一种是有名字的, 一种是没名字的. 有命令的磁盘可以使用docker volume rm 删除.
匿名磁盘挂载的时候加上--rm参数. 在下面的容器退出的时候. 下面的例子中, /foo 磁盘可以在容器退出被删除的时候自动删除, awesome磁盘会保留

docker run --rm -v /foo -v awesome:/bar busybox top

删除所有未使用的磁盘
docker volume prune

tmpfs

在linux环境中, 可以再容器中使用tmpfs文件系统, 在容器停止时, tmpfs也会被删除
tmpfs的限制

  • tmpfs无法在多个容器间同时使用
  • 只能在linux中的docker使用
  • tmpfs的权限在容器启动时会失效(重置为755)

使用--tmpfs或者--mount来启用tmpfs, 区别是--tmpfs无法指定任何选项, 并且无法在swarm中使用

在容器中使用tmpfs

docker run -d \
  -it \
  --name tmptest \
  --mount type=tmpfs,destination=/app \
  nginx:latest


docker run -d \
  -it \
  --name tmptest \
  --tmpfs /app \
  nginx:latest

在启动的容器中可以看到/app使用了tmpfs

root@554cde5ab19f:/# df -hl /app
Filesystem      Size  Used Avail Use% Mounted on
tmpfs            32G     0   32G   0% /app

使用参数设置tmpfs的大小

docker run -d \
  -it \
  --name tmptest \
  --mount type=tmpfs,destination=/app,tmpfs-mode=1770,tmpfs-size=10g \
  nginx:latest