DICOM:docker实现DICOM服务虚拟化之“数据卷”

Posted zssure

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DICOM:docker实现DICOM服务虚拟化之“数据卷”相关的知识,希望对你有一定的参考价值。

背景:

由于docker技术能够实现最大化应用隔离、且自身对资源损耗极低,甚至可以等同于进程,遂催生了希望将docker应用到DICOM服务开发领域。上一篇博文DICOM:docker实现DICOM服务虚拟化作为开篇,介绍了如何在docker容器内部安装DICOM运行环境(其实在这之前,也试玩过docker技术用来托管C-STORE服务DICOM:试玩Docker发布C-STORE SCP服务),其中提到了“环境变量”失效的问题。本篇继续科普docker应用中常见的问题,“数据持久化,即数据卷VOLUME”,为后续DICOM服务中文件存储做准备。

docker镜像与容器:

docker中最核心的概念当属image镜像和container容器,关于两者的对比介绍的资料很多,详情可以阅读文后的参考资料。这里通过个人学习经历,简单介绍一下自己的理解:

1. image镜像

image镜像 ,最开始听到 镜像” 这个概念是在安装操作系统时,接触最多的就是ISO光盘镜像,使用虚拟光驱(例如Daemon Tools Lite)可以完成系统安装。想必docker镜像与ISO文件类似,是一个静态文件,包含linux系统启动的核心模块。

2. container容器

延续上述概念,container容器就如同顺利安装后的系统,不同的是容器依托的不是ISO光盘镜像而是image镜像。启动后用户就可以自由操作容器,实现自己的应用。

简单对比看一下比较正式的docker镜像和docker容器的介绍:

Docker 镜像: Docker 镜像就是一个只读的模板。例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。镜像可以用来创建 Docker 容器。

Docker 容器:Docker 利用容器来运行应用。容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

大抵与我用ISO光盘镜像来类比相同,需要明确的是docker镜像(image)是静态的只读的,而docker容器(container)是动态的可读写的;若想深入了解两者的区别,以及两者是如何控制读写的,可参考文后的资料。

docker数据卷:

继续使用ISO光盘镜像类比docker镜像,照此类推,docker容器是我们安装完成后的操作系统,在系统中我们需要永久保留自己的数据,自然就会使用硬盘(在linux中通过mount的方式),那么如果想永久保存docker容器内的数据该怎么办呢?这就是数据卷的作用。由于初步涉猎docker,并未深入研究底层技术,因此本文从实践角度出发来学习VOLUME数据卷,详情可参考深入理解Docker Volume(一))。
为了更好的演示VOLUME创建的过程,清空之前本地的所有docker镜像和docker容器,重新导入从时速云下载的centos7原始镜像。如下图所示:


创建数据卷有两种方式,都需要通过docker run的-v参数来设定(当然还有一种在Dockfile的VOLUME来设定,这里暂不考虑)。

1. 创建数据卷(-v /data):

第一种方式,在docker run 的命令行中添加-v /data的方式来创建,此命令行的含义是将/data目录挂载到docker容器内。

docker run -d -v /data-volume 95fafe0db8000XXXX

参照Where are Docker images stored?的介绍,进入到/var/lib/docker目录下观察结果如下:

查看/containers/CONTAINER_ID/config.json文件,可知:

    "MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c244,c334",
    "MountPoints": 
        "/data-volume": 
            "Destination": "/data-volume",
            "Driver": "local",
            "Name": "a83e38d73545455bb669557dfc86f26b5e6608b25681be3f9f3596d6430b86d7",
            "RW": true,
            "Relabel": "",
            "Source": ""
        
    ,

由此可以看出使用-v /data-volume参数后,系统服务会在/var/lib/docker/volumes目录下自动创建一个文件夹(此处为/var/lib/docker/volumes/a83e38d73545455bb669557dfc86f26b5e6608b25681be3f9f3596d6430b86d7/_data),并将其挂载到docker容器内的data-volume目录下。
为了验证我们的想法,进入到宿主机的_data目录下,创建一个本地文件volume_dat_test_from_host,而后使用docker exec命令进入到容器内部进行查看:

由此验证了/var/lib/docker/volumes中对应目录文件与docker容器内部挂载目录data-volume的关系,正是通过该方式实现docker与宿主主机间数据的直接交互,这也正是数据卷的目的。
那么创建的数据卷是否会保存到镜像内部呢?与镜像之间有何种关系呢?我们继续试验下去:
将刚才创建数据卷的启动的容器提交为新的镜像,如下:

