前言、Docker中的数据管理
Docker镜像是由多个只读层叠加而成,启动容器时,Docker会加载只读层并会在镜像栈顶部添加一个读写层,如果运行中的容器修改了现有的一个文件,那么该文件就会从只读层复制一份到读写层中,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,这就是docker的写时复制机制。关闭重启容器,其数据不受影响,但是删除容器时,其改变的读写层数据就会丢失。
容器在运行项目时会产生数据,比如运行的mysql容器,那么一定会有数据的产生,那么问题来了,数据是保存在容器内部还是保存在外部?如果将数据保存在内部,那么也就意味着我们改变了原有镜像,这种做法是不可取的,因为在后期的镜像升级将变得不可能了。除非我们在改变镜像后commit提交打成一个新的镜像。显然,数据是应该保存在容器的外部,也就是说保存在主机上。那么问题又来了,数据保存在主机上,那么容器该如何读取主机中的数据呢?
为了能够持久化数据以及共享容器间的数据,Docker提出了Volume的概念。简单来说,Volume就是目录或者文件,它可以绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。
容器中管理数据主要有两种方式:
- 数据卷(Data volumes):容器内数据直接映射到本地主机环境
- 数据卷容器(Data Volume Containers):使用特定容器维护数据卷,数据卷容器挂载数据卷,其他容器通过挂载数据卷容器实现数据传递共享
一、数据卷的概念
数据卷就是由docker挂载到容器中的目录或者文件,但是不属于UnionFS。数据卷的生命周期完全独立于容器,docker不会在容器被删除时而删除其挂载的数据卷,因此可以实现持久化或共享数据。
特点:
- 数据卷可以在不同容器之间共享或重用数据
- 数据卷中的更改直接生效
- 数据卷中的更改不会包含在镜像的更新之中
1-1、创建容器时添加数据卷
数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似于linux中的mount操作。在create或者run容器时,可以通过-v参数指定主机的目录,挂载到容器中的某一个目录上,这样,容器就在这个目录读写数据了。从而实现了容器和数据的分离。例如:
docker run --name 容器名 -v /宿主机绝对路径:/容器内路径 镜像名
docker run -p 3306:3306 --name mymysql -v $PWD/conf:/etc/mysql/conf.d -v $PWD/logs:/logs -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql
二、Docker实战案例五:Docker安装MySQL实现宿主机和容器之间的数据共享
2-1、查找镜像
docker search mysql
2-2、拉取镜像
docker pull mysql
默认拉取tag为latest的mysql官方镜像
latest: Pulling from library/mysql
683abbb4ea60: Pull complete
0550d17aeefa: Pull complete
7e26605ddd77: Pull complete
9882737bd15f: Pull complete
999c06ab75f6: Pull complete
c71d695f9937: Pull complete
c38f847c1491: Pull complete
5e0cb05a8fc3: Pull complete
c89e3e373fca: Pull complete
fa39a2c9922d: Pull complete
b293d9c897c4: Pull complete
3dc061869740: Pull complete
Digest: sha256:43ed4f8c9d1695e97a39cdfe9475af9096e3723cfb79d820d8da00d61a277a85
Status: Downloaded newer image for mysql:latest
2-3、创建容器
新建本地映射到docker镜像的mysql文件目录,/mysql/conf、/mysql/logs、/mysql/data。
使用如下命令将提前创建好的/mysql/conf、/mysql/logs、/mysql/data挂载到容器中MySQL对应的目录中:
docker run -p 3306:3306 --name mymysql -v $PWD/conf:/etc/mysql/conf.d -v $PWD/logs:/logs -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql
2-4、查看并验证
查看MySQL容器是否正常运行:
进入容器内部并进入MySQL:
三、数据卷容器
如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门用来提供数据卷供其他容器挂载。如果要授权一个容器访问另一个容器的Volume,我们可以使用--volumes-from参数来实现。可以使用数据卷容器对其中的数据卷进行备份、恢复、以实现数据的迁移。
首先创建一个数据卷容器dbdata,并在其中创建一个数据卷挂载到/dbdata。
//创建一个数据卷容器
[root@xxx ~]# docker run -it -v /dbdata --name dbdata ubuntu
//查看目录
root@d4bb57243d45:/# ls
bin boot dbdata dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
然后,可以在其他容器中使用--volumes-from来挂载dbdata容器中的数据卷,例如创建db1和db2两个容器,并从dbdata容器挂载数据卷:
// 创建2个容器挂载dbdata容器中的数据卷
[root@xxx ~]# docker run -it --volumes-from dbdata --name db1 ubuntu
[root@xxx ~]# docker run -it --volumes-from dbdata --name db2 ubuntu
此时,容器db1和容器db2都挂载同一个数据卷到相同的dbdata目录。三个容器任何一方在该目录下的写入,其他容器都可以看到。例如,在dbdata容器中创建一个test文件,在db1容器中可能查看到它:
//在dbdata容器的数据卷中创建文件a
root@9e90f695bcb8:/dbdata# touch a
root@9e90f695bcb8:/dbdata# ll
total 4
drwxr-xr-x. 2 root root 14 Apr 14 10:02 ./
drwxr-xr-x. 22 root root 4096 Apr 14 10:01 ../
-rw-r--r--. 1 root root 0 Apr 14 10:02 a
//在db1容器中查看数据卷目录dbdata,也发现了文件a
root@ab4426a23cb4:/dbdata# ll
total 4
drwxr-xr-x. 2 root root 6 Apr 14 10:01 ./
drwxr-xr-x. 22 root root 4096 Apr 14 10:02 ../
root@ab4426a23cb4:/dbdata# ls
a
//db2结果和db1一样
root@b4bea0f56613:/# cd dbdata/
root@b4bea0f56613:/dbdata# ll
total 4
drwxr-xr-x. 2 root root 14 Apr 14 10:02 ./
drwxr-xr-x. 22 root root 4096 Apr 14 10:03 ../
-rw-r--r--. 1 root root 0 Apr 14 10:02 a
可以多次使用--volumes-from参数来从多个容器挂载多个数据卷。还可以从其他已经挂载了容器卷的容器来挂载数据卷。
使用--volumes-from参数所挂载数据卷的容器自身并不需要保持在运行状态。如果删除了挂载容器(包括dbdata、db1和bd2),数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显示使用docker rm -v命令来指定同时删除关联的数据卷。