首页 > 其他分享 >四.docker持久化存储

四.docker持久化存储

时间:2022-11-20 15:59:30浏览次数:81  
标签:容器 存储 持久 volume nginx docker data 目录

四、docker持久化存储

Docker的镜像是只读的,但是容器是可写的,我们可以将数据写入到容器,不过一旦容器删除数据就会丢失,所以要将数据实现持久化存储。

默认情况下,容器(container)内部新创建文件或者修改文件结果会保存在容器的可读可写层中,这意味着:

1.当容器消失时,与容器一体的可读写层也一起消失,数据并没有持久化。并且,当一个容器需要其它容器中可读写层数据的时候,取出操作非常困难。

2.容器的可读写层与宿主机的文件系统紧密结合,很难将它从一台宿主机迁移到其他宿主机。

3.写入容器的可写层需要 存储驱动程序来管理文件系统。存储驱动程序提供了一个联合文件系统,使用 Linux 内核。与使用直接写入主机文件系统的数据卷相比,这种额外的抽象会降低性能 。

为什么容器需要持久化存储:

容器按照业务类型分为无状态的(数据不需要被格式化)、有状态的(数据需要被格式化)。

显然,容器更擅长无状态应用。因为未持久化数据的容器根目录的生命周期和容器的生命周期一样,容器文件系统的本质就是在镜像层上面创建的可读写层,运行中的容器对任何文件的修改都存在于该读写层,当容器被删除时,容器中的读写层也会随之消失。

虽然容器希望所有的业务都尽量保持无状态,这样容器就可以开箱即用,并且可以任意调度,但实际业务总是有各种需要数据持久化的场景,比如mysql、kafka等有状态的业务,因此为了解决有状态业务的需求,Docker提出了卷(Volume)的概念。

卷的本质是文件或目录,他可以绕过默认的联合文件系统,直接以文件的形式存在于宿主机上。卷的概念不仅解决了数据持久化的问题,还解决了容器间共享数据的问题。使用卷可以将容器内的目录或文件持久化,当容器重启后不会丢失。

在docker中实现数据持久化有两种方式:Bind mount和Docker Manger Volume。

  • Bind mount数据持久化的方式,如果是挂载本地的一个目录,则容器内对应的目录下的内容会被本地的目录覆盖掉,而Docker Manager Volme这种方式则不会,不管使用哪种方式的持久化,在容器被销毁后,本地的数据都不会丢失。
  • 使用“-v”选项挂载时,Bind mount 明确指定了要挂载宿主机(docker host)的某个目录到容器中,而Docker Manager Volume则只指定了要对容器的某个目录进行挂载,而挂载的是docker host本地的哪个目录,则是由docker来管理的。

数据持久化的特点:

  • Data Volume是目录或文件,不能是没有格式化的磁盘(块设备)。
  • 若要挂载一个文件到容器中,那么该文件必须是已经存在,否则会被当成一个目录挂载到容器中。
  • 默认挂载到容器内的文件或目录,容器是有读写权限。可以在运行容器时-v指定完挂载目录后面加“:ro”限制容器的写入权限。例如:
[root@bogon ~]# mkdir /123
docker run -dit --name ubuntu001 -v /123:/123:ro ubuntu:16.04
这样的话容器只能读宿主目录的文件。不能进行写文件
  • volume数据可以永久保存,即使使用它的容器已经被销毁。

1、数据卷容器:

Bind mount-----数据卷容器:-volumes-from方式实现数据持久化

举例:有A、B、C三个容器,其中A作为数据卷容器,挂载了本地的/www/web01和/www/web02这两个目录到容器内的/usr/share/nginx/html/和/data这两个目录。

我们基于busybox镜像作数据卷容器

[root@bogon ~]# docker run -dit --name data -v /www/web01:/usr/share/nginx/html -v /www/web02:/data busybox

运行两个Nginx容器并指定数据卷容器

 docker run -d --name web01 --volumes-from data -P nginx
docker run -d --name web02 --volumes-from data -P nginx

通过docker inspect 容器名称来查看容器的挂载信息。

