docker 数据管理

2020-07-31 11:53:49 浏览数 (1)

如何在Docker内部以及内部容器之间管理数据

docker内的文件系统是如何工作的?

docker镜像被存储在一系列的只读层,当我们开启一个容器,docker读取只读镜像并添加一个读写层在顶部,如果正在运行的容器修改了现有的文件,该文件将被拷贝出底层的只读层到最顶层的读写层,在读写层中的旧版本文件隐藏于该文件之下,但并没有被破坏,它仍然存在于镜像一下,当docker的容器被删除时,然后重新启动镜像时,将开启一个没有任何更改的新的容器,这些更改会丢失,为了能够保存数据以及共享容器间的数据,docker提出了volumes的概念,volumes可以是目录或者文件,它们是外部默认的联合文件系统或者是存在与宿主文件系统正常的目录和文件。

为什么使用数据卷?

docker镜像是由一系列的只读层组合而来,当启动一个容器的时候,docker加载镜像的所有只读层,并在最上层加入一个读写层,这个设计使得docker可以提高镜像构建、存储、分发的效率,节省了时间和存储空间,但是也会存在如下的问题

  • 容器中的文件在宿主机上存在形式复杂,不能在宿主机上很方便的对容器中的文件进行访问
  • 多个容器之间的数据无法共享
  • 当删除容器时,容器产生的数据将丢失

为了解决这些问题,docker引入了volume数据卷。volume是存在一个或多个容器中的特定文件或文件夹,这个目录能够独立于联合文件系统的形式在宿主机中存在,并为数据的共享与持久化提供一下便利。

管理数据主要有两种方式:

  • 数据卷(Volumes)
  • 挂载主机目录(Bind mounts)

数据卷

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性:

  • 数据卷可以在容器之间共享和重用
  • 对数据卷的修改会立马生效
  • 对数据卷的更新,不会影响镜像
  • 数据卷默认会一直存在,即使容器被删除

创建数据卷

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

创建 [root@xs_test01 registry]# docker volume create my-vol my-vol 查看 [root@xs_test01 registry]# docker volume ls DRIVER VOLUME NAME local 719fc569772718a3df2fe95b3f6f459b12b5b52aa4a4c320a427d144e4dec715 local bc7502d4fa8a3303fd3aa769e40750e8e08b4474864a3989eb75228e7e3ce328 local e533c38fc38c56c4e22544fb9ad6c37feff91bb32eb43df16f9ad4363e12b79a local my-vol 查看数据卷信息 [root@xs_test01 registry]# docker volume inspect my-vol [ { "CreatedAt": "2018-03-14T16:19:10 08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/my-vol/_data", "Name": "my-vol", "Options": {}, "Scope": "local" }

启动一个挂载数据卷的容器

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

[root@xs_test01 service]# docker run -d -P --name web --mount source=my-vol,target=/webapp trainin g/webapp python app.py Unable to find image 'training/webapp:latest' locally latest: Pulling from training/webapp e190868d63f8: Pull complete 909cd34c6fd7: Pull complete 0b9bfabab7c1: Pull complete a3ed95caeb02: Pull complete 10bbbc0fc0ff: Pull complete fca59b508e9f: Pull complete e7ae2541b15b: Pull complete 9dd97ef58ce9: Pull complete a4c1b0cb7af7: Pull complete Digest: sha256:06e9c1983bd6d5db5fba376ccd63bfa529e8d02f23d5079b8f74a616308fb11d Status: Downloaded newer image for training/webapp:latest 3a4e21fff498fba70eb85ade5d0911289578382950ad0323615b6f138ed59ddd

查看数据卷的具体信息

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207

