Docker实践(三):数据持久化及共享

环境说明:

主机名 操作系统版本 IP地址 docker版本
ubuntu1604 Ubuntu 16.04.5 172.27.9.31 18.09.2

ubuntu安装详见:Ubuntu16.04.5以lvm方式安装全记录
docker安装详见:Ubuntu16.04安装Docker
?在Linux上运行的Docker有三种不同的方式将数据从 Docker Host挂载到 Docker 容器,并实现数据的读取和存储:volumes、bind mounts、tmpfs。??
三者的区别在于数据存储在docker主机的位置不同。

  • Volumes(又称docker managed volume)储在主机文件系统的中,由docker管理(在Linux上默认位置为/var/lib/docker/volumes/),只有Docker进程能修改该位置,Volumes是在Docker中保存数据的最佳方式。
  • Bind mounts可以存储在主机系统的任何位置,可能是重要的系统文件或目录,Docker主机或Docker容器上的非Docker进程可以随时修改它们。
  • tmpfs挂载仅存储在主机系统的内存中,不写入主机系统的文件系统。?

一、Volumes

简介

volumes(也被称为Docker-managed volumes)是保存Docker容器生成和使用的数据的首选机制。相较于bind mounts依赖于主机的目录结构,volumes完全由Docker管理。与bind mounts相比,volumes有几个优势:

  • 与bind mounts相比,volumes更容易备份或迁移。
  • 可以使用docker cli命令或docker api管理volumes。
  • volumes可以在Linux和Windows容器上工作。
  • 可以更安全地在多个容器之间共享volumes。
  • Volume drivers可以实现在远程主机或云主机存储数据以供加密卷的内容,或添加其他功能。
  • 新的volumes可以通过容器预先填充其内容。

此外,volumes通常比在容器的可写层中保存数据更好,因为volumes不会增加使用它的容器的大小,并且volumes的内容存在于给定容器的生命周期之外(即使容器被销毁volumes也会保存在docker host的文件系统中)
volumes在docker host的位置:

Volumes测试

1.新建Volume

root@ubuntu1604:~# docker volume create my-vol
my-vol

2.列出Volumes

root@ubuntu1604:~# docker volume ls
DRIVER              VOLUME NAME
local               my-vol

3.查看volume详情

root@ubuntu1604:~# docker volume inspect my-vol
[
    {
        "CreatedAt": "2019-03-25T15:02:16+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
    }
]

volume 在host上的默认目录为:/var/lib/docker/volumes/$(VOLUME NAME)/_data
新建的volume内容为空

root@ubuntu1604:~# ll /var/lib/docker/volumes/my-vol/_data
total 8
drwxr-xr-x 2 root root 4096 Mar 25 15:02 ./
drwxr-xr-x 3 root root 4096 Mar 25 15:02 ../

4.使用volume

4.1新建container

新建container myweb01并使用volume my-vol

root@ubuntu1604:~# docker run -d -p 80:80 -v my-vol:/usr/local/apache2/htdocs --name myweb01 httpd

容器myweb01的80端口被映射为主机的80端口,my-vol被挂载到apache server存放静态文件的目录/usr/local/apache2/htdocs??

4.2访问myweb01

root@ubuntu1604:~# curl 172.27.9.31:80
<html><body><h1>It works!</h1></body></html>

4.3再次查看volume内容

root@ubuntu1604:~# ll /var/lib/docker/volumes/my-vol/_data
total 12
drwxr-sr-x 2 root www-data 4096 Mar 25 15:30 ./
drwxr-xr-x 3 root root     4096 Mar 25 15:02 ../
-rw-r--r-- 1 root src        45 Jun 12  2007 index.html
root@ubuntu1604:~# more /var/lib/docker/volumes/my-vol/_data/index.html
<html><body><h1>It works!</h1></body></html>

发现容器myweb01的内容index.html被复制到volume中,这也印证了前面所讲的volumes的特点之一:“新的volumes可以通过容器预先填充其内容”?

4.4更新数据并访问

