docker(三)数据卷和持久化数据

容器数据存储简介

默认情况下,在运行中的容器里创建的文件,被保存在一个可写的容器层:

  • 如果容器被删除了,那么容器里面的数据也没有了。
  • 这个可写的容器层和特定的容器层绑定的,也就是当前容器的数据和其他容器不能共享。

如果希望自己的容器数据保留下来(持久化),则需要将数据存储在数据卷上。数据卷和容器是解耦的,从而可以独立创建并管理数据卷,即使关联容器被删除了,数据卷不会被删除。

docker主要提供了两种方式做数据的持久化

  • Data Volume(数据卷),由docker管理,它存在宿主机上的,linux是/var/lib/docker/volumes目录下,windows是在C:\ProgramData\Docker\windowsfilter下,它是持久化数据最好的方式。
  • Bind Mount(磁盘)由用户指定存储在宿主机的具体目录上。

容器和镜像的底层关系

  • 容器其实是一个运行中的镜像
  • 实质是复制image并在image的最上面加一层可读可写的层,(称之为container layer,容器层)
  • 基于同一个image可以创建多个container
  • 如果没有设置数据卷,那么默认数据是保存在container layer中,如果容器删除这其中的数据也跟着删除了,这就是为什么数据要做持久化的原因。
    在这里插入图片描述

数据持久化(Data Volume方式)

这是采用数据卷的方式,也是系统推荐的。在使用的时候,即可以先创建数据卷,也可以直接启动容器,容器会自动创建数据卷。同时支持配置多数据卷。

  • 先创建数据卷方式:
    docker volume create [volume_name]

  • 启动容器时创建:
    -v [数据卷名称]:[容器中的目录]

# 以启动redis容器为例
docker run -itd --name=redis -v redis-data:/data -v redis-conf:/etc/redis -p 6379:6379 -e LANG=C.UTF-8 redis:latest
  • 查看数据卷的列表
docker volume ls

在这里插入图片描述

  • 查看数据卷的详情
    docker volume inspect redis-data
docker volume inspect redis-data

在这里插入图片描述

数据持久化(Bind Mount方式)

格式:-v [宿主机上的目录]:[容器目录]
注意:容器运行时需要可读可写目录权限,—privileged=true

这是我们需要在宿主机上创建目录,然后将目录和容器的目录进行绑定就行,同时支持配置多数据卷
假如安装mongodb时,就在宿主机目录下分别创建数据目录/data/docker-mongo/data 和 配置文件目录/data/docker-mongo/config,启动容器时可以这样子来操作:

docker run -it --name=mongo -v /data/docker-mongo/data:/data/db -v /data/docker-mongo/config:/data/configdb --restart=always --privileged=true -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=123456 -d mongo --auth

查看数据卷是否挂载成功:

docker inspect mongo

在这里插入图片描述

数据卷容器

数据卷容器是一个专门用来挂载数据卷的容器,该容器作用主要是来共享数据的,即供其他容器使用。所谓的数据卷容器,实际上就是一个普通的容器,它提前建立了和宿主机的目录映射,其他容器来引用它。

