Docker 数据持久化方案详解

-
-
2024-03-12

Docker 数据持久化方案详解

Docker数据持久化概述

联合文件系统

了解联合文件系统后,我们知道,镜像是只读的,类似共享文件形式让多个容器使用。如果要在容器里修改文件,即镜像里的文件,那该如何修改?

为了解决这个问题,docker 引入了 写时复制(copy-on-write),需要修改文件操作时,会先从镜像里把要写的文件复制到自己的文件系统中进行修改。

默认情况下,Docker容器内部新创建文件或者修改文件,结果会保存在容器的可读写层中,因此:

(1)当container消失时,与container一体的可读写层也一并消失,数据并未持久化。当一个container需要其它container中可读写层的数据时,读取操作非常困难。

(2)container可读写层与宿主机的文件系统紧密结合,很难进行迁移。

(3)写入数据到container可读写层需要storage driver,与直接在宿主机文件系统中读写数据相比效率要低。

容器的数据卷


 什么是数据卷

Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据作为容器的一部分保存下来,那么当容器被删除之后,数据也就没了,为了能够保存数据,在docker容器中使用卷。

数据卷是经过特殊设计的目录,可以绕过联合文件系统(UFS),为一个或者多个容器提供访问,数据卷设计的目的,在于数据的永久存储,它完全独立于容器的生存周期,因此,docker 不会在容器删除时删除其挂载的数据卷,也不会存在类似的垃圾收集机制,对容器引用的数据卷进行处理,同一个数据卷可以只支持多个容器的访问。

网上关于数据卷的叫法确实比较混乱,本文中数据卷

数据卷特点

  • 数据卷可以在容器之间共享和重用
  • 可以对数据卷里的内容直接进行修改
  • 数据卷的变化不会影像镜像的更新。
  • 卷会一直存在,即使挂载数据卷的容器已经被删除
  • 使用docker commit生成新镜像不会把卷中的数据,写入新的容器镜像中

Docker提供三种方式将数据从宿主机挂载到容器

  • Volumes: Docker 管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式。
  • Bind mounts: 将宿主机的任意位置的文件或者目录挂载到容器中。
  • tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用tmps,同时避免写入容器可写层提高性能。

关于他们的区别如下图,可以参考docker - bind mount 和volumes的区别这篇文章

区别如下表所示

对比项bind mountvolume
Source位置用户指定/var/lib/docker/volumes/
Source为空覆盖dest为空保留dest内容
Source非空覆盖dest内容覆盖dest内容
Source种类文件或目录只能是目录
可移植性一般(自行维护)强(docker托管)
宿主直接访问容易(仅需chown)受限(需登陆root用户)*

基本命令

用户可以通过docker run--volume/-v--mount选项来创建带有数据卷的容器

--volume(-v)


参数--volume(或简写为-v)

示例:

docker run --name $CONTAINER_NAME -it 
-v $PWD/$CONTAINER_NAME/app:/app:rw \
-v $PWD/$CONTAINER_NAME/data:/data:ro \
avocado-cloud:latest /bin/bash

命令格式有三种,不同的命令格式,会有不同的挂载方式。

  • 使用bind mount 方式挂载
docker run -v 宿主机目录:容器目录[:OPTIONS]
#宿主机目录必须为绝对路径或者~/开头的目录 
#当宿主机目录不存在时会自动创建
#容器目录必须为绝对路径,没有也会自动创建
  • 使用匿名volume方式挂载
docker run -v 容器目录[:OPTIONS] 
# 容器目录必须为绝对路径,没有会自动创建
#此时会在/var/lib/docker/volumes/目录下创建匿名数据卷,卷名为随机数字,并挂载到容器目录上
  • 使用具名volme方式挂载
docker run -v 数据卷名:容器目录[:OPTIONS] 
# 数据卷名不存在时,会自动创建,存放在/var/lib/docker/volumes/目录下
#也可以提前使用docker volume create 数据卷名  提前创建后,在挂载到容器目录

 

