笔者在上篇学习docker的笔记中学习理解并归纳了容器命令,镜像原理以及镜像commit。在这篇笔记中,笔者将会学习记录容器数据卷的原理以及命令。Docker中的数据可以存储在类似于虚拟机磁盘的介质中,在Docker中称为数据卷(Data Volume)。数据卷可以用来存储Docker应用的数据,也可以用来在Docker容器间进行数据共享。数据卷呈现给Docker容器的形式就是一个目录,支持多个容器间共享,修改也不会影响镜像。使用Docker的数据卷,类似在系统中使用 mount 挂载一个文件系统。
容器数据卷
Docker将运用与运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对数据的要求希望是持久化的。容器之间希望有可能共享数据。Docker容器产生的数据,如果不通过Docker commit生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据就没有了。为了能保存数据,在Docker中,我们使用了卷。我们可以用Redis里面的rdb和aof文件来形容容器数据卷,容器数据卷就类似于Docker中的rdb和aof文件,主要用来数据共享以及数据持久化操作。
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的是数据的持久化,完全独立于容器的生存周期,因此Docker不会再容器删除时删除其挂载的数据卷。
那么容器数据卷有什么特点呢?
- 数据卷可以在容器之间共享或重用数据
- 卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期会一直持续到没有容器使用它为止
- 它可以使容器持久化
- 容器间的继承以及共享数据
如何去添加容器卷呢?
有两种方式:
- 直接命令添加
- DockerFile添加
命令docker run -it -v/宿主机绝对路径目录:/容器内目录 镜像名
v是卷的英文缩写。
可以看到文件根目录下的所有东西,并且没有我们想要的myDataVolume,我们可以待会儿新建一个,那么这个myDataVolume就是我们宿主机的绝对路径目录。那么容器内目录就是dataVolumeContainer。
我们先登录ubuntu镜像,可以看到,在文件根目录下并不能找到dataVolumeContainer。
$ docker run -it -v /myDataVolume:/dataVolumeContainer ubuntu
那么我们输入该命令,相当于插一个活动硬盘实现容器和主机之间数据共享。
可以看到生成了06a26ca52a24,这个是我们的容器。那么我们去根目录下去搜索,可以发现myDataVolume已创建成功。
我们可以使用如下命令查看其中内容。
$ ls -d /myDataVolume
此时,我们可以看到容器和主机之间的对接。
我们首先查看是否挂载成功,我们可以再启动一个终端来验证。
我们可以看到已经成功绑定。RW是读写的意思,我们现在可以对其进行读写操作。
那么容器和宿主机之间数据共享又是怎么样的呢?
我们先在/myDataVolume中主机建一个新文件。那么接下来,我们到容器中查看,发现容器中已经存在了这些数据。
那么我们修改一下host.txt这个文件,笔者发现docker的ubuntu中并没有安装vi和vim的包,因此笔者使用如下命令进行下载和更新。
apt update
apt-get install -y vim
下载完成后,我们就可以使用vi命令了。输入以下命令
$vi host.txt
进入编辑页面
在里面输入container update 01是可以的,按esc :wq保存退出。
然后我们再touch container.txt
在容器内修改了主机的文件,那么我再到主机去查看文件。
可以看到,container update 01可以被读取到。
容器停止退出后,主机修改后数据是否同步?
我们先用exit退出停止容器,并查看当前运行的容器,虽然容器停止了,但是主机还仍在运行。
我们创建一个新的文件host02,并对container.txt中的内容进行编辑。
那么我主机上有了个host02,现在启动容器能不能进行同步?
首先,我们先使用docker ps -l命令查看上一次运行的容器ID。
我们可以看到尾号为f411的就是我们上一次运行的容器。
$ docker start 9f1e1960f411
我们启动容器后,用docker ps查看一下。
可以看到这个容器就是我们上一次启动的容器,用attach命令进入容器。
再使用cd命令,在其dataVolumeContainer目录下能看到host02.txt
可以看到,即使是文件中的数据也与主机同步了。因此,数据之间的同步拉取就此实现。容器停止退出后,主机修改后数据完全同步。
命令(带权限)
docker run -it -v/宿主机绝对路径目录:/容器内目录:ro镜像名
以之前的示例为例子,我们可以输入命令
$ docker run -it -v /myDataVolume:/dataVolumeContainer:ro
我们先回到上一层,将myDataVolume删光。然后我们去容器内输入命令ll看一下情况。
可以看到,里面的总量为0。再次查询容器目录,发现文件夹并没有删掉
现在我们停止并退出容器。我们输入命令
可以看到我们又进入一个容器,输入ll,并且进入dataVolumeContainer,发现只有这两个文件。
那么我们进入到主机
可以看到,也只有这两个文件。那么我们重复之前的步骤创建host文件。我们使用vim命令往host.txt中加入host update。
我们可以看到主机里有文件,且里面有host update。此时,我们去容器内查看。
此时已经存在了host.txt以及它的内容,但是我们使用touch container.txt命令时会发现不能写操作,因为它是一个只读文件。并且通过vi/vim不能对其进行修改。只允许主机单向修改。
Docker file添加
类似于java中的 Hello.java ------- Hello.class
Docker中的 images --------- DockerFile
首先,登录根目录下新建mydocker文件夹并进入。
输入mkdir /docker建立一个目录,然后用cd命令打开它。
可在Dockerfile中使用VOLUME指令来给镜像添加一个或者多个数据卷。
VOLUME["/dataVolumeContainer","/dataVolumeContainer2","/dataVolumeContainer3"]
说明:由于可移植和分享考虑,用-v主机目录:容器目录这种方法不能够直接在Dockerfile中实现。由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有宿主机上都存在这样的特定目录。
用vim打开文档,输入图中命令,并且保存文档。
输入以下命令去创建文档
$ docker build -f /mydocker/Dockerfile -t cccc/ubuntu .
我们成功构建了一个镜像。
可以看到我们的镜像创建成功了,那我们直接进行运行。
我们运行一下,会发现里面已经有dataVolumeContainer1和dataVolumeContainer2了。
那么通过上述步骤以后,容器内的卷目录地址对应的主机目录地址在哪?
用cd命令进入/dataVolumeContainer1的目录,再创建一个container1.txt的文档。那么我们在容器内建了,我们去哪找主机目录呢呢?
新开一个终端,查询正在运行的容器,并且用inspect去查看内部信息
可以看到这两个容器的RW,也就是读写都是True。
而source后面显示的一长串则代表本地机器宿主机上的。那么我们再打开一个终端。
用cd打开这一长串的地址以后,用ll遍历里面的东西,可以发现这个container1.txt就在里面,这就实现了宿主机到容器,容器到宿主机之间的共享。
我们touch host.txt再到容器中去寻找。
此时,我们可以发现主机和容器都包含这两个文件。
如果遇到Docker挂载主机目录Docker访问出现cannot open directory .:Permission denied这个问题时。
解决办法:在挂载目录后多加一个–privileged=true参数即可。
数据卷容器
命名的容器挂载数据卷。其他容器通过挂载这个(父容器)实现数据共享,挂在数据卷的容器,称之为数据卷容器。
我们以我们上一步新建的镜像cccc/ubuntu为模板并运行容器dc01/dc02/dc03。
重复之前的步骤,我们在dataVolumeContainer2中创建一个dc01_add.txt文档
此时我们使用ctrl + P + Q 退出,我们可以看到dc01正在运行着,那么我们的父容器就准备好了。
接下来我们写dc02和dc03继承它。
我们可以发现在dataVolumeContainer2中也有dc01_add.txt
建立一个dc02_add.txt然后退出。
那么我们在3之中进行查看。
可以看到这里已经有dc01和dc02了,那么与之前一样,我们touch dc03_add.txt然后退出。
我们用ps命令看一下,发现这三个都在运行。那么3中的东西会不会影响1和2呢?
进去以后我们可以发现,容器卷达到了继承和共享传递的目的,父到子,子到父都能互相传递。
那么我们删除dc01后,doc02修改后dc03可否继续访问?
进入dc02,并在里面创建一个dc02_update.txt文档。那么我们之前用的是2和3继承1,我们可以发现实际上2并没有受到影响,那么3也不会受到影响。那么我现在在2上面修改了,在3上面会有什么影响吗。
我们可以看到,存在dc02_update.txt,因为数据共享是一直存在的。我们可以新建dc04继承dc03后再删除dc03,dc04依旧有这些信息。所以容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。