[root@xs_test01 service]# docker inspect web [ { "Id": "3a4e21fff498fba70eb85ade5d0911289578382950ad0323615b6f138ed59ddd", "Created": "2018-03-14T09:45:19.230218812Z", "Path": "python", "Args": [ "app.py" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 4773, "ExitCode": 0, "Error": "", "StartedAt": "2018-03-14T09:45:20.901061494Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557", "ResolvConfPath": "/var/lib/docker/containers/3a4e21fff498fba70eb85ade5d0911289578382950ad0323615b6f138ed59ddd/resolv.conf", "HostnamePath": "/var/lib/docker/containers/3a4e21fff498fba70eb85ade5d0911289578382950ad0323615b6f138ed59ddd/hostname", "HostsPath": "/var/lib/docker/containers/3a4e21fff498fba70eb85ade5d0911289578382950ad0323615b6f138ed59ddd/hosts", "LogPath": "/var/lib/docker/containers/3a4e21fff498fba70eb85ade5d0911289578382950ad0323615b6f138ed59ddd/3a4e21fff498fba70eb85ade5d0911289578382950ad0323615b6f138ed59ddd-json.log", "Name": "/web", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "", "ExecIDs": null, "HostConfig": { "Binds": null, "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": {}, "RestartPolicy": { "Name": "no", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "CapAdd": null, "CapDrop": null, "Dns": [], "DnsOptions": [], "DnsSearch": [], "ExtraHosts": null, "GroupAdd": null, "IpcMode": "shareable", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": true, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "ConsoleSize": [ 0, 0 ], "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DiskQuota": 0, "KernelMemory": 0, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": false, "PidsLimit": 0, "Ulimits": null, "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "Mounts": [ { "Type": "volume", "Source": "my-vol", "Target": "/webapp" } ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/a04e17161b883546358106a47157aae0dd2ad3a55ff176d1345bfbfbc9440fef-init/diff:/var/lib/docker/overlay2/681158ba5c9e8e6485b0f897a38990b6125c88f00fff918d00f410b15b1fb71b/diff:/var/lib/docker/overlay2/ead6441580a7da34d41ad067c67d74530924e2fbf774459a0aafad5fc0297615/diff:/var/lib/docker/overlay2/a58d33e716b44b5b732d9ac56c7caf6bd4093b4db0aa5de3bdcc2ba05a6592e9/diff:/var/lib/docker/overlay2/6a111fca256aa721ceec783ba474e476521011783e72490c708bb55d2fb8b936/diff:/var/lib/docker/overlay2/8d25e381a6795051ffbb78a5114d7bf806b882ecaec6853c680283ede01e70aa/diff:/var/lib/docker/overlay2/d0d8a213f485ee85f1649f7104a5be2b4352ce402032f082b37caf37c97232c1/diff:/var/lib/docker/overlay2/c88370da809a8fb49551c46fe0b6bae09d3ebc6e9ce7e6074fa688993b20e603/diff:/var/lib/docker/overlay2/a0617d1b376ebb0d7fcf30d0ba85d8e947d6760cd758aa4e3c246691222721c9/diff:/var/lib/docker/overlay2/cec5d529f500feb6082c454b59516dc68b701dd43f13689663a1e1b312f0bea4/diff:/var/lib/docker/overlay2/477de8444c1e46c305f59bc60bcb3dd5b51ad2de813cc6c396174589a7e5a31d/diff:/var/lib/docker/overlay2/5730c353dde2ba11167f462bf4da920383bcb521169b41ba4caa208529701fa8/diff:/var/lib/docker/overlay2/f32b8aed01afe6eb8ab5c3fb848eb9e24c5442cc9640fdd900cb81615c134e61/diff:/var/lib/docker/overlay2/775a4d083f6f803cf3c4b2c823ecb72fadbcccf7b1a847ce5a893b23a7714bbf/diff", "MergedDir": "/var/lib/docker/overlay2/a04e17161b883546358106a47157aae0dd2ad3a55ff176d1345bfbfbc9440fef/merged", "UpperDir": "/var/lib/docker/overlay2/a04e17161b883546358106a47157aae0dd2ad3a55ff176d1345bfbfbc9440fef/diff", "WorkDir": "/var/lib/docker/overlay2/a04e17161b883546358106a47157aae0dd2ad3a55ff176d1345bfbfbc9440fef/work" }, "Name": "overlay2" }, <span style="color: #ff0000;">"Mounts": [ { "Type": "volume", "Name": "my-vol", "Source": "/var/lib/docker/volumes/my-vol/_data", "Destination": "/webapp", "Driver": "local", "Mode": "z", "RW": true, "Propagation": "" } ],</span> "Config": { "Hostname": "3a4e21fff498", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "5000/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "python", "app.py" ], "Image": "training/webapp", "Volumes": null, "WorkingDir": "/opt/webapp", "Entrypoint": null, "OnBuild": null, "Labels": {} }, "NetworkSettings": { "Bridge": "", "SandboxID": "cb4c791d9c3e3331190524f52f1d1c17f5274e53f47a6749a47d7e31fcd71e0f", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": { "5000/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "32768" } ] }, "SandboxKey": "/var/run/docker/netns/cb4c791d9c3e", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "90106423c4bf3ee62f311a037d0f00db3557affee3dec2e505e3ed8c500deea7", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.4", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:04", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "e0e2d6ca4e6bcde38b489bab314e8840c9b9d9a6f602c601116b36470f77fb03", "EndpointID": "90106423c4bf3ee62f311a037d0f00db3557affee3dec2e505e3ed8c500deea7", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.4", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:04", "DriverOpts": null } } } } ]

