Docker数据持久化和容器与容器的数据共享

云计算

一、前言

当我们使用Docker创建一个mysql的container, 数据是存储在container内的.
如果有一天不小心执行了docker rm $(docker ps -aq)删除所有container. 那么Mysql里的数据也会被删掉, 这是不安全的.
我们需要将数据持久化, 存储在container外部. 即使删除container也不会删除原有的数据.

二、容器的缺陷

容器中的数据可以存储在容器层。但是将数据存放在容器层存在以下问题:
1.数据不是持久化。意思是如果容器删除了,这些数据也就没了
2.主机上的其它进程不方便访问这些数据
3.对这些数据的I/O会经过存储驱动,然后到达主机,引入了一层间接层,因此性能会有所下降

三、data volume有两种挂载方式:

1)bind mount(用户管理):将宿主机上的某个目录或文件(不可以是没有格式化的磁盘文件),挂载到容器中,默认在容器内对此目录是有读写权限的,如果只需要向容器内添加文件,不希望覆盖目录,需要注意源文件必须存在,否则会被当做一个目录bind mount给容器。
2)docker manager volume(docker自动管理):不需要指定源文件,只需要指定mount point(挂载点)。把容器里面的目录映射到了本地。
这种方式相比bind mount 缺点是无法限制对容器里边目录或文件的权限。

使用第二种挂载方式,-v 挂载时,不指定源文件位置,则默认挂载的路径是:

[root@sqm-docker01 _data]# pwd
/var/lib/docker/volumes/dd173640edd5b0205bb02f3c4139647be12528b38289b9f93f18123a6b1266a8/_data
#当有目录挂载时,默认在/var/lib/docker/volumes/下会生成一串hash值,hash值下有一个_data的目录,容器内映射的文件就在此路径下。

四、Storage Driver

数据存储方式

Centos7版本的docker,Storage Driver(数据存储方式)为:overlay2 ,Backing Filesystem(文件系统类型): xfs

可使用 “docker inspect 容器名称” 来查看数据存储方式

五、Data Volume
(Bind mount)

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

特点:
**1. Data Volume是目录或文件,不能是没有格式化的磁盘(块设备)。

容器可以读写volume中的数据。
Volume数据可以永久保存,即使使用它的容器已经被销毁。**

小实验:

运行一个nginx服务,做数据持久化

(1)Data Volume是目录或文件,不能是没有格式化的磁盘(块设备)。

[root@docker01 ~]# mkdir html
//创建测试目录
[root@docker01 ~]# cd html/
[root@docker01 html]# echo This is a testfile in dockerHost. > index.html
//创建测试网页
[root@docker01 ~]# docker run -itd --name testweb -v /root/html/:/usr/share/nginx/html nginx:latest
//运行一个nginx容器,并挂载目录
[root@docker01 ~]# docker inspect testweb

[root@docker01 ~]# curl 172.17.0.3

注意:dockerhost上需要被挂载的源文件或目录,必须是已经存在,否则,会被当作一个目录挂载到容器中。

(2)容器可以读写volume中的数据。

[root@docker01 ~]# docker exec  -it testweb  /bin/bash
root@ef12d312a94e:/# cd /usr/share/nginx/html/
root@ef12d312a94e:/usr/share/nginx/html# echo update > index.html
//容器中更新网页
root@ef12d312a94e:/usr/share/nginx/html# exit
[root@docker01 ~]# cat html/index.html
//可以看到宿主目录的挂载目录也更新了

(3)Volume数据可以永久保存,即使,使用它的容器已经被销毁,也可以通过宿主机的挂在目录重新启动一个容器挂载这个目录进行访问。

[root@docker01 ~]# docker ps -a -q |xargs docker rm -f
//删除所有容器

[root@docker01 ~]# cat html/index.html
//容器删除之后,宿主机的测试网页也在

[root@docker01 ~]# docker run  -itd --name t1  -P -v  /root/html/:/usr/share/nginx/html nginx:latest
//基于测试网页创建一个容器
[root@docker01 ~]# docker ps

[root@docker01 ~]# curl 127.0.0.1:32768
//访问一下

[root@docker01 ~]# echo update-new > html/index.html
//再次更新测试网页
[root@docker01 ~]# curl 127.0.0.1:32768
//在宿主机更新测试网页,刚刚创建的容器的测试网页也会更新

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

[root@docker01 ~]# docker run  -itd --name t2 -P  -v  /root/html/:/usr/share/nginx/html:ro  nginx:latest
//创建容器设置指读权限
[root@docker01 ~]# docker exec -it t2 /bin/bash
//进入容器
root@4739c0f5d970:/# cd /usr/share/nginx/html
root@4739c0f5d970:/usr/share/nginx/html# echo 1234 > index.html
//修改测试网页(失败,因为是只读的)

[root@docker01 ~]# echo 654321 > html/index.html 
//宿主机可以更改
[root@docker01 ~]# curl 127.0.0.1:32768

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

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

[root@docker01 ~]# curl 127.0.0.1:32770

<1>测试2

[root@docker01 ~]#  echo test > test.html
[root@docker01 ~]# docker run -itd --name t8 -P -v /root/test.html:/usr/share/nginx/html/test.html nginx:latest

[root@docker01 ~]# curl 127.0.0.1:32772/test.html