--mount


参数--mount默认情况下用来挂载volume,但也可以用来创建bind mount和tmpfs。

如果不指定type选项,则默认为挂载volume,volume是一种更为灵活的数据管理方式,volume可以通过docker volume命令集被管理。示例:

docker run --name $CONTAINER_NAME -it \
--mount type=bind,source=$PWD/$CONTAINER_NAME/app,destination=/app \
--mount source=${CONTAINER_NAME}-data,destination=/data,readonly \
avocado-cloud:latest /bin/bash

--mount可以通过tpye选项指定参数,明确使用的挂载方式

  • 挂载volume命令格式:
docker run --mount [type=volume,]source=my-volume,destination=/path/in/container[,...]
  • 创建bind mount命令格式
docker run --mount type=bind,source=/path/on/host,destination=/path/in/container[,...]
#如果创建bind mount并指定source则必须是绝对路径,且路径必须已经存在

 Docker持久化方案

volume持久化方案

volume简介

volume是Docker官方推荐的持久化方案,默认情况下,volume的存储空间来自于宿主机文件系统中的某个目录,如/var/lib/docker/volumes/。

Volume 由 Docker 创建也由 Docker 管理。你可以使用命令 docker volume create 手动创建(显示创建),也可以在容器、服务创建时,自动创建(隐式创建) 。

一个特定的 volume 可以同时被挂载进多个容器。即使所有的容器都停了,volume 也不会被自动删除,对 Docker 来说仍然可用

Volume  docker系统外的程序无权限修改其中的数据

一个volume可以同时供多个container使用,如果没有container使用volume,其不会自动删除,用户需运行docker volume prune明确删除。

volume基本命令

 

[root@izoq008ryseuupz docker]# docker volume help

Usage:	docker volume COMMAND

Manage volumes

Commands:
  create      Create a volume
  inspect     Display detailed information on one or more volumes
  ls          List volumes
  prune       Remove all unused local volumes
  rm          Remove one or more volumes

Run 'docker volume COMMAND --help' for more information on a command.

volume特点

使用docker run -v 运行容器时,-v参数 如果以/或~/开头,则为bind mount ,否则 Docker 会将其当成某个volume名字挂载。

如果容器中的目录不存在,docker会自动创建目录;

如果容器中的目录已有内容,如果挂载的卷为空,则容器在初始化时,会把容器目录中的数据复制到卷中;如果挂载的卷不为空,宿主机上卷目录的内容覆盖容器目录的内容。

如果用户显式创建volume,则需要给其指定一个名称;

如果是隐式创建volume,Docker会自动为其分配一个在宿主机范围内唯一的名字。

命令的基本使用

 ### 管理卷
docker volume create nginx-vol # docker volume ls
docker volume inspect nginx-vol
## 用卷创建一个容器
docker run -d --name=nginx-test -v nginx-vol:/usr/share/nginx/html nginx
## 清理
docker stop nginx-test # docker rm nginx-test
docker volume rm nginx-vol
 
## 注意:如果没有指定卷,自动创建。

创建数据卷,启动容器使用 nginx-vol 这个数据卷

 [root@offline-client docker]# docker volume create nginx-vol
nginx-vol
[root@offline-client docker]# docker volume inspect nginx-vol
[
    {
        "CreatedAt": "2022-05-15T12:10:52+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/nginx-vol/_data",
        "Name": "nginx-vol",
        "Options": {},
        "Scope": "local"
    }
]
[root@offline-client ~]#  docker run -d --name=nginx-test -v nginx-vol:/usr/share/nginx/html nginx:1.17Unable to find image 'nginx:1.17' locally
[root@offline-client ~]# curl  172.17.0.2
hello world

创建容器并挂载数据卷

volume使用场景

通过使用第三方提供的volume driver,用户可以将数据持久到远程主机或者云存储中。

(1)多个容器间共享数据。

(2)宿主机不保证存在固定目录结构。

(3)持久化数据到远程主机或者云存储而非本地。