docker commit -a "zssure@163.com" -m "Test volume of docker" CONTAINER_ID zssure:cenots7-volume

随后直接启动该镜像,不添加任何-v参数。

进入到/var/lib/docker/containers容器内部查看新生成容器的config.json文件,同样可以看到

 "MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c271,c894",
    "MountPoints": 
        "/data-volume": 
            "Destination": "/data-volume",
            "Driver": "local",
            "Name": "8182abcb8a307d1b785a555c0ab92df66e618a3ae01185f494b00c1c68d1ab85",
            "RW": true,
            "Relabel": "",
            "Source": ""
        
    ,

此时宿主主机系统重新生成了一个数据卷文件挂载到docker新的容器,挂载点依然是/data-volume。由此可以得出的结论是:docker run -v参数绑定的数据卷通过docker commit指令后会提交到新的docker镜像文件中,下次启动后依然有效。

【但是:】由于系统会随机重新在本地生成对应的数据卷文件,因此在docker内部data-volume目录下为空。这里还是以ISO光盘镜像为例,每一次docker run指令可以认为是重装了一次系统,使用docker commit类似于ghost,重新生成了系统镜像。而VOLUME就是原本系统硬盘中的数据,ghost并不能把数据备份(当然ghost也可以用于备份数据)。

2. 创建数据卷(-v /host_dir:/docker_dir):

上面第一种方式系统是随机将本地/var/lib/docker/volumes目录下挂载到docker容器内部。现在介绍第二种方式,将宿主主机特定目录挂载到容器内部,详情如下:

docker run -d -v /home/zssure/Desktop/docker_volume_test:/volume_map_from_host --privileged=true IMAGEID

此时我们看一下container对应目录下的config.json文件内容,

 "MountPoints": 
        "/volume_map_from_host": 
            "Destination": "/volume_map_from_host",
            "Driver": "",
            "Name": "",
            "RW": true,
            "Relabel": "",
            "Source": "/home/zssure/Desktop/docker_volume_test"
        
    
    ....
    "Volumes": 
        "/volume_map_from_host": "/home/zssure/Desktop/docker_volume_test"
    ,
    "VolumesRW": 
        "/volume_map_from_host": true
    

至此与第一种方式很像,将宿主主机的固定目录挂在到docker容器内部,从而实现数据共享。
同样我们使用docker commit来保存此刻的镜像,如下所示:

再一次重启上述创建的镜像centos7-volume-mapper,依然可以看到volume_map_from_host,其内容为空。

此时再次查看container内部的config.json文件,如下:

    "MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c324,c913",
    "MountPoints": 
    "Volumes": ,
    "VolumesRW": 

总结:

至此对比两种创建VOLUME数据卷的方法,可以看出第一种创建的数据卷在commit提交后会保存到镜像中,即使在下一次docker run命令行启动中没有添加-v参数,系统依然会在宿主主机随机创建一个目录挂载到之前的数据卷的挂载目录下;而第二种方法虽然commit提交后会保留docker容器内部的挂载点目录,但是下一次启动命令行中如果未使用-v参数,此刻docker容器与宿主主机之间是没有任何数据卷沟通的

参考资料:

  1. Where are Docker images stored?
  2. Docker解析:数据卷(Data Volume)的实现
  3. 深入理解Volume
  4. 深入理解Docker Volume(二)
  5. Docker In-depth: Volumes
  6. mount到非空目录
  7. 官方docker data volume
  8. 剖析Docker文件系统:Aufs与Devicemapper



    作者:zssure@163.com
    时间:2015-12-29

以上是关于DICOM:docker实现DICOM服务虚拟化之“数据卷”的主要内容,如果未能解决你的问题,请参考以下文章

DICOM:docker实现DICOM服务虚拟化

DICOM:Docker实现增量发布之前期准备

DICOM医学图像处理:fo-dicom网络传输之 C-Echo and C-Store

DICOM:DICOM开源库多线程分析之“ThreadPoolQueue in fo-dicom”

DICOM:DICOM开源库多线程分析之“ThreadPoolQueue in fo-dicom”

DICOM:DICOM开源库多线程分析之“ThreadPoolQueue in fo-dicom”