删除数据卷

正在使用的数据卷不能删除,绑定挂载的数据卷不能删除

ddocker volume rm my-vol

因为数据卷是独立于容器的,docker不会在容器被删除之后自动删除数据卷,如果在删除容器的同时移除数据卷,清理可以使用docker volume prune

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

[root@xs_test01 docker]# docker volume prune WARNING! This will remove all volumes not used by at least one container. Are you sure you want to continue? [y/N] y Deleted Volumes: 6c38fb13e6688f80070fe7594d83ad7bbfcaa70229a13ea015e487bcf478ea21 1fe2eb4a3fbe21250d66f6f415c2ecbeb8e7ef69dcae8e5437589afba9ca8629 0a7f474b3a09772c299edf781177c93abb5c6ecbe63c749d25135e0639547979 383ee58e163f598b8a528a5bb6059632874cec1e4beb199cad2c26eeab4402a9 1bbf6d5fc5e3b90bb47d63393db2f2382101e2e2f88d3a4a8596f41834be4871 bc7502d4fa8a3303fd3aa769e40750e8e08b4474864a3989eb75228e7e3ce328 67fe3999a521d87629e32518c83028d6423f055aabe23f41169f34cbdbe5fbd9 18121affd4e94d4fec7bf38c5ab36cedba24972a2da0baaea688b07f4188a505 1d498a9198a66b987d0fbffc77d84e463b9aabe6ec96eb61da53f54b4b0b253a 719fc569772718a3df2fe95b3f6f459b12b5b52aa4a4c320a427d144e4dec715 e533c38fc38c56c4e22544fb9ad6c37feff91bb32eb43df16f9ad4363e12b79a Total reclaimed space: 184B [root@xs_test01 docker]# docker volume ls DRIVER VOLUME NAME local my-vol

挂载数据卷

使用--mount

1 2 3 4 5 6 7 8 9

[root@xs_test01 docker]# docker run -d --name web2 --mount type=bind,source=/src/webapp,target=/opt/webapp training/webapp python app .py docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist. See 'docker run --help'. [root@xs_test01 docker]# mkdir -p /src/webapp [root@xs_test01 docker]# docker run -d --name web2 --mount type=bind,source=/src/webapp,target=/opt/webapp training/webapp python ap p.py 3ceb1e19e996cd8305cb9b0cce4b5938134c4cd155a4805455717755d53a3217 #可以看出使用--mount挂载目录时,如果目录不存在,则会报错

也可以通过readonly参数来使所挂载的目录为只读目录,默认不加时为可读写。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

测试 [root@xs_test01 docker]# docker run -it -d -p 3333:3333 --name centos1 --mount type=bind,source=/src/webapp,target=/opt/webapp,readonly centos /bin/bash 8ef4bce12ebfda49a5bc3c0684a873b445a591e279e0026b53adaf0056aab870 [root@xs_test01 docker]# [root@xs_test01 docker]# [root@xs_test01 docker]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8ef4bce12ebf centos "/bin/bash" 4 seconds ago Up 2 seconds 0.0.0.0:3333->3333/tcp centos1 a7805164cee7 training/webapp "python app.py" 3 minutes ago Exited (2) 3 minutes ago web6 c99da3196e5a training/webapp "python app.py" 3 minutes ago Created web5 3ff50d7dec9a training/webapp "python app.py" 4 minutes ago Exited (2) 4 minutes ago web4 ec6fadc157f2 training/webapp "python app.py" 7 minutes ago Exited (2) 7 minutes ago web3 3ceb1e19e996 training/webapp "python app.py" 12 minutes ago Exited (2) 12 minutes ago web2 3a4e21fff498 training/webapp "python app.py" 21 hours ago Exited (137) 19 hours ago web eab05e17db69 registry "/entrypoint.sh /etc…" 25 hours ago Up 25 hours 0.0.0.0:5000->5000/tcp hopeful_bose 1cd1fadb254b ubuntu:17.04 "/bin/sh -c 'while t…" 28 hours ago Up 28 hours kind_wilson [root@xs_test01 docker]# docker exec -it 8ef4bce12ebf /bin/bash [root@8ef4bce12ebf /]# cd /opt/webapp/ [root@8ef4bce12ebf webapp]# touch 1 touch: cannot touch '1': Read-only file system

0 人点赞