六,Docker Manager Volume

会自动在宿主机生成目录,所以在挂载目录的时候只用写容器中的目录。
特性和上边的bind mount基本一样

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

[root@docker01 ~]# docker inspect t1

[root@docker01 _data]# cd /var/lib/docker/volumes/17c50a065a6b10ccd01ca1ce8091fdf6282dc9dcb77a0f6695906257ecc03a63/_data
[root@docker01 _data]# echo this is a testfile > index.html
[root@docker01 _data]# docker ps

[root@docker01 _data]# curl 127.0.0.1:32777

[root@docker01 _data]# docker volume ls

[root@docker01 _data]# docker rm t1 -f
[root@docker01 _data]# cat index.html

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

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

[root@docker01 ~]# cd /var/lib/docker/volumes/2781dbfdc673fc7d149dc4f6217ef277fe72e05ba2e20fcebb617afe97eccb30/_data
[root@docker01 _data]# docker rm -v t2 -f
t2
[root@docker01 _data]# ls

七,容器与容器的数据共享

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
[root@docker01 ~]# docker inspect vc_data

[root@docker01 ~]# docker run -itd --name t3 -P  --volumes-from vc_data nginx:latest
[root@docker01 ~]# docker ps

[root@docker01 ~]# curl 127.0.0.1:32779

八,容器的跨主机数据共享

实验环境

docker01 docker02

httpd
nfs

要求:docker01和docker02的主目录,是一样的。

准备工作

[root@localhost ~]# hostnamectl set-hostname nfs
[root@localhost ~]# hostnamectl set-hostname docker01
[root@localhost ~]# hostnamectl set-hostname docker02

nfs操作

[root@localhost ~]# yum -y install nfs-utils
//下载nfs服务

[root@nfs ~]# mkdir /datashare
//创建共享目录

[root@nfs ~]# vim /etc/exports
//设置权限如下
/datashare *(rw,sync,no_root_squash)

开启各项服务

[root@nfs ~]# systemctl start rpcbind
[root@nfs ~]# systemctl enable rpcbind
[root@nfs ~]# systemctl start nfs-server
[root@nfs ~]# systemctl enable nfs-server

docker01和docker02测试nfs

[root@docker01 htdocs]# showmount -e 192.168.1.20
[root@docker02 htdocs]# showmount -e 192.168.1.20

docker01的操作

[root@docker02 ~]# mkdir /xxx
[root@docker01 ~]# mount  -t nfs 192.168.1.10:/datashare /xxx
//挂载nfs上的共享目录
[root@docker01 ~]# mount | tail -1
//查看是否挂载

nfs创建测试文件

[root@nfs ~]# cd datashare/
[root@nfs datashare]# vim index.html
<div id=datetime>
    <script>
        setInterval(document.getElementById(\'datetime\').innerHTML=new Date().toLocaleString();, 1000);
    </script>
</div>
xgp666

docker01查看一下

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

[root@docker01 ~]# docker run -itd --name bdqn-web1 -P -v /xxx/:/usr/local/apache2/htdocs httpd:latest 
[root@docker02 ~]# docker run -itd --name bdqn-web2 -P -v /xxx/:/usr/local/apache2/htdocs httpd:latest
[root@docker01 ~]# docker ps 
//查看端口
0.0.0.0:32775->80/tcp   bdqn-web
[root@docker02 ~]# docker ps
//查看端口
0.0.0.0:32769->80/tcp   bdqn-web2

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

想办法将元数据写入镜像内,在基于镜像创建一个vc_data容器,这里因为没有接触到docker-compose和docker-swarm等docker编排工具,所以需手动创建镜像!

nfs操作

[root@nfs datashare]# echo xgp666 > index.html 
//更改测试文件

docker02操作

[root@docker02 ~]# cd /xxx/
[root@docker02 xxx]# vim Dockerfile
//编写Dockerfile
[root@docker02 xxx]# cat Dockerfile 
FROM busybox
ADD index.html /usr/local/apache2/htdocs/index.html
VOLUME /usr/local/apache2/htdocs

创建镜像并运行一个容器

[root@docker02 xxx]# docker build -t back_data .
//基于Dockerfile创建镜像
[root@docker02 xxx]# docker create --name back_container1  back_data:latest 
//基于刚刚创建的镜像创建容器

运行容器,并导出镜像

[root@docker02 xxx]# docker run -itd --name bdqn-web3 -P  --volumes-from  back_container1 httpd:latest 
//运行一台容器
[root@docker02 xxx]# docker save > back_data.tar back_data:latest
//导出镜像,因为是在共享目录所以docker01也可以看到

docker01

[root@docker01 xxx]# docker load -i back_data.tar 
//去共享目录,导入镜像
[root@docker01 xxx]# docker  create --name back_container2  back_data:latest
//基于刚刚创建的镜像运行容器
[root@docker01 xxx]# docker run  -itd --name bdqn-web4 -P  --volumes-from  back_container2 httpd:latest
//运行一台容器

浏览器访问

[root@docker01 ~]# docker ps 
//查看端口
 0.0.0.0:32776->80/tcp   bdqn-web4
[root@docker02 ~]# docker ps
//查看端口
0.0.0.0:32770->80/tcp   bdqn-web3

新网虚拟主机

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注