Docker Volume学习笔记
Docker存储
默认情况下, docker的文件存储在可写的容器层, 这可能会有以下问题
- 如果容器被删了, 那么数据也会随着容器一起被删除
- 写入到容器文件系统需要存储驱动的中间层, 这个抽象的中间层会影响容器文件系统的性能
docker通过两种方式把文件持久化存储: volume
和bind 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