1.什么是数据卷volume
为了了解什么是Docker Volume,首先我们需要明确Docker内的文件系统是如何工作的。Docker镜像被存储在一系列的只读层。当我们开启一个容器,Docker读取只读镜像并添加一个读写层在顶部。如果正在运行的容器修改了现有的文件,该文件将被拷贝出底层的只读层到最顶层的读写层。在读写层中的旧版本文件隐藏于该文件之下,但并没有被不破坏 - 它仍然存在于镜像以下。当Docker的容器被删除,然后重新启动镜像时,将开启一个没有任何更改的新的容器 - 这些更改会丢失。此只读层及在顶部的读写层的组合被Docker称为Union File System(联合文件系统)。
为了能够保存(持久)数据以及共享容器间的数据,Docker提出了Volumes的概念。很简单,volumes是目录(或者文件),它们是外部默认的联合文件系统或者是存在于宿主文件系统正常的目录和文件。
2.为什么使用数据卷volume
Docker的镜像是由一系列的只读层组合而来,当启动一个容器的时候,Docker加载镜像的所有只读层,并在最上层加入一个读写层。这个设计使得Docker可以提高镜像构建、存储和分发的效率,节省了时间和存储空间,然而也存在如下问题。
(1)容器中的文件在宿主机上存在形式复杂,不能在宿主机上很方便的对容器中的文件进行访问
(2)多个容器之间的数据无法共享
(3)当删除容器时,容器产生的数据将丢失
为了解决这些问题,Docker引入了数据卷(volume)机制。volume是存在一个或多个容器中的特定文件或文件夹,这个目录能够独立于联合文件系统的形式在宿主机中存在,并为数据的共享与持久提供一下便利。
(1)volume在容器创建时就初始化,在容器运行时就可以使用其中的文件
(2)volume能在不同的容器之间共享和重用
(3)对volume中的数据的操作会马上生效
(4)对volume中数据操作不会影响到镜像本身
(5)volume的生存周期独立于容器的生存周期,即使删除容器,volume仍然会存在,没有任何容器使用的volume也不会被Docker删除
3.如何使用数据卷
3.1 从容器挂载volume(-v /path)
在使用docker run创建新容器的时候,可以使用-v 标签为容器添加数据卷volume,以下用法是从容器中的某个文件夹创建volume,如果容器中指定的文件夹不存在,会自动生成

在上面的概念中,有说道,宿主机应该会有一个文件夹绑定挂载到容器中的volume挂载点,那默认的宿主机上的文件夹在哪呢,使用docker inspect命令,查看下容器详情(CRT令起一个SSH终端)
[root@localhost ~]# docker inspect volume-test01
[
{
"Id": "81a74152e6f45a3f780ac7cdc37c9a089814f9a70aad1d27747093ca3c3dae3e",
"Created": "2016-08-25T07:48:55.942949334Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 10199,
"ExitCode": 0,
"Error": "",
"StartedAt": "2016-08-25T07:48:56.777918888Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:4fd21defa24c8c07b3689b267a63d563ca0e26ef931b329fc3f3d46efb5bba2d",
"ResolvConfPath": "/var/lib/docker/containers/81a74152e6f45a3f780ac7cdc37c9a089814f9a70aad1d27747093ca3c3dae3e/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/81a74152e6f45a3f780ac7cdc37c9a089814f9a70aad1d27747093ca3c3dae3e/hostname",
"HostsPath": "/var/lib/docker/containers/81a74152e6f45a3f780ac7cdc37c9a089814f9a70aad1d27747093ca3c3dae3e/hosts",
"LogPath": "",
"Name": "/volume-test01",
"RestartCount": 0,
"Driver": "devicemapper",
"MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c47,c332",
"ProcessLabel": "system_u:system_r:svirt_lxc_net_t:s0:c47,c332",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "journald",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"ShmSize": 67108864,
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": null,
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"KernelMemory": 0,
"Memory": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": -1,
"OomKillDisable": false,
"PidsLimit": 0,
"Ulimits": null
},
"GraphDriver": {
"Name": "devicemapper",
"Data": {
"DeviceId": "29",
"DeviceName": "docker-253:0-101330881-9cb32851050b1707022b475489686582a272d883a56a8ff52f3344f56b65639f",
"DeviceSize": "10737418240"
}
},
"Mounts": [
{
"Name": "5ddd734c53a38a78a9f739157c63074b4aff736d4045925616d7753402304137",
"Source": "/var/lib/docker/volumes/5ddd734c53a38a78a9f739157c63074b4aff736d4045925616d7753402304137/_data",
"Destination": "/opt/vol-data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "81a74152e6f4",
"Domainname": "",
"User": "",
"AttachStdin": true,
"AttachStdout": true,
"AttachStderr": true,
"Tty": true,
"OpenStdin": true,
"StdinOnce": true,
"Env": null,
"Cmd": [
"/bin/bash"
],
"Image": "test/mycentos:v1.0",
"Volumes": {
"/opt/vol-data": {}
},
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "c73841812aab480cf8e6a02071e36951dceb002d7b36f7dc0b38ccd9db833ba5",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/c73841812aab",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "3e492b611d9bd2c202c8a6c8fe4b4a755393545348b1aeb4e60995609dabb07c",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "54001aaff29a231c9b2fe83459805d99dce0c21d6e2719f9b11bc90d8fe2f9c9",
"EndpointID": "3e492b611d9bd2c202c8a6c8fe4b4a755393545348b1aeb4e60995609dabb07c",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02"
}
}
}
}
]
注意看Mounts节点(Docker的版本用的是1.10.3),数据卷的使用,类似于 Linux 下对目录或文件进行 mount。
"Mounts": [
{
"Name": "5ddd734c53a38a78a9f739157c63074b4aff736d4045925616d7753402304137",
"Source": "/var/lib/docker/volumes/5ddd734c53a38a78a9f739157c63074b4aff736d4045925616d7753402304137/_data",
"Destination": "/opt/vol-data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]

当我们在容器的volume上操作时,宿主机上对应的文件是否也会跟着变动呢?测试

