Docker数据持久化

想要了解Docker Volume,首先我们需要知道Docker的文件系统是如何工作的。
Docker镜像是由多个文件系统(只读层)叠加而成。
当我们启动一个容器的时候,Docker会加载只读镜像层并在其上(注:镜像栈顶部)添加一个读写层。
如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏。
当删除Docker容器,并通过该镜像重新启动时,之前的更改将会丢失。
在Docker中,只读层及在顶部的读写层的组合被称为Union File System(联合文件系统)。

为了能够保存(持久化)数据以及共享容器间的数据,Docker提出了Volume的概念。
简单来说,Volume就是目录或者文件,它可以绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。


参考看了两本书中有关Volume的内容,发觉都只能重新构建一个容器来指定挂载目录,而并没有针对现在运行的容器挂载的。
于是想到了这样去解决线上现有容器的数据挂载问题。

1、构建(run)一个数据容器作为数据库存放,
构建完成后将之前备份出来的数据库文件,也就是/var/lib/mysql之中的文件复制到数据容器中,
停止运行数据容器以防浪费资源;

(或者构建的时候用creat也行)

2、构建一个mysql容器挂载使用数据库容器,因为之前都复制过去了,理论上和线上这个容器是一致的;

3、停止线上在运行中的生产mysql容器,因为后面构建的容器映射3306端口会有冲突;

4、wordpress再接新建的mysql容器,线上测试和以前别无二致之后,再同样做wordpress容器的数据容器化操作。

————————-实操如下—————————

1、docker run -it --name data -h wp_db -v /data centos /bin/bash
注:-it 为创建一个交互式的终端;
-h 为指定主机名字,hostname;
-v 挂载宿主机数据卷
后面接的/bin/bash只是方便用终端命令交互而已。
这种方式的卷是挂载在/var/lib/docker/volumes下面的一串长码的子目录下,缺点是找起来有点麻烦
但同时这种缺点也是一种优点,也就是没有那么容易误删除或被人为恶意破坏,另外似乎是双向同步的
与类似指明/data:/var/lib/mysql这种来说,Volume会复制到镜像目录,镜像不会复制到卷?单向同步?有待验证。
第二个优点是备份容易方便。

命令完成后,马上就进到交互终端(tty)模式了,测试touch生成一个txt文件,看在宿主机里能不能找到。

在第二个ssh的远程窗口宿主机内敲以下命令
docker inspect data #查看data容器的底层信息

会列出一大长段的信息,你要找到”Mounts”区块,其中会有个”Source”参数会告诉你volumes真正对应的宿主机物理路径。

ls查看(复制那一段长目录路径)volumes目录会看到容器内生成的txt文件在宿主机的目录下也会有产生。

同理,我在宿主机中拷贝文件过去。

在另一端容器内用ls查看,也是有此目录产生了

[root@wp-db data]# ls
mysql  test.txt

这样,就可以做数据卷共享了。
然而这个时候想到了我是要做mysql的数据库容器卷,理论上我应当使用数据库本身的镜像就好了。
而这边我用的是centos的镜像去做的。并且也没有使用echo来作为提示,而是使用了/bin/bash交互。

—————–参考———————-
数据库容器
常见的使用场景是使用纯数据容器来持久化数据库、配置文件或者数据文件等。官方的文档上有详细的解释。例如:
$ docker run --name dbdata postgres echo "Data-only container for postgres"

该命令将会创建一个已经包含在Dockerfile里定义过Volume的postgres镜像,运行echo命令然后退出。
当我们运行docker ps命令时,echo可以帮助我们识别某镜像的用途。

我们可以用-volumes-from命令来共享其它容器的Volume:
$ docker run -d --volumes-from dbdata --name db1 postgres

使用数据容器的两个注意点:
1、不要运行数据容器,这纯粹是在浪费资源。
2、不要为了数据容器而使用“最小的镜像”,如busybox或scratch,只使用数据库镜像本身就可以了。
你已经拥有该镜像,所以并不需要占用额外的空间

————–参考结束——————–

既然如此,我还是严谨点去分别做数据库容器和(wordpress)文件共享的数据容器吧。
刚好也要测试一下指定目录来做的volume。

1、docker run --name mysqldb -h wordpress_db -v /data/mysql_wp_db:/var/lib/mysql mysql echo "WordPress_DB for mysql"

成功生成,容器显示了提示后也自动停止了,毕竟作为数据容器并不需要浪费资源去运行。

使用docker inspect mysqldb 查看底层信息,会发现使用“宿主机目录:容器目录”这种volumes的方式后,不是以mounts挂载的方式了。
而是就成了Binds 捆绑连接的方式,理论上也是一样使用一样共享,不过还得测试是不是双向同步?