(4)需要备份、迁移、合并数据时。停止container,将volume整体复制,用于备份、迁移、合并等

2.3 Bind Mounts持久化方案


bind mount持久化方式将宿主机中的文件、目录挂载到容器上,相应文件、目录可以被宿主机读写,也可以被容器读写。

bind mount持久化方式可以将数据存储在宿主机器任何地方,但会依赖宿主机的目录结构,因此不能通过docker CLI直接管理(如docker volume ls 命令是查不到的),并且非Docker进程和Docker进程都可以修改。

2.3.1 bind mount特点

(1)性能最好

(2)Docker容器与宿主机耦合过于紧密,移植性较差。

2.3.2 bind mount使用场景

(1)container共享宿主机配置文件,如docker将宿主机文件/etc/resov.conf文件bind mount到容器上,两者会使用相同的DNS服务器。

(2)监控服务container化。读取宿主机固定文件中的数据实现监控。

2.3.3 常用命令

 #用卷创建一个容器:
docker run -d --name=nginx-test --mount type=bind,src=/app/wwwroot,dst=/usr/share/nginx/html nginx 
docker run -d --name=nginx-test -v /app/wwwroot:/usr/share/nginx/html nginx
# 验证绑定:
docker inspect nginx-test
# 清理:
docker stop nginx-test 
docker rm nginx-test

启动 nginx-test容器,挂载/app/wwwroot到/usr/share/nginx/html

 [root@offline-client ~]# docker run -d --name=nginx-test --mount type=bind,src=/app/wwwroot,dst=/usr/share/nginx/html nginx
13e5652a1b889d61021b9b726579646a00531fa2773068b1b7066ff60eff11f5
[root@offline-client ~]# ll  /app/wwwroot/
total 0
[root@offline-client ~]# echo hello world >  /app/wwwroot/index.html
[root@offline-client ~]# curl  172.17.0.2
hello world

将 根路径下wwwNginx路径mount到/usr/share/nginx/html,并输入 内容 ,然后访问

2.3.4 bind mount注意事项

(1)-v 宿主机目录路径必须以/或~/开头,否则docker会将其当成是volume 而不是bind mount。

(2)如果宿主机上的目录不存在,docker会自动创建目录(多级的绝对路径好像不行)。

(3)如果容器中的目录不存在,docker会自动创建目录。

(4)如果容器中目录已有内容,那么docker会使用宿主机上目录的内容覆盖容器目录的内容。

(5)如果宿主机目录中已有内容,那么

2.4 tmpfs mount持久化方案


2.4.1 tmpfs mount

tmpfs mount只在Linux主机内存中持久化,是临时性的。当容器停止,tmpfs mount会被移除,通常用于临时存放敏感文件。

tmpfs mounts 可选选项

Option

Description

tmpfs-size

挂载的tmpfs的字节数,默认不受限制

tmpfs-mode

tmpfs的文件模式,例如700或1700.默认值为1777,这意味着任何用户都有写入权限

使用--tmpfs参数无法指定任何其他的可选项,并且不能用于Swarm Service(集群节点服务)。

docker run -d -it --name tmptest --tmpfs /test busybox

2.4.2 tmpfs mount特点

(1)只能在Linux主机内存中,不会持久化到磁盘。

(2)不支持多容器间共享。

2.4.3 tmpfs mount使用场景

Docker可将用户名与密码等敏感数据保存在某个数据库中,当启动需要访问这些敏感数据的container或者service时,docker会在宿主机上创建一个tmpfs,然后将敏感数据从数据库读出写到tmpfs中,再将tmpfs mount到container中,安样能保证数据安全。当容器停止运行时,则相应的tmpfs也从系统中删除。


参考原文链接:Hello Docker(七)——Docker数据持久化_docker持久化目录_天山老妖的博客-CSDN博客

原文链接:Docker数据持久化_丰恒谷的博客-CSDN博客

“您的支持是我持续分享的动力”

微信收款码
微信
支付宝收款码
支付宝

目录