使用场景

  1. 方便容器数据来做备份,恢复,迁移。
  2. 如果你有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。
  3. 多个容器挂载同一个数据卷(缺点:操作比较麻烦,因为当容器过多时,需要一个个的挂载。

特性

数据卷中的数据并不能继承于镜像,也不在联合文件系统临时层所管理的范围内,所以镜像层面的写时复制不会作用于数据卷中的数据,而这些数据也不会被docker commit提交到新的镜像中。

  • 文件的操作不是在沙盒环境中进行的,而是直接作用于宿主机内真实的硬盘I/O中;
  • 生命周期不受容器控制(即使数据容器删除了,数据卷也还在),能够安全有效的存储文件到数据卷中;
  • 数据卷独立于容器之外,可以实现多个容器共享一个数据卷。
    如下图所示:
    在这里插入图片描述

创建数据卷的姿势

docker run --volumes-from [容器名称] -d [镜像名称]

举例1共享nginx容器

1. 创建nginx数据容器卷:
以ubuntu为镜像的数据镜像,并在容器里面创建/usr/share/nginx/html的目录,作为后面nginx容器 共享目录。

docker run -itd -v /usr/share/nginx/html/ --name mydata ubuntu:latest

在这里插入图片描述
在Portainer的数据卷管理里面可以看到数据卷容器,就存在宿主机的/var/lib/docker/volumes
在这里插入图片描述
2. 引用容器
此时再创建两个nginx容器,nginx1和nginx2,同时数据卷引用mydata容器。

docker run -itd --volumes-from mydata -p 80:80 --name=nginx1 --restart=always --privileged=true nginx:latest
docker run -itd --volumes-from mydata -p 81:80 --name=nginx2 --restart=always --privileged=true nginx:latest

这时三个容器内,都有了usr/share/nginx/html目录。任意一个修改了该目录下的文件,其他两个容器都会同步。通过查看nginx1,nginx2的容器详情就会发现其数据卷挂载的位置都是相同的,都是挂载在/usr/lib/docker/volumes/.../_data目录下。
在这里插入图片描述
3. 删除数据容器的影响
下面测试是删除数据容器mydata后,两个nginx容器是否受到影响

docker container stop mydata

docker container rm mydata

如下图,从portainer的数据卷明细中看到,nginx1,nginx2的容器都还是绑定原来的目录,并没有被删除。说明数据容器对应的/usr/share/nginx/html目录绑定的是在/var/lib/volumes,所以mydata数据容器删除,并不影响数据卷。
在这里插入图片描述

举例2忘记mongodb的密码

通过将原来的容器作为数据容器,以无免密启动临时容器,来修改密码

  1. 停止原有容器
docker container stop mongo
  1. 启动临时容器,将原有容器作为数据卷,并免密登录
# 参数--rm表示临时容器,等容器停止后自动删除
docker run -it --name mongo-repair --rm --volumes-from mongo mongo:6.0.8 --noauth
  1. 进入新容器,修改密码
# 另开一个终端
docker exec -it mongo-repair mongosh --port 27017

# 进入admin数据库
use admin
db.updateUser("admin",{pwd:"123456"})

# 退出数据库
exit
  1. 停止新容器
# 停止容器后自动删除
docker container stop mongo-repair
  1. 启动原来容器
docker container start mongo

数据的备份和恢复

利用数据卷容器可以实现数据的备份和恢复。

备份

  • 格式:
    docker run --volumes-from [待备份容器] -v $(pwd):/backup --name=[临时容器名] [镜像] tar -cvf /backup/backup.tar [容器数据卷]
  • 命令解释:
  1. 首先使用–volume-from连接 待备份容器。
  2. 创建临时容器,来作为备份的数据容器
  3. -v参数用来将宿主机当前目录挂载到容器的/backup目录下。
  4. 接下来将容器中的/usr/share/nginx/html目录下的的内容,使用tar命令压缩生成到/backup/backup.tar文件中去,由于已经设置将宿主机当前目录映射到容器的/backup目录,所以容器/backup下的tar文件在当前目录能马上看到

例子,以容器nginx1为例子

docker run --volumes-from nginx1 -v $(pwd):/backup --name=nginx1-copy nginx:latest \ 
tar -cvf /backup/backup.tar /usr/share/nginx/html

在这里插入图片描述

恢复

数据恢复前先准备一个存放恢复数据的容器,需要挂载一个数据卷,这样子方便给外部容器连接

docker run -itd -P -v /usr/share/nginx/html/ --name nginx3 nginx:latest

在这里插入图片描述
再准备一个临时容器,用来恢复数据用

恢复命令格式:docker run --volumes-from [新建的容器] -v 存放备份目录:/当前容器数据目录 [镜像] tar xvf [备份的压缩包路径]

docker run --volumes-from nginx3 -v $(pwd):/backup nginx tar xvf /backup/backup.tar

在这里插入图片描述

1, 首先还是使用–volumes-from参数连接上备份容器,即第一步创建出来的nginx3
2. 然后将当前目录映射到容器的/backup目录下
3. 然后执行解压操作,将backup.tar文件解压。解压文件位置描述是一个容器内的地址,但是该地址已经映射到宿主机中的当前目录了,因此这里要解压缩的文件实际上就是宿主机当前目录下的文件。

多主机之间的容器数据共享

docker的数据卷支持多种driver,默认都是和宿主机绑定在一起,也就是在本地的。

$ docker volume inspect redis-data

[
    {
        "CreatedAt": "2023-09-04T17:24:08+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/redis-data/_data",
        "Name": "redis-data",
        "Options": null,
        "Scope": "local"
    }
]

如果想要多个远程主机实现数据共享,我们需要用到sshfs驱动。以下是我在mac上安装3个ubuntu虚拟机,来进行测试。有了OrbStack,安装虚拟机也就很方便。
在这里插入图片描述
下面是使用远程文件共享的架构图
在这里插入图片描述

环境准备

远程主机的ssh服务和端口需要开启

准备在orbstack安装好的3台ubuntu虚拟机,在虚拟机里已经装好了docker环境,我们通过sshfs将ubuntu1和ubuntu2的数据卷关联到ubuntu3上宿主目录上。

hostnameipssh_userssh_password
ubuntu1198.19.249.150allen.huang123456
ubuntu2198.19.249.19allen.huang123456
ubuntu3198.19.249.171allen.huang123456

安装sshfs插件

在ubuntu1和ubuntu2上都安装

docker plugin install --grant-all-permissions vieux/sshfs

查看插件

docker plugin ls

ID             NAME                 DESCRIPTION               ENABLED
ca79b48ec4d0   vieux/sshfs:latest   sshFS plugin for Docker   true

通过sshfs创建数据卷

格式:
docker volume create --driver vieux/sshfs
-o sshcmd=[用户名]@远程机器IP:远程机器的目录
-o password=[密码] [数据卷名称]

示例:
在ubuntu1上创建数据卷,以下以非root账号运行,所以带上sudo

sudo docker volume create --driver vieux/sshfs -o sshcmd=allen.huang@198.19.249.171:/home/allen.huang -o password=123456 ssh_volume1

查看数据卷列表

$ sudo docker volume ls

DRIVER               VOLUME NAME
vieux/sshfs:latest   ssh_volume1

查看数据卷详情

$ sudo docker inspect ssh_volume1

[
    {
        "CreatedAt": "0001-01-01T00:00:00Z",
        "Driver": "vieux/sshfs:latest",
        "Labels": null,
        "Mountpoint": "/mnt/volumes/bd8ecd8c4fc7cea8ca46542864096b18",
        "Name": "ssh_volume1",
        "Options": {
            "password": "123456",
            "sshcmd": "allen.huang@198.19.249.171:/home/allen.huang"
        },
        "Scope": "local"
    }
]

创建容器挂载volume

创建容器,挂载ssh_volume1到/data目录,然后进入容器的shell,在/data中创建一个text.txt文件,写入一些内容

allen.huang@ubuntu1:~$ sudo docker run -it --name=busybox -v ssh_volume1:/data busybox sh
/ # LS
sh: LS: not found
/ # ls
bin    data   dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # cd data
/data # ls
/data # echo 'test ssh volume' > test.txt
/data # cat test.txt
test ssh volume
/data #
/data #

在查看ubuntu3查看文件test.txt文件也已经存在,这说明已经同步成功
在这里插入图片描述
同时在ubuntu2上像ubuntu1上的方式创建数据卷,并创建容器挂载数据

sudo docker run -it --name=busybox -v ssh_volume:/data busybox sh

/ # ls
bin    data   dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # cd data
/data # echo 'test2' > test.txt
/data # ls
test.txt
/data # cat test.txt
test ssh volume
/data # echo "sync unbuntu2 data" >> test.txt
/data # cat test.txt
test ssh volume
sync unbuntu2 data

这时数据同步到ubuntu1和ubuntu3上了看效果:
ubuntu3:
在这里插入图片描述
ubuntu1:
在这里插入图片描述

结语

容器中的数据存储算是比较重要的内容,本人水平有限,也只能分享到这里,如有问题请指点。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值