Docker数据存储

数据持久化

在这里插入图片描述

一、Storage Driver

数据存储
CentOS7版本的docker,Storage Driver为: Overlay2 backing filesystem: xfs。

正常情况下,只有很少量的数据被写入到容器最上层的写入层,并且通过volume 来写数据,然而我们也会遇到一些情况需要我们可以直接写入到容器的写入层,这我们就需要到了 storage driver 来帮忙。

Docker 使用一些列不同的 storage driver 来管理镜像层和容器层,这些storage driver 不同于前面说到的 volume。

一个镜像是有若干镜像层组成。

Dockerfile 中的每条指令都会生成一个镜像层,除了最上面的一层之外,其他的都是只读的。

最上一层主要是镜像运行时的一些命令。
每一层只是与它之前的层有一些不同,层层堆叠在一起。
创建容器的时候,只是在底层上添加一个新的可写层。这一层通常称为“容器层”。

Docker 支持多种 storage driver,有 AUFS、Device Mapper、Btrfs、OverlayFS、VFS 和 ZFS。它们都能实现分层的架构,同时又有各自的特性。对于 Docker 用户来说,具体选择使用哪个 storage driver 是一个难题,因为:

1.没有哪个 driver 能够适应所有的场景。
2.driver 本身在快速发展和迭代。

不过 Docker 官方给出了一个简单的答案:
优先使用 Linux 发行版默认的 storage driver。

Docker 安装时会根据当前系统的配置选择默认的 driver。默认 driver 具有最好的稳定性,因为默认 driver 在发行版上经过了严格的测试。

Ubuntu 用的 AUFS,底层文件系统是 extfs,各层数据存放在/var/lib/docker/aufs。

Redhat/CentOS 的默认 driver 是 Device Mapper,SUSE 则是 Btrfs。

对于某些容器,直接将数据放在由 storage driver 维护的层中是很好的选择,比如那些无状态的应用。无状态意味着容器没有需要持久化的数据,随时可以从镜像直接创建。

比如 busybox,它是一个工具箱,我们启动 busybox 是为了执行诸如wget,ping 之类的命令,不需要保存数据供以后使用,使用完直接退出,容器删除时存放在容器层中的工作数据也一起被删除,这没问题,下次再启动新容器即可。

但对于另一类应用这种方式就不合适了,它们有持久化数据的需求,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据,也就是说,这类容器是有状态的。

这就要用到 Docker 的另一种存储机制:Data Volume。

二、Data Volume

Data Volume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中。Data Volume 有以下特点:

1.Data Volume 是目录或文件,而非没有格式化的磁盘(块设备)。
2.容器可以读写 volume 中的数据。
3. volume 数据可以被永久的保存,即使使用它的容器已经销毁。

好,现在我们有数据层(镜像层和容器层)和 volume 都可以用来存放数据,具体使用的时候要怎样选择呢?考虑下面几个场景:

Database 软件 vs Database 数据
Web 应用 vs 应用产生的日志
数据分析软件 vs input/output 数据
Apache Server vs 静态 HTML 文件

相信大家会做出这样的选择:
前者放在数据层中。因为这部分内容是无状态的,应该作为镜像的一部
分。
后者放在 Data Volume 中。这是需要持久化的数据,并且应该与镜像分开
存放。

还有个大家可能会关心的问题:如何设置 volume 的容量?
因为 volume 实际上是 docker host 文件系统的一部分,所以 volume 的容量取决于文件系统当前未使用的空间,目前还没有方法设置 volume 的容量。

1、Bind mount

持久化存储:本质上是DockerHost文件系统中的目录或文件,能够直接被Mount到容器的文件系统中。在运行容器时,可以通过-v 实现。

小实验:
运行一个nginx服务,做数据持久化。