root@ubuntu1604:~# echo "update volumes:loong576" >/var/lib/docker/volumes/my-vol/_data/index.html
root@ubuntu1604:~# curl 172.27.9.31:80
update volumes:loong576

更新volume中的index.html,发现容器myweb01的访问内容也一并更新。??

4.5销毁volume

root@ubuntu1604:~# docker rm -f -v myweb01
myweb01
root@ubuntu1604:~# more /var/lib/docker/volumes/my-vol/_data/index.html
update volumes:loong576
root@ubuntu1604:~# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
root@ubuntu1604:~# docker volume ls
DRIVER              VOLUME NAME
local               my-vol
root@ubuntu1604:~# docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
my-vol

Total reclaimed space: 24B
root@ubuntu1604:~# docker volume ls
DRIVER              VOLUME NAME
root@ubuntu1604:~# more /var/lib/docker/volumes/my-vol/_data/index.html
more: stat of /var/lib/docker/volumes/my-vol/_data/index.html failed: No such file or directory

当销毁容器时,volume没有被同时消除,留下孤儿volume,通过docker volume prune即可删除???

二、Bind mounts??

简介

?Docker早期就有了Bind mounts。与volumes相比,Bind mounts的功能有限。使用Bind mounts时,主机上的文件或目录将装载到容器中。文件或目录由其在主机上的完整路径或相对路径引用。相反,使用卷时,会在主机上Docker的存储目录中创建一个新目录,Docker管理该目录的内容。

?对于Bind mounts,文件或目录不需要已经存在于Docker主机上。如果它还不存在,则按需创建。Bind mounts的性能非常好,但它们依赖于主机的文件系统,该文件系统具有特定的可用目录结构。如果您正在开发新的Docker应用程序,请考虑改用volumes。另外不能使用docker cli命令直接管理绑定装载。
Bind mounts在docker host的位置:

Bind mounts测试

本文使用NFS作为Bind mounts的挂载点
NFS搭建配置详见:Centos7下NFS服务器搭建及客户端连接配置

1.挂载nfs并新建index.html

root@ubuntu1604:~# mount -t nfs 172.27.9.181:/nfs /mywebtest
root@ubuntu1604:~# df -h
Filesystem               Size  Used Avail Use% Mounted on
udev                     467M     0  467M   0% /dev
tmpfs                     98M  5.9M   92M   7% /run
/dev/mapper/rootvg-root  4.6G  539M  3.8G  13% /
/dev/mapper/rootvg-usr   4.6G  921M  3.5G  21% /usr
tmpfs                    488M     0  488M   0% /dev/shm
tmpfs                    5.0M     0  5.0M   0% /run/lock
tmpfs                    488M     0  488M   0% /sys/fs/cgroup
/dev/sda1                453M   59M  367M  14% /boot
/dev/mapper/rootvg-tmp   4.6G  9.6M  4.4G   1% /tmp
/dev/mapper/rootvg-opt   4.6G  9.6M  4.4G   1% /opt
/dev/mapper/rootvg-var   4.6G  470M  3.9G  11% /var
/dev/mapper/rootvg-home  4.6G  9.6M  4.4G   1% /home
cgmfs                    100K     0  100K   0% /run/cgmanager/fs
tmpfs                     98M     0   98M   0% /run/user/0
172.27.9.181:/nfs        6.0G   97M  5.9G   2% /mywebtest
root@ubuntu1604:~# cd /mywebtest/ && touch index.html && echo "bind mount webtest:loong576" > index.html
root@ubuntu1604:/mywebtest# more index.html
bind mount webtest:loong576

/mywebtest被挂载到远程的nfs服务器172.27.9.181的/nfs目录,并在/mywebtest目录新建index.html文件

2.新建container myweb02

root@ubuntu1604:~# docker run -d -p 81:80 -v /mywebtest/:/usr/local/apache2/htdocs --name myweb02 httpd
749a107648450a627a03fadc29680a0cdaff1e68ba10421ddebb52e2f7f7baf4

新建容器myweb02,将 /mywebtest挂载到容器/usr/local/apache2/htdocs,容器的80端口映射为主机的81端口。