注意:因为之前定义的容器运行时候进程是echo,可以说是没办法再登录进此容器查看了,但我们可以用间接的办法去做到看到数据容器内的文件是否有效。
首先宿主机内先将mysql的数据CP一份到宿主机本身的/data/mysql_wp_db目录上,因为这也是数据容器的/var/lib/mysql目录。

cp -r /download/mysql/* /data/mysql_wp_db/ #复制mysql数据库去测试

2、docker run -d --volumes-from mysqldb --name mysqldb_backup mysql #再生成一个容器,使用的卷来自之前做为数据容器的mysqldb

docker exec -it f6b95 bash
这次的容器就会在运行状态,就可以exec的方式进到容器里面验证了。
ls 查看容器里的/var/lib/mysql ,得出的结果是生效了!不过这只是证明了宿主机往容器内同步,接下来要在容器里生成一些文件测试,容器内能不能反向同步回宿主机。

容器内touch test-file,然后宿主机内进/data/mysql_wp_db查看,同样有此文件,证明数据卷容器成功!

3、再来测试停掉原本线上运行的mysql容器,重新再开mysqldb2容器,且db2挂载上共享数据容器卷。

4、docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=FBi36#mon --volumes-from mysqldb --name mysqldb2 mysql
只比第一个线上的mysql容器多了一个参数--volumes-from mysqldb,然后wordpress的容器也不需要重新–link联接就已经可以读取到重开的这个db2容器的数据库了。

数据库数据储存问题是解决了,并且也不用太担心误删容器了,毕竟还有数据容器卷。

那么接下来要再解决的就是wordpress的数据问题了。

docker exec -it a3b2 bash #进入wordpress博客所在的容器交互查看验证

wordpress容器内/var/www/html目录就是我们需要保存的wordpress博客的目录、主题、媒体库等等的文件。

退出,但不停止容器
Ctrl+P+Q
开始copy文件
sudo docker cp 容器id:/path_in_container /path_on_host
也就是:docker cp a3b23:/var/www/html /data/wordpress

这里看到的权限因为是用root用户复制的,所以和容器内的www-data用户权限不一样,说不定设置挂载卷后得将权限也改改。

做wordpress的数据容器:和之前做mysql数据容器同理,直接使用原wordpree镜像去做就行了:
1、docker run --name wordpress_backup -h wordpress_backup -v /data/wordpress:/var/www/html wordpress echo "WordPress data backup"

停止线上在运行的wordpress容器,生成一个使用到前面wordpress_backup容器卷的新容器
2、docker run -d --volumes-from wordpress_backup --name wordpress2 --link mysqldb2:mysql -p 80:80 wordpress #(连接mysqldb2容器里的mysql程序)

再点击博客地址,如常。证明生效了。我线上传一个图片上去,再看宿主机/data/wordpress/wp-content/upload目录下有没有生成图片,权限正常不。

果然权限也是得注意的,考虑参照之前wordpress的用户名和用户组权限chown改变一下。

如上图,我们可以用简单的一行命令就可以做到查看参照回之前的最初镜像容器内的mysql用户和www-data用户的UID

docker run -ti --rm --entrypoint="/bin/bash" mysql -c "id mysql"

# -ti tty终端交互  --rm 这个参数是重点,是运行完此容器后马上rm删除掉,也就是不留痕的只看命令输出的结果,非常棒;

   --entrypoint="bin/bash" 也是重点,情形就等于你用exec 交互进bash,但这个方便多了,只是看结果没必要进容器退容器的;
   后接镜像,-c 看帮助文件似乎是和cpu有关?反正我理解成后面双引号要输的bash命令要先-c了。
   "id 用户名",linux中为查询用户的UID信息命令。效果从图中也看出来了。

添加www-data用户和mysql用户、-M不建立用户家目录,-s /sbin/nologin不允许登录系统,-u 指定uid(设置成和镜像内的一样)
接着用chown修改卷目录对应的属主,chmod修改对应的权限就不用多说了。
补充:理应属组也改为随着用户自行建立起的www-data组和mysql组为好。

如上图设置好后,在博客后台编辑文章和上传图片都正常了。

另外在宿主机中查看也能找到wordpress博客刚上传的图片。

这里的属组,由于我还没有新建www-data这个组,所以显示的是uid为33的组了。
无碍。强迫症可再进行创建www-data和mysql组的操作。嗯,我打算就这么做。
进行中发现此两组在建用户的时候就自动建立起来了……
后面使用gourpmod -g 33 www-datagourpmod -g 999 mysql将属组的gid改正过来,
并且重新chown -R 将两者的共享卷属组也改正过来。终于完美!告一段落,可以安心写博客了!

by:铁乐与猫

2017年8月

end

发表评论

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