[root@docker01 ~]# mkdir html
[root@docker01 ~]# cd html/
[root@docker01 ~]# vim index.html
添加:
This is a testfile in dockerHost.
[root@docker01 ~]# docker run -itd --name testweb -v /root/html/:/usr/share/nginx/html -p 80 nginx:latest
[root@docker01 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
a9bf2a40ee4a        nginx:latest        "/docker-entrypoint.…"   2 minutes ago       Up 2 minutes        0.0.0.0:32768->80/tcp   testweb
[root@docker01 ~]# curl 172.17.0.1:32768
This is a testfile in dockerHost.

PS: DockerHost上需要被挂着的源文件或目录,必须是已经存在,否则,
当做的一个目录挂着到容器中。

host 中的修改确实生效了,bind mount 可以让 host 与容器共享数据。这在管理上是非常方便的。

即使容器没有了,bind mount 也还在。这也合理,bind mount 是 host文件系统中的数据,只是借给容器用用,哪能随便就删了啊。

默认挂载到容器内的文件,容器是有读写权限。可以在运行容器是-v后边加“:ro” 限制容器的写入权限。

//限制容器对挂载目录或文件只读权限。

[root@docker01 ~]# docker run -itd --name testweb2 -p 80 -v /tmp/html:/usr/share/nginx/html:ro nginx

并且还可以挂载单独的文件到容器内部,一般它的使用场景是:如果不想对整个目录进行覆盖,而只希望添加某个文件,就可以使用挂载单个文件。

//挂载单个文件。

[root@docker01 ~]# docker run -itd --name testweb3 -p 80 -v /tmp/html/index.html:/usr/share/nginx/html/index.html:ro nginx

mount point 有很多应用场景,比如我们可以将源代码目录 mount 到容器中,在 host 中修改代码就能看到应用的实时效果。再比如将 mysql 容器的数据放在 bind mount 里,这样 host 可以方便地备份和迁移数据。

bind mount 的使用直观高效,易于理解,但它也有不足的地方:bindmount 需要指定 host 文件系统的特定路径,这就限制了容器的可移植性,当需要将容器迁移到其他 host,而该 host 没有要 mount 的数据或者数据不在相同的路径时,操作会失败。

2、Docker Manager Volume

docker managed volume 与 bind mount 在使用上的最大区别是不需要指定 mount 源,指明 mount point 就行了。

[root@docker01 ~]# docker run -itd --name t1 -P -v /usr/share/nginx/html nginx:latest

我们通过 -v 告诉 docker 需要一个 data volume,并将其 mount 到/usr/share/nginx/html。那么这个 data volume 具体在哪儿呢?

这个答案可以在容器的配置信息中找到,执行 docker inspect 命令:

[root@docker01 ~]# docker inspect t1

每当容器申请 mount docker manged volume 时,docker 都会在/var/lib/docker/volumes 下生成一个目录(例子中是"/var/lib/docker/volumes/f4a0a1018968f47960efe760829e3c5738c702
533d29911b01df9f18babf3340/_data ),这个目录就是 mount 源。

删除容器的操作,默认不会对dockerHost上的源文件操作,如果想要在删除容器时把源文件也删除,可以在删除容器时添加 -v 选项(一般不推荐使用这种方式,因为文件有可能被其他容器使用)。

除了上述这种方式之外,还可以手动创建volume。

//手动创建volume

[root@docker01 ~]# docker volume create testweb4
testweb4
[root@docker01 ~]# docker volume ls
DRIVER              VOLUME NAME
local               47786c758c43ee7395d22b69d47e47c9cffc4ef7fe0518b922608ec861f6c97d
local               testweb4

[root@docker01 ~]# docker volume inspect testweb4 
[
    {
        "CreatedAt": "2021-02-10T04:00:02+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/testweb4/_data",
        "Name": "testweb4",
        "Options": {},
        "Scope": "local"
    }
]
[root@docker01 ~]# docker run -itd -P -v testweb4:/usr/share/nginx nginx:latest

PS: 注意一下,运行容器时使用的我们手动创建的volume,在书写格式上和bind mount一样,但查看容器的详细信息,其实它仍然使用的是dockermanager volume这种方式。

总结:

Bind Mount 和 Docker Manager Volume的特点;

bind mountdocker managed volume
volume 位置可任意指定/var/lib/docker/volumes/…
有mountpoint 影响隐藏并替换为volume原有数据复制到 volume
是否支持单个文件支持不支持,只能是目录
权限控制可设置为只读,默认为读写权限无控制,均为读写权限
移植性移植性弱,与 hostpath 绑定移植性强,无需指定 host目录

容器与容器的数据共享:
volume container:给其他容器提供volume存储卷的容器。并且它可以提供bind mount,也可以提供docker manager volume.

//创建一个vc_data容器。

[root@docker01 ~]# docker create --name vc_data -v ~/html:/usr/share/nginx/html -v /other/useful/tools busybox

//使用vc容器。

[root@docker01 ~]# docker run -itd --name t5 -P --volumes-from vc_data nginx

容器的跨主机数据共享

docker01docker02docker03
httpdhttpdnfs

要求:docker01和docker02上基于httpd镜像运行2个或多个容器,保证的主目录(默认访问界面内容)是一样的。

[root@docker01 ~]# docker pull httpd
[root@docker02 ~]# docker pull httpd

docker03操作

[root@docker0 ~]# yum -y install nfs-utils
[root@docker0 ~]# mkdir /datashare
[root@docker0 ~]# vim /etc/exports
[root@docker0 ~]# systemctl start rpcbind
[root@docker0 ~]# systemctl enable rpcbind
[root@docker0 ~]# systemctl start nfs-server
[root@docker0 ~]# systemctl enable nfs-server
[root@docker0 ~]# vim /datashare/index.html 
添加:
bdqn-webshare

docker01操作

[root@docker01 ~]# yum -y install showmount
[root@docker01 ~]# showmount -e 192.168.1.22
Export list for 192.168.1.22:
/datashare *
[root@docker01 ~]# mkdir /htdocs
[root@docker01 ~]# mount -t nfs 192.168.1.22:/datashare /htdocs/
[root@docker01 ~]# cat /htdocs/index.html 
bdqn-webshare

docker02操作(跟docker01操作一样)

[root@docker02 ~]# showmount -e 192.168.1.22
Export list for 192.168.1.22:
/datashare *
[root@docker02 ~]# yum -y install showmount
[root@docker02 ~]# mkdir /htdocs
[root@docker02 ~]# mount -t nfs 192.168.1.22:/datashare /htdocs/
[root@docker02 ~]# cat /htdocs/index.html 
bdqn-webshare

这里先不考虑将代码写入镜像,先以这种方式,分别在docker01和docker02部署httpd服务

//docker01

[root@docker01 ~]# docker run -itd --name bdqn-web1 -P -v /htdocs:/usr/local/apache2/htdocs httpd:latest

PS: 查看端口映射0.0.0.0:32774->80/tcp

[root@docker01 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
ace81a2ceae5        httpd:latest        "httpd-foreground"   33 seconds ago      Up 32 seconds       0.0.0.0:32774->80/tcp   bdqn-web1

//docker02

[root@docker02 ~]# docker run -itd --name bdqn-web2 -P -v /htdocs:/use/local/apache2/htdocs httpd:latest

PS: 查看端口映射0.0.0.0:32768->80/tcp

[root@docker02 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
a58abe97bd04        httpd:latest        "httpd-foreground"   5 seconds ago       Up 3 seconds        0.0.0.0:32768->80/tcp   bdqn-web2

此时,用浏览器访问,两个WEB服务的主界面是一样。但如果,NFS服务器上的源文件丢失,则两个web服务都会异常。

想办法将源数据写入镜像内,在基于镜像做一个vc_data容器。这里因为没接触到docker-compose和docker swarm等docker 编排工具,所以我们在docker01和docker02上先手动创建镜像。
//dockre01

[root@docker01 htdocs]# vim Dockerfile
添加:
FROM busybox 
COPY index.html /usr/local/apache2/htdocs/index.html 
VOLUME /usr/local/apache2/htdocs
[root@docker01 htdocs]# docker build -t back_data .
[root@docker01 htdocs]# docker create --name back_container1 back_data:latest

//docker02一样(直接从docker复制过来)

[root@docker01 htdocs]# scp /htdocs/Dockerfile 192.168.1.21:/htdocs/
[root@docker02 htdocs]# docker build -t back_data .
[root@docker02 htdocs]# docker create --name back_container1 back_data:latest

总结:
1)解决容器跨主机数据共享的方案: NFS
2)容器与容器的数据共享: 基于某个容器而来(–volumes-from选项),意味着这些容器和vc容器的数据存储是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值