3.访问myweb02

root@ubuntu1604:~# curl 172.27.9.31:81
bind mount webtest:loong576

发现访问内容为刚刚新建的index.html,bind mounts的内容覆盖了了容器的index.html。

4.更新index.html

root@ubuntu1604:~# echo "update bind mount webtest:loong576 02" >/mywebtest/index.html
root@ubuntu1604:~# curl 172.27.9.31:81
update bind mount webtest:loong576 02

更新index.html,访问myweb02,发现一并更新

5.销毁容器

root@ubuntu1604:~# docker rm -f myweb02
myweb02
root@ubuntu1604:~# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
root@ubuntu1604:~# more /mywebtest/index.html
update bind mount webtest:loong576 02

容器myweb02被销毁,但是Bind mounts继续存在。
volumes与bind mounts异同:

不同点 volumes bind mounts
Source位置 /var/lib/docker/volumes/... 可以任意指定
对已有挂载点影响 容器内数据复制到volume 覆盖掉容器的内容
是否支持单个文件 不支持,只能是目录 支持
权限控制 读写或者只读 读写或者只读
移植性 强,无需指定host目录 弱,与host path绑定

三、tmpfs mounts

简介

?volumes和bind mounts允许您在主机和容器之间共享文件,这样即使容器停止,您也可以保留数据。
?如果您在Linux上运行docker,则有第三个选项:tmpfs mounts。当使用tmpfs装载创建容器时,容器可以在容器的可写层之外创建文件。
?与volumes和bind mounts不同,tmpfs挂载是临时的,并且只持久存在于主机内存中。当容器停止时,tmpfs挂载将被删除,在那里写入的文件将不会被持久化。
tmpfs mounts在docker host的位置:

tmpfs mounts测试

1.新建container myweb03

root@ubuntu1604:~# docker run -d -p 82:80 --tmpfs /web03 --name myweb03 httpd 

新建容器myweb03,容器对目录/web03所有的读写操作都在内存中。

2.新建test.txt

root@ubuntu1604:~# docker exec -it myweb03 bash
root@f91161779960:/usr/local/apache2# cd /web03/ && echo tmpfs-test > test.txt
root@f91161779960:/web03# more test.txt
tmpfs-test

在/web03中新建测试文件test.txt,重启容器后观察该文件是否存在。

3.重启myweb03

root@ubuntu1604:~# docker stop myweb03
myweb03
root@ubuntu1604:~# docker start myweb03
myweb03
root@ubuntu1604:~# docker exec -it myweb03 bash
root@f91161779960:/usr/local/apache2# cd /web03/
root@f91161779960:/web03# ls -l
total 0

重启容器,发现测试文件test.txt消失。

四、容器间的数据共享

bind mounts方式

?该方式为依赖于主机的共享,多个容器通过 Volume 绑定到主机上的相同位置

1.新建index.html

root@ubuntu1604:~# echo "container datas share : bind mounts" > /mywebtest/index.html

2.新建container web01 web02 web03

root@ubuntu1604:~# docker run -d -p 7701:80 -v /mywebtest/:/usr/local/apache2/htdocs --name web01 httpd
cfa46a13458aa650c2d3243460f38ef0a53d4f8d4643633b34edb1c257fa56f6
root@ubuntu1604:~# docker run -d -p 7702:80 -v /mywebtest/:/usr/local/apache2/htdocs --name web02 httpd
4655998a69590653af9e41eaa92e48a3798666e79a70f55f9ca33d5c1e60ea05
root@ubuntu1604:~# docker run -d -p 7703:80 -v /mywebtest/:/usr/local/apache2/htdocs --name web03 httpd
69e917fbbb20f8a5b886b14ffa05ee93d28461e551eaf4caf9abc0610f60943b

新建容器web01/web02/web03,将主机的/mywebtst分别挂载到容器的usr/local/apache2/htdocs目录。

3.访问web