1.查看数据卷容器data的mount信息:
docker inspect data
"Mounts": [
            {
                "Type": "bind",
                "Source": "/www/web01",
                "Destination": "/usr/share/nginx/html",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",
                "Source": "/www/web02",
                "Destination": "/data",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
2.查看web01的mount信息
dockerinspect web01
 "Mounts": [
            {
                "Type": "bind",
                "Source": "/www/web01",
                "Destination": "/usr/share/nginx/html",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",
                "Source": "/www/web02",
                "Destination": "/data",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
3、同理web02和web01也是一样的

不难发现,采用数据卷容器这种方式可以让多个容器挂载相同的目录,让实现数据持久化的目录保持一致。
数据容器卷的使用场景:

  • 多个容器需要实现数据持久化的目录是一致的,可以采用这种方式。
  • 解决指定多目录使用-v选项的错误几率。一般单个使用就可以直接-v使用。
 docker run -dit -v 宿主机目录:容器内目录 -P  nginx

总结:
1、随便挑选一个镜像运行一个容器作为数据卷的容器,挂载到本地目录到容器内的目录,不用管宿主机和容器的目录是否存在,docker会自动创建相应的目录。

2、之后无论运行多少容器,都可以使用-volumes-from选项来指定一个运行的容器进行数据持久化。

3、实现的效果为:挂载数据卷容器实现数据持久化的容器,会自动将数据卷容器挂载的本地目录挂载到该容器本身(本身的挂载点与数据卷容器的挂载点自动保持一致),也仅仅只会挂载数据卷容器实现了数据持久化的目录到自己本身,而不是数据卷容器的全部目录。

2.Docker Manager Volume实现数据持久化

运行容器时,-v选项指定一个路径,则就是容器内的目录,也就是Docker Manager Volume 方式。

[root@bogon ~]# docker run -tid -v /usr/share/nginx/html -P --name web03 nginx

查看容器的mount信息

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

可以看到挂载的是一个本地的一个目录(/var/lib/docker/volumes/a56b854405b8268a20e50393dc33f20c0ce7aa6c9c1a1ae38c44a62037d054a9/_data)。这个目录就是挂载的/usr/share/nginx/html的目录。

3、Docker卷的操作

Docker提供了卷(Volume)的功能,使用docker Volume命令可以实现对卷的创建、查看和删除等操作。下面我们来详细了解一下这些命令!

图片

(1)创建一个名为myvolume数据卷

[root@localhost ~]# docker volume create myvolume
myvolume

默认情况下,docker创建的数据卷为local模式,仅能提供本主机的容器访问,如果想要实现远程访问,需要借助网络存储来实现。Docker的local存储模式并未提供配额管理,所以在生产环境中需要手动维护磁盘的空间。
其他方法:

除了使用docker volume create的方式创建卷,我们还可以在docker启动时使用-v的方式指定容器内需要被持久化的路径,Docker会自动为我们创建卷,并且绑定到容器中,使用命令如下:

docker run -d --name=nginx-volume -v /usr/share/nginx/html nginx
使用以上命令,我们启动了一个nginx容器,-v参数使得Docker自动生成一个卷并且绑定到容器的
/usr/share/nginx/ht目录中。

使用docker volume ls命令查看主机上的卷:

[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     a56b854405b8268a20e50393dc33f20c0ce7aa6c9c1a1ae38c44a62037d054a9

可以看到Docker自动为我们创建了一个名称为随机ID的卷。

(2)查看数据卷

已经创建的数据卷可以使用docker volume ls命名查看。

docker volume ls
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     myvolume

如果想查看某个数据卷的详细信息,可以使用以下命令:

docker volume inspect 数据卷名
例如我想查看myvolume的详细信息,命令如下:
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     a56b854405b8268a20e50393dc33f20c0ce7aa6c9c1a1ae38c44a62037d054a9
local     myvolume
[root@localhost ~]# docker volume inspect myvolume
[
    {
        "CreatedAt": "2022-04-11T22:33:45+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/myvolume/_data",
        "Name": "myvolume",
        "Options": {},
        "Scope": "local"
    }
]

通过docker volume inspect命令可以看到卷的创建日期、命令、挂载路径信息。

(3)使用数据卷

使用docker volume创建的卷在容器启动时,添加--mount参数指定卷的名称即可使用!

使用myvolume来启动一个nginx容器,并将/usr/share/nginx/html目录与卷关联,命令如下:

 docker run -d --name nginx --mount source=myvolume,target=/usr/share/nginx/html nginx

使用docker的卷可以实现指定目录的文件持久化,下面我们进入容器中并且修改index.html文件内容,命令如下:

[root@localhost ~]# docker exec -it nginx /bin/bash
root@07d9708e756d:/# cat <<EOF >/usr/share/nginx/html/index.html
hello,Docker Volume!
EOF
ctrl+p+q退出容器

此时我们使用docker rm命令将运行中的nginx容器彻底删除

docker rm -f nginx

旧的nginx容器删除后,我们再使用docker run命令启动一个新的容器,并且挂载到myvolume卷:

docker run -d --name=nginx --mount source=myvolume,target=/usr/share/nginx/html nginx

新容器启动后,我们进入容器查看一下index.html

[root@localhost ~]# docker exec -it nginx /bin/bash
root@b3d289858889:/# cat /usr/share/nginx/html/index.html
hello,Docker Volume!

可以看到此时的index.html文件内容依旧为我们之前写入的内容。可见,使用Docker卷后我们的数据并没有随着容器的删除而消失。

(4)删除数据卷

容器的删除并不会自动删除已经创建的数据卷,因此不在使用的数据卷需要我们手动去删除,删除的命令为docker volume rm。例如删除上面的myvolume数据卷:

注意:正在被使用中的数据卷无法删除,如果你想删除正在使用中的数据卷,需要先删除所有关联的容器。

[root@localhost ~]#docker rm -f nginx
[root@localhost ~]#docker volume rm myvolume
myvolume

(5)容器与容器之间数据共享

有时候,两个容器之间会有共享数据的需求,很典型的一个场景就是容器内产生的日志需要一个专门的日志采集程序去采集日志的内容,例如我需要使用Filebeat(一种日志采集工具)采集nginx容器内的日志,我就需要使用卷来共享一个日志目录,从而使得Filebeat和nginx容器都可以访问到这个目录,这就需要用到容器之间共享数据卷的方式。

那如何实现容器与容器之间的数据共享?下面进行举例说明!

首先使用docker volume create命令创建一个共享日志的数据卷。

docker volume create log-volume

启动一个生产日志的容器(用log-server窗口表示)

 docker run -dit --mount source=log-volume,target=/tmp/log --name=log-server busybox

然后再启动一个(用log-clinet表示):

docker run -dit --name log-clinet --volumes-from log-server  busybox

进入log-server容器,使用以下命令创建一个 mylog.log 文件并写入 "Hello,My log." 的内容:

[root@localhost ~]# docker exec -it log-server sh
/ # cat <<EOF >/tmp/log/mylog.log
Hello, My log.
EOF
exit

进入log-clinet容器,查看相关内容:

[root@localhost ~]# docker exec -it log-clinet sh
/ # cat /tmp/log/mylog.log
Hello,My log.

总结一下:我们首先使用docker volume create命令创建了log-volume卷来作为共享目录,log-server容器向该卷写入数据,log-clinet容器从该卷读取数据。这就像主机上的两个进程,一个向主机目录写数据,一个从主机目录读取数据,利用主机的目录,实现了容器之间的数据共享。

(6)主机与容器之间的数据共享

Docker卷的目录默认在/var/lib/docker下,当我们想要把主机的其他目录映射到容器内时,就需要用到主机与容器之间数据共享的方式了,例如我想把Mysql容的/var/lib/mysql目录映射到主机的/var/lib/mysql目录中,我们就可以使用主机与容器之间数据共享的方式去实现。要实现与容器之间的数据共享其实很简单,只需要我们在启动容器的时候添加-v参数即可。格式为:-v HOST_PATH:CONTIANAER_PATH.也就是-v 宿主机目录:容器内的目录。

例如我想挂载容器的/usr/local/data到主机的/data目录中,可以使用以下命令:

docker run -v /data:/usr/local/data -it busybox

容器启动后,便可以在容器内的/usr/local/data访问到主机/data目录的内容了,并且容器重启后,/data目录下的数据不会丢失。

4、Docker卷的实现原理

在了解Docker卷的原理前,我们先来回顾下容器和镜像的文件系统原理。

镜像和容器的文件系统原理:镜像是由多层文件系统组成的,当我们想要启动一个容器时,Docker会在镜像上层创建一个可读写层,容器中的文件都工作在这个读写层中,当容器删除的时候,与容器相关的工作文件将都会消失。

Docker容器的文件系统不是一个真正的文件系统,而是通过联合文件系统实现的一个伪文件系统,而Docker卷则是直接利用主机的某个文件或者目录,他可以绕过联合文件系统,直接挂载到主机上的文件或目录到容器中,这就是Docker卷的工作原理。

下面,我们通过一个实例来说明卷的工作原理。首先,我们创建一个名称为volume-data的卷:

[root@localhost ~]# docker volume create volume-data
volume-data

我们使用ls命令查看一下/var/docker/volumes目录下的内容:

[root@localhost ~]# ls -l /var/lib/docker/volumes/
drwx-----x. 3 root root    19 4月  12 15:05 volume-data

然后我们查看volume-data下有什么内容:

[root@localhost ~]# ls -l /var/lib/docker/volumes/volume-data/
总用量 0
drwxr-xr-x. 2 root root 6 4月  12 15:05 _data

可以看到我们创建的卷出现在了/var/lib/docker/volumes目录下,并且volume-data目录下创建一个_data目录。实际上在我们创建Docker卷时,Docker会把卷的数据全部放在/var/lib/docker/volumes下,并且在每个对应的卷目录下创建一个_data目录,然后把_data目录绑定到容器中。因此我们在容器中挂载卷的目录下操作文件,实际上是在操作主机上的_data目录。为了证明这个说法进行如下实验:
首先,我们先启动一个容器,并且绑定volume-data卷到容器内的/data目录下:

docker run -it --mount source=volume-data,target=/data busybox

我们进入到容器的/data目录,创建一个data.log文件:

/ # cd /data
/data # touch data.log
ctrl+p+q

然后我们查看主机上的内容:

[root@localhost ~]# ls -l /var/lib/docker/volumes/volume-data/_data/
总用量 0
-rw-r--r--. 1 root root 0 4月  12 15:26 data.log

可以看到主机上的_data目录下也出现了data.log文件。这说明了在容器内操作卷挂载的目录就只直接操作主机上的_data目录。符合之前说的。
综上:Docker卷的实现原理是在主机的/var/lib/docker/volumes目录下,根据卷的名称创建相应的目录,然后在每个卷的目录下创建_data目录,在容器启动时如果使用--mount参数,Docker会把主机上的目录直接映射到容器的指定目录下,实现数据持久化。

标签:容器,存储,持久,volume,nginx,docker,data,目录
From: https://www.cnblogs.com/wtdata123/p/16908655.html

相关文章

  • 一.docker介绍(1)
    一、docker介绍容器是一种基础工具,指任何可以用于容纳其他物品的工具。而docker是一个开源的应用容器引擎。docker公司位于旧金山,原名叫dotcloud,底层使用了Linux容......
  • 二.docker基础命令
    二、Docker基础命令:2.1dockersearchdockersearch镜像名:版本号。用来去dockehub搜索一个镜像。搜索mysql镜像:dockersearchmysqlNAME         ......
  • 定制jekins-slave-jnlp镜像封装docker和kebectl命令实现pipline
    基于官方:jenkins/inbound-agent:latestDockerHub成品:dockerpullsvipghy/jenkins-jnlp-slave:v1Dockerfile[root@node-1/root/jenkins]k8s-node#catDockerfile......
  • 存储容量
    存储容量的定义\(存储容量=存储字数\times字长\)存储字数表示存储器的地址空间大小,字长表示一次存取操作的数据量。主存容量的扩展位扩展法扩展字长,字扩展法扩展存储字......
  • docker使用
    例子:dockerrun-d--namegame-p8080:80game2048映射到系统的8080端口 ​​http://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/​​ yumi......
  • Docker发布.net6.0项目
     1、创建一个项目,并且添加docker支持(我这边是用了一个以前就创建好的项目)如下图,添加docker支持,选择linux,添加后会自动生成一个Dockerfile文件(这个文件是构建docker镜......
  • 根据docker镜像反推dockerfile
    Dockerfile是一个文本文件,其中包含我们为了构建Docker镜像而手动执行的所有命令。Docker可以从Dockerfile中读取指令来自动构建镜像。我们可以使用dockerbuild命......
  • Android 数据存储方案
    Android数据存储方案利用文件进行存取数据写入文件数据openFileOutput是Context中提供的一个方法,用于将数据存储到指定的文件中,第一个参数是文件名,第二个参数是文件......
  • 将x年或x年x月或x年x月x日等字符串转化成日期类型存储到数据库
    //将年月日字符串转换成具体的年月日publicstaticDateStringToDate(StringdateStr){if(StringUtils.isEmpty(dateStr)){thrownewSel......
  • Windows11 Docker镜像存储路径更改(非C盘路径)
    https://blog.csdn.net/Ber_Bai/article/details/120816638?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v......