root@ubuntu1604:~# curl 172.27.9.31:7701
container datas share : bind mounts
root@ubuntu1604:~# curl 172.27.9.31:7702
container datas share : bind mounts
root@ubuntu1604:~# curl 172.27.9.31:7703
container datas share : bind mounts

在/web03中新建测试文件test.txt,重启容器后观察该文件是否存在。

4.更新index.html

root@ubuntu1604:~# echo "container datas share 02 : bind mounts" > /mywebtest/index.html
root@ubuntu1604:~# curl 172.27.9.31:7701
container datas share 02 : bind mounts
root@ubuntu1604:~# curl 172.27.9.31:7702
container datas share 02 : bind mounts
root@ubuntu1604:~# curl 172.27.9.31:7703
container datas share 02 : bind mounts

更新并再次访问web,发现所有容器的web访问页面已更新。

Volume container方式

?创建一个容器专门用于定义Volumes(可以是上文提到的volumes也可以是bind mounts),这个容器可以不运行,因为停止的容器也会保留对Volume的引用。然后其它的容器在创建或运行时通过--volumes-from从该容器复制Volume定义。?
使用该方式的注意事项:

  • 一般容器名加前缀 vc_,表示 volume container
  • 涉及的各容器对于 Volume 绑定的目录位置及命名规范都必须协同一致

1.新建container vc_data

root@ubuntu1604:~# docker create -v /mywebtest/:/usr/local/apache2/htdocs -v /apps --name vc_data  busybox

使用的busybox无实际意义,该镜像很小很适合测试

2.查看vc_data

root@ubuntu1604:~# docker inspect vc_data


/mywebtest/通过bind mounts方式挂载到容器/usr/local/apache2/htdocs目录,卷6a635ec450eeecd487df4f25615c14443aa2a4da07b8c605a031d5ab9b5bbf47通过volume方式挂载至容器/apps目录。

3.使用vc_data

root@ubuntu1604:~# docker run -d -p 7704:80 --volumes-from vc_data --name web04 httpd
25ff55566720281791f2b1956236204dbca6ad529fa460a76d80e970786df22d
root@ubuntu1604:~# docker run -d -p 7705:80 --volumes-from vc_data --name web05 httpd
dcce95be79b1ecc888d748d684b814743583c5db1ac41f026ca4ed5525f51c67
root@ubuntu1604:~# docker run -d -p 7706:80 --volumes-from vc_data --name web06 httpd
edd257edaf6101ee8911afeb08b70ec95673b5e1c64c774e2b00f1486b025ba8

新建容器web04/web05/web06并使用vc_data。

4.查看web04

root@ubuntu1604:~# docker inspect web04


挂载信息和vc_data一致。

5.共享验证

root@ubuntu1604:~# echo "abc123" > /var/lib/docker/volumes/6a635ec450eeecd487df4f25615c14443aa2a4da07b8c605a031d5ab9b5bbf47/_data/test.txt
root@ubuntu1604:~# curl 172.27.9.31:7704
container datas share : Volume container
root@ubuntu1604:~# curl 172.27.9.31:7705
container datas share : Volume container
root@ubuntu1604:~# curl 172.27.9.31:7706
container datas share : Volume container
root@ubuntu1604:~# docker exec -it web04 bash
root@25ff55566720:/usr/local/apache2# cd /apps/ && ls -l
total 4
-rw-r--r-- 1 root root 7 Mar 27 08:12 test.txt
root@25ff55566720:/apps# more test.txt
abc123

分别在共享目录更新新建文件,各容器也能正常访问读取共享数据。

Data-packed volume container 方式

?这种模式扩展至Volume container模式。Data-packed volume container不仅定义Volumes,而且将从本容器的映像中的一些数据(如静态文件、配置数据、代码等)复制到这个定义的Volumes中,从而可与其它容器共享。

1.构建镜像

配置查看

root@ubuntu1604:~# pwd
/root
root@ubuntu1604:~# ls
Dockerfile  htdocs
root@ubuntu1604:~# more htdocs/index.html
container datas share : Data-packed volume
root@ubuntu1604:~# more Dockerfile
FROM busybox
ADD htdocs /usr/local/apache2/htdocs
VOLUME /usr/local/apache2/htdocs

构建镜像

root@ubuntu1604:~# docker build -t image_datapacked .
Sending build context to Docker daemon  18.43kB
Step 1/3 : FROM busybox
 ---> d8233ab899d4
Step 2/3 : ADD htdocs /usr/local/apache2/htdocs
 ---> d9266ad06c41
Step 3/3 : VOLUME /usr/local/apache2/htdocs
 ---> Running in c7d1cab717d4
Removing intermediate container c7d1cab717d4
 ---> f8f9f9c15171
Successfully built f8f9f9c15171
Successfully tagged image_datapacked:latest

通过Dockerfile方式构建镜像,镜像名为image_datapacked

2.创建data-packed volume container

root@ubuntu1604:~# docker run -it  --name vc_datapacked image_datapacked
/ # cd /usr/local/apache2/htdocs/
/usr/local/apache2/htdocs # ls
index.html
/usr/local/apache2/htdocs # more index.html
container datas share : Data-packed volume

运行data-packed volume container:vc_datapacked,可以看到之前写进镜像层的index.html:container datas share : Data-packed volume
查看vc_datapacked详情

root@ubuntu1604:~# docker inspect vc_datapacked  


因为在 Dockerfile中已经使用了VOLUME指令,这里就不需要指定volume的 mount point了。
volume为/var/lib/docker/volumes/3c37bc016de3018cb59292cdfca581893a77d19ba8b8f5538b04aab71b3603a1,容器挂载点为/usr/local/apache2/htdocs

3.使用vc_datapacked

root@ubuntu1604:~# docker run -d -p 7707:80 --volumes-from vc_datapacked --name web_datapacked httpd

新建容器web_datapacked并使用vc_datapacked。

4.查看web_datapacked

root@ubuntu1604:~# docker inspect web_datapacked


volume为/var/lib/docker/volumes/3c37bc016de3018cb59292cdfca581893a77d19ba8b8f5538b04aab71b3603a1,容器挂载点为/usr/local/apache2/htdocs。挂载信息和vc_datapacked一致。

5.共享验证

root@ubuntu1604:~# curl 172.27.9.31:7707
container datas share : Data-packed volume

访问容器web_datapacked的web服务,返回结果与写入镜像image_datapacked的index.html一直,实现了静态文件index.html

6.总结

  • 1.相较于volume container,data-packed volume container方式直接把共享数据写进镜像层,通过上传至私有仓库,其它docker host都能使用该镜像实现容器的数据共享;
  • 2.data-packed volume container只适用于静态数据共享;
  • 3.若要修改data-packed volume container中的共享数据,只能重建image,不能动态修改。

本文参考:
https://docs.docker.com/storage/
http://www.atjiang.com/persistent-storage-and-shared-state-with-volumes-in-docker/
https://blog.51cto.com/cloudman/1948779
?

原文地址:https://blog.51cto.com/3241766/2371023

时间: 2024-08-29 16:33:48

Docker实践(三):数据持久化及共享的相关文章

docker容器实现数据持久化的两种方式及其区别

前言 这篇博文是我对docker实现数据持久化几种方式的特征进行一个总结. 在docker中,它的存储文件系统是在dockerhost上原有的xfs或ext4架设了一层文件系统:overlay2(将此行重点标注的原因就是我在面试中被问到过:docker使用的是什么文件系统?),通过docker info命令可以查看出主机上docker相关的信息,包括支持的网络类型.系统版本.内核版本.docker主机的cpu.内存等信息.如下: 在docker中实现数据持久化有两种方式:Bind mount和D

Docker Swarm bind 数据持久化

Docker Swarm bind 数据持久化 bind:主要将工作节点宿主级文件或目录,同步挂载到容器中. 环境: 系统:Centos 7.4 x64 应用版本:Docker 18.09.0 管理节点:192.168.1.79 工作节点:192.168.1.78 工作节点:192.168.1.77 一.两种宿主级挂载方式 管理节点:读写挂载 docker service create --mount type=bind,src=<HOST-PATH>,dst=<CONTAINER-PA

docker 实践三:操作容器

在学习了 docker 镜像的内容后,我们在来看 docker 的另一个核心点:容器. 注:环境为 CentOS7,docker 19.03 docker 的容器是镜像的一个运行实例.docker 镜像是只读文件,而容器则带有运行时的可读写层,而且容器中的应用进程处于运行状态.接下来我们就来学习 docker 容器的具体操作. 创建容器 创建容器相关的命令有 create.start.run.wait 和 logs. 新建容器 使用命令 docker [container] create 新建一

Docker数据持久化简述

Docker中的数据持久化方式有两种:数据卷(Data Volumes)挂载主机目录 (Bind mounts) 数据卷:数据卷可以在容器之间共享和重用对数据卷 的修改会立马生效对数据卷 的更新,不会影响镜像数据卷默认会一直存在,即使容器被删除$ docker volume create my-vol #创建数据卷$ docker volume ls #查看有哪些卷$ docker volume inspect my-vol #查看卷详情$ docker run -d -P --name web

K8s实现数据持久化

前言 在一切虚拟化解决方案中,数据的持久化都是需要我们非常关心的问题,docker如此,K8s也不例外.在k8s中,有一个数据卷的概念. k8s数据卷主要解决了以下两方面问题: 数据持久性:通常情况下,容器运行起来后,写入到其文件系统的文件时暂时性的.当容器崩溃后,kebelet将这个容器kill掉,然后生成一个新的容器,此时,新运行的容器将没有原来容器内的文件,因为容器是重新从镜像创建的. 数据共享:同一个pod中运行的容器之间,经常会存在共享文件/文件夹的需求. 在k8s中,Volume(数

k8s实践(七):存储卷和数据持久化(Volumes and Persistent Storage)

环境说明: 主机名 操作系统版本 ip docker version kubelet version 配置 备注 master Centos 7.6.1810 172.27.9.131 Docker 18.09.6 V1.14.2 2C2G master主机 node01 Centos 7.6.1810 172.27.9.135 Docker 18.09.6 V1.14.2 2C2G node节点 node02 Centos 7.6.1810 172.27.9.136 Docker 18.09.

Docker数据持久化与容器迁移

上节讲到当容器运行期间产生的数据是不会在写镜像里面的,重新用此镜像启动新的容器就会初始化镜像,会加一个全新的读写入层来保存数据.如果想做到数据持久化,Docker提供数据卷(Data volume)或者数据容器卷来解决问题,另外还可以通过commit提交一个新的镜像来保存产生的数据.那么,来一一看下各自的使用方法. 一.数据卷 数据卷特性: 可以绕过UFS文件系统,为一个或多个容器提供访问. 完全独立于容器的生存周期,因此不会在删除容器时删除其挂在的数据卷. 数据卷特点: 数据卷在容器启动初始化

自己学Docker:5.Docker的数据持久化之数据卷

首先,别忘记之前的两个问题: 1. 如何保存我们在容器里的修改? 2. 如果apt-get如果不能安装时,如何在Docker中安装软件? 删除镜像命令 在此之前,先记一个命令, sudo docker rm ID/NAME 即删除创建的镜像.如 现在删除id为"cc8a23b1d624"的镜像. sudo docker rm cc8a23b1d624 可以看到,id为cc8a23b1d624的镜像被删除了. 而且可以发现,本地的/var/lib/docker/containers目录下

docker学习系列(四):数据持久化

需要搞清楚一个概念的是,docker的容器设计理念是可以即开即用,用完可以随意删除,而新建容器是根据镜像进行渲染,容器的修改是不会影响到镜像,但是有时候容器里面运行的产生的数据(如mysql)或者配置项(如nginx的nginx.conf)我们又需要保存起来的,因而我们需要对容器某些修改的数据进行挂载. 下面介绍三种持久化数据的方式 1.挂载磁盘到本地 docker run -v 宿主目录:容器挂载的目录 镜像 这时候docker会自动在对应的目录下进行挂载,值得注意的是,如果容器里面没有宿主机