【Docker】进阶之路:(十一)Docker存储

【Docker】进阶之路:(十一)Docker存储

  • Docker存储简介
  • storage driver
  • data volume
    • volume
    • bind mount
    • tmpfs mount

Docker提供了4种存储方式:默认存储、volume(数据卷)、bind mounts(绑定挂载)、tmpfsmount(仅在Linux环境中提供)。其中volume、bind mounts两种存储方式实现持久化容器数据。持久化存储系统的功能是将各种服务在运行过程中产生的数据长久地保存下来,即使容器被销毁,数据也仍然存在。

Docker存储简介

Docker为容器提供两种存放数据的资源,分别是由storage driver管理的容器层和镜像层、data volume存储卷。也就是说,容器的存储可以分为两大类:一种是与镜像相关的,在容器内创建的所有文件都存储在可写容器层上,这种直接将文件存储在容器层的方式,数据难以持久化和共享。由于依赖存储驱动与使用直接写入主机文件系统的数据卷相比,这种额外的抽象会降低性能;另一种是宿主机存储,即通过将宿主机目录绑定或挂载到容器中使用,容器停止后数据也能持久化。

Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层。如果运行中的容器修改了现有的一个已经存在的文件,那么该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本依然存在,只是已经被读写层中该文件的副本所隐藏,这就是“写时复制(COW,Copy-On-Write)”机制。对于这种方式来说,我们去访问一个文件,修改和删除等一类的操作,由于隔着很多层镜像,效率会非常低。而要想绕过这种限制,我们可以通过使用存储卷的机制来实现。

数据卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立绑定关系。这就意味着,当我们在容器中的这个目录下写入数据时,容器会将其内容直接写入宿主机上与此容器建立了绑定关系的目录。在宿主机上与容器形成绑定关系的目录被称作数据卷。

使用数据卷的好处是,如果容器中运行的进程的所有有效数据都保存在数据卷中,从而脱离容器自身文件系统之后,那么当容器关闭甚至被删除时,只要不删除与此容器绑定的、在宿主机上的这个存储目录,就不用担心数据丢失了。因此,数据卷可以脱离容器的生命周期,实现数据持久化存储。

通过数据卷的方式管理容器,容器就可以脱离主机的限制,可以在任意一台部署了Docker的主机上运行容器,而其数据则可以置于一个共享存储文件系统上,比如NFS服务器。

Docker的数据卷默认情况下使用的是它所在的宿主机上的本地文件系统目录,也就是说宿主机上有一块属于自己的硬盘,这个硬盘并没有共享给其他的Docker主机,而在这台主机上启动的容器所使用的数据卷是关联到此宿主机硬盘上的某个目录之下。这就意味着容器在这台主机上停止运行或者被删除了再重建,只要关联到硬盘上的这个目录下,那么其数据还存在;但如果在另一台主机上启动一个新容器,那么数据就没了。而如果在创建容器的时候,我们手动将容器的数据挂载到一台NFS服务器上,那么这个问题就解决了。

storage driver

容器由最顶层的可写容器层以及若干只读的镜像层组成,容器的数据就存放在这些层中。这种分层结构的特点如下:

  • 新数据会直接存放在最顶层的容器层。
  • 修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变。
  • 如果多个层中有名称相同的文件,那么用户只能看到最上面那层中的文件。

镜像的分层结构使得镜像和容器的创建、共享以及分发变得非常高效,而这些都要归功于Docker storage driver(存储驱动)。正是storage driver实现了多层数据的堆叠,并为用户提供一个单一的合并之后的统一视图。Docker支持多种storage driver,有AUFS、Device Mapper、Btfs、OverlayS、VFs和ZFS。它们都能实现分层的架构,同时又有各自的特性,需要根据应用的实际场景,选择合适的storage driver。Ubuntu默认使用AUFS,底层文件系统是etfs,各层数据存放在/var/ib/docker/aufs。对于无状态的应用容器,直接将数据存放在由storage driver维护的层中是很好的选择,无状态意味着容器没有需要持久化的数据,随时可以从镜像中直接创建。
但对于有持久化数据的需求的应用,这种方式就不合适了,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据,这就要用到Docker的另一种存储机制data volume。

data volume

data volume(数据卷,也称为存储卷)本质上是宿主机文件系统中的目录或文件,能够直接被mount到容器的文件系统中。设计数据卷的目的就是让数据的持久化完全独立于容器的生命周期,因此Docker不会在容器被删除时删除其挂载的数据卷。数据卷是一个可供容器使用的特殊目录,它可以绕过文件系统提供很多有用的特性:

  • 数据卷可以在容器之间共享和重用数据。
  • 数据卷是目录或者文件,而不是没有格式化的磁盘。
  • 对数据卷的修改会立刻生效。
  • 对数据卷的更新不会影响镜像。
  • 数据卷会一直存在,直到没有容器使用为止。

Docker提供四种存储方式:默认存储、volume(数据卷)、bind mount(绑定挂载)、tmpfs mount(仅在Linux环境中提供),其中volume、bind mount两种存储方式实现持久化容器数据。

  • 默认存储:数据保存在运行的容器中,容器被删除后,数据也随之删除。默认方式是容器管理自己的数据,容器文件系统实际是一系列只读文件层和最上层的容器可写文件层组成,最上层的容器可写文件层保留容器运行过程中产生的所有数据及修改,可写文件层的管理是利用容器的storage driver实现的(默认是Overlay2,可以通过Docker的dameon.json配置文件修改),对容器内部文件系统是透明的。由于容器在文件系统之上又封装了一层storage driver,性能比不上volume或bind,因此不建议在生产环境使用默认存储方式。
  • volume:数据存放在主机文件系统/var/lib/docker/volumes/目录下,该目录由Docker管理,不允许其他进程修改,推荐该种方式持久化数据。
  • bind mount:直接挂载主机文件系统的任何目录或文件,类似主机和容器的共享目录,主机上任何进程都可以访问修改,在容器中也可以看到修改,这种方式最简单。
  • tmpfs:数据暂存在主机内存中,不会写入文件系统。主机重启后,数据将被删除。
    在这里插入图片描述

volume

volume适合在多个容器间共享数据的场景中使用。当无法确保Docker主机一定拥有某个指定的文件夹或目录结构时,使用volume可以屏蔽这些宿主机差异。当需要将数据存储在远程主机或云服务上,或者是备份、恢复或从一台Docker主机迁移数据到另一台Docker主机时,可以选择使用volume。

volume由Docker创建和管理,可以使用docker volume create命令显式地创建数据卷,或者在容器创建时创建数据卷。

[root@docker ~]# docker volume create nginx_volume
nginx_volume
[root@docker ~]# docker inspect nginx_volume
[{"CreatedAt": "2023-12-09T23:42:02+08:00","Driver": "local","Labels": null,"Mountpoint": "/var/lib/docker/volumes/nginx_volume/_data","Name": "nginx_volume","Options": null,"Scope": "local"}
]
[root@docker ~]# 

可以看到挂载点处于Docker的根目录/var/lib/docker/volumes下。
通过docker volume rm/prune命令清除单个或所有未再使用的数据卷。对比绑定挂载bind mount来说,可以通过docker命令来管理数据卷是一个优势。

[root@docker ~]# docker volume ls
DRIVER    VOLUME NAME
local     f484042048a8c1cb156be0068e554bc81fb65bc6a393ae15a4bad895c2829150
...
local     fd5e826f2d1a0b3e78ff89f0cf3fedf4ed87aceb0feaa8b5c4051ec0ed736dda
local     nginx_volume
[root@docker ~]# docker volume prune
WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
2990ceb30cd33dd5486d27615e910d43f204311268f3b8f990b787f6486e03dc
...
f484042048a8c1cb156be0068e554bc81fb65bc6a393ae15a4bad895c2829150
8ffd3faac7d6635f8e41b54d8cfcf0a17612a254d1102730038265a8274b823bTotal reclaimed space: 338B
[root@docker ~]# 

在创建容器时,如果未指定容器挂载的源,则Docker会自动创建一个匿名数据卷,也是位于Docker根目录下。

[root@docker ~]# docker run -dit -v /usr/share/nginx/html --name nginx_with_volume nginx
4e35c9fa57d097cc23691164f0dcb8a49f31c2919fb09933519c8ecc8b10a2bc
[root@docker ~]# docker volume ls
DRIVER    VOLUME NAME
local     047d04f24e43ce6f7d69221c06cfcd74361cda4ded9e1c133c726d63ae8760e2
local     nginx_volume
[root@docker ~]# ls /var/lib/docker/volumes/
047d04f24e43ce6f7d69221c06cfcd74361cda4ded9e1c133c726d63ae8760e2  metadata.db
backingFsBlockDev                                                 nginx_volume
[root@docker ~]# 

当挂载数据卷之后,此时的存储与bind mount一致。不过当Docker主机不能保证具有给定的目录或文件结构时,数据卷可协助将Docker主机的配置与容器运行时分离。这样一来当需要将数据从一台Docker主机备份、还原或迁移到另一台主机时,数据卷就很方便了,可以避免主机与容器的耦合。
在使用绑定挂载和数据卷时需要注意以下传播覆盖原则

  • 绑定挂载一个空数据卷时:容器内目录的内容会传播(复制)到数据卷中。
  • 绑定挂载非空数据卷时:容器内目录的内容会被数据卷或绑定的主机目录覆盖。

在这里插入图片描述

bind mount

通过bind mount可以在宿主机和容器间共享配置文件。例如,将nginx容器的配置文件保存在宿主机上,通过bind mount后就不用进入容器来修改nginx的配置了。
在宿主机和容器间共享代码或者build输出。例如,将宿主机某个项目的target目录挂载到容器中,这样在宿主机上Maven build一个最新的产品,可以直接在容器中运行,不需要生成一个新的镜像。Docker主机上的文件或目录结构是确定的。

注意bind mount和volume行为上的差异。若将一个空volume挂载到一个非空容器目录上,那这个容器目录中的文件会被复制到volume中,即容器目录原有文件不会被volume覆盖。若使用hind mount将一个宿主机目录挂载到容器目录上.那么此容器目录中原有的文件会被隐藏,从而只能读取到宿主机目录下的文件。

bind mount与volume相比功能有限。使用绑定挂载时,主机上的文件或目录会挂载到容器中.立件或目录由它在主机上的完整路径引用。目录不需要存在于Docker主机上,如果不存在,Docker会自动创建。注意只能自动创建目录。

通过-v选项绑定挂载一个目录/nginx/html到容器中:

[root@docker ~]# docker run -dt -v /nginx/html:/usr/share/nginx/html --name nginx nginx
66bc659dac18f8dbe4832aabb9a06c47a1eef2004ba51b22dffa1976c1fb078f

通过docker inspect nginx查看容器Mounts字段:

[root@docker ~]# docker inspect nginx
[{"Id": "66bc659dac18f8dbe4832aabb9a06c47a1eef2004ba51b22dffa1976c1fb078f","Created": "2023-12-09T15:55:39.145460398Z","Path": "/docker-entrypoint.sh","Args": ["nginx","-g","daemon off;"],"State": {"Status": "running","Running": true,"Paused": false,"Restarting": false,"OOMKilled": false,"Dead": false,"Pid": 10567,"ExitCode": 0,"Error": "","StartedAt": "2023-12-09T15:55:39.388333291Z","FinishedAt": "0001-01-01T00:00:00Z"},"Image": "sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85","ResolvConfPath": "/var/lib/docker/containers/66bc659dac18f8dbe4832aabb9a06c47a1eef2004ba51b22dffa1976c1fb078f/resolv.conf","HostnamePath": "/var/lib/docker/containers/66bc659dac18f8dbe4832aabb9a06c47a1eef2004ba51b22dffa1976c1fb078f/hostname","HostsPath": "/var/lib/docker/containers/66bc659dac18f8dbe4832aabb9a06c47a1eef2004ba51b22dffa1976c1fb078f/hosts","LogPath": "/var/lib/docker/containers/66bc659dac18f8dbe4832aabb9a06c47a1eef2004ba51b22dffa1976c1fb078f/66bc659dac18f8dbe4832aabb9a06c47a1eef2004ba51b22dffa1976c1fb078f-json.log","Name": "/nginx","RestartCount": 0,"Driver": "overlay2","Platform": "linux","MountLabel": "","ProcessLabel": "","AppArmorProfile": "","ExecIDs": null,"HostConfig": {"Binds": ["/nginx/html:/usr/share/nginx/html"],"ContainerIDFile": "","LogConfig": {"Type": "json-file","Config": {}},"NetworkMode": "default","PortBindings": {},"RestartPolicy": {"Name": "no","MaximumRetryCount": 0},"AutoRemove": false,"VolumeDriver": "","VolumesFrom": null,"ConsoleSize": [37,108],"CapAdd": null,"CapDrop": null,"CgroupnsMode": "host","Dns": [],"DnsOptions": [],"DnsSearch": [],"ExtraHosts": null,"GroupAdd": null,"IpcMode": "private","Cgroup": "","Links": null,"OomScoreAdj": 0,"PidMode": "","Privileged": false,"PublishAllPorts": false,"ReadonlyRootfs": false,"SecurityOpt": null,"UTSMode": "","UsernsMode": "","ShmSize": 67108864,"Runtime": "runc","Isolation": "","CpuShares": 0,"Memory": 0,"NanoCpus": 0,"CgroupParent": "","BlkioWeight": 0,"BlkioWeightDevice": [],"BlkioDeviceReadBps": [],"BlkioDeviceWriteBps": [],"BlkioDeviceReadIOps": [],"BlkioDeviceWriteIOps": [],"CpuPeriod": 0,"CpuQuota": 0,"CpuRealtimePeriod": 0,"CpuRealtimeRuntime": 0,"CpusetCpus": "","CpusetMems": "","Devices": [],"DeviceCgroupRules": null,"DeviceRequests": null,"MemoryReservation": 0,"MemorySwap": 0,"MemorySwappiness": null,"OomKillDisable": false,"PidsLimit": null,"Ulimits": null,"CpuCount": 0,"CpuPercent": 0,"IOMaximumIOps": 0,"IOMaximumBandwidth": 0,"MaskedPaths": ["/proc/asound","/proc/acpi","/proc/kcore","/proc/keys","/proc/latency_stats","/proc/timer_list","/proc/timer_stats","/proc/sched_debug","/proc/scsi","/sys/firmware","/sys/devices/virtual/powercap"],"ReadonlyPaths": ["/proc/bus","/proc/fs","/proc/irq","/proc/sys","/proc/sysrq-trigger"]},"GraphDriver": {"Data": {"LowerDir": "/var/lib/docker/overlay2/ff534546df16bbd82350f99144e242689961bfe3d2965b05ceb747755f6c2b27-init/diff:/var/lib/docker/overlay2/87839d75fc8d8156b6e8e6dce26e33656ac0720f2d38824237b955d1869f4ab5/diff:/var/lib/docker/overlay2/7d21dabb4ec6bd6d9f2539309dd0ca6e73c1ad0ab6b17e04030b3233f57296df/diff:/var/lib/docker/overlay2/5c855af6d6078412b1c70f343d4fdf88630be1c63be7ef4593bb7ccdd016d359/diff:/var/lib/docker/overlay2/29def7eb03e7b3d07c6eba7f6105b42f2526960e257f4e4aa56dfce19be02115/diff:/var/lib/docker/overlay2/9221f66223b31550805df61a409b03861c73bf4de8bfa0df5a56ce30fea53cb4/diff:/var/lib/docker/overlay2/1c494cbe1271bf494d078d9339129ea687e925fef25aca5471dc36bcb4dc2cc4/diff","MergedDir": "/var/lib/docker/overlay2/ff534546df16bbd82350f99144e242689961bfe3d2965b05ceb747755f6c2b27/merged","UpperDir": "/var/lib/docker/overlay2/ff534546df16bbd82350f99144e242689961bfe3d2965b05ceb747755f6c2b27/diff","WorkDir": "/var/lib/docker/overlay2/ff534546df16bbd82350f99144e242689961bfe3d2965b05ceb747755f6c2b27/work"},"Name": "overlay2"},"Mounts": [{"Type": "bind","Source": "/nginx/html","Destination": "/usr/share/nginx/html","Mode": "","RW": true,"Propagation": "rprivate"}],"Config": {"Hostname": "66bc659dac18","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,"AttachStderr": false,"ExposedPorts": {"80/tcp": {}},"Tty": true,"OpenStdin": false,"StdinOnce": false,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","NGINX_VERSION=1.21.5","NJS_VERSION=0.7.1","PKG_RELEASE=1~bullseye"],"Cmd": ["nginx","-g","daemon off;"],"Image": "nginx","Volumes": null,"WorkingDir": "","Entrypoint": ["/docker-entrypoint.sh"],"OnBuild": null,"Labels": {"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"},"StopSignal": "SIGQUIT"},"NetworkSettings": {"Bridge": "","SandboxID": "84acc916f76bd8f8d0e1d5a22d944f46a278708b3e5a69980e249e51edd1b6df","HairpinMode": false,"LinkLocalIPv6Address": "","LinkLocalIPv6PrefixLen": 0,"Ports": {"80/tcp": null},"SandboxKey": "/var/run/docker/netns/84acc916f76b","SecondaryIPAddresses": null,"SecondaryIPv6Addresses": null,"EndpointID": "97beacc486df02851bfdde8a645f3e2b7472042a42f3fde2db7046a4efcdaff8","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": "7a72caeb58cd5c7d7589a06372f8136dd4b0f15e5492d5d7996ef2220423d256","EndpointID": "97beacc486df02851bfdde8a645f3e2b7472042a42f3fde2db7046a4efcdaff8","Gateway": "172.17.0.1","IPAddress": "172.17.0.2","IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"MacAddress": "02:42:ac:11:00:02","DriverOpts": null}}}}
]
[root@docker ~]# 

接下来,在Docker主机上创建一个index.html文件并写入“hello nginx”,然后访问容器IP,显然挂载已经生效:

[root@docker ~]# echo "hello nginx" > /nginx/html/index.html
[root@docker ~]# curl 172.17.0.2
hello nginx
[root@docker ~]# 

可以通过Docker主机修改文件使容器内文件生效,反过来也可以,容器可以修改、创建和删除主机文件系统上的内容。处理这个问题时,可以在创建容器的时候配置挂载目录的权限,例如赋予只读权限:

docker run -dt -v /nginx/html:/usr/share/nginx/html:ro --name nginx nginx

tmpfs mount

tmpfs mount的使用场景为:若因为安全或其他原因,不希望将数据持久化到容器或宿主机上,则可以使用tmpfs mount模式:使用Liunx运行Docker,避免写入数据到容器存储层可以使用tmpfs mount、

tmpfs mout是一种非持久化的数据存储,仅将数据保存都在宿主机的内存中,一旦容器停止运行tmpfs mount就会被移除,从而总成数据丢失。

可以在运行容器时,通过制定–tmpfs参数或–mount参数来使用tmpfs mount。

docker run -d \
-it \
--name tmptest \
--mount type=tmpfs,destination=/app \
nginx:latestdocker run -d \
-it \
--name tmptest \
--tmpfs /app \
nginx:latest

使用-tmpfsc参数无法指定任何其他的可选项,并且不能用于swarm Service。
tmpfs mount有以下两个可选项:

  • tmpfs-size:挂载的tmpfs的宇节数,默认不受限制。
  • tmpfs-nide:tmpfs的文件模式,例如700或者1700,默认值为1777,表示任何用户都有写入权限 。

使用docker container inspect tmptest命令,然后查看Mounts文本部分,可以看到:

[root@docker ~]# docker container inspect tmptest
[{"Id": "0a3a8c958db0663f5ae227c324f761e49698a878c12c3740ea42b474e6e1d814","Created": "2023-12-09T16:08:43.092093398Z","Path": "/docker-entrypoint.sh","Args": ["nginx","-g","daemon off;"],"State": {"Status": "running","Running": true,"Paused": false,"Restarting": false,"OOMKilled": false,"Dead": false,"Pid": 10695,"ExitCode": 0,"Error": "","StartedAt": "2023-12-09T16:08:43.363050075Z","FinishedAt": "0001-01-01T00:00:00Z"},"Image": "sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85","ResolvConfPath": "/var/lib/docker/containers/0a3a8c958db0663f5ae227c324f761e49698a878c12c3740ea42b474e6e1d814/resolv.conf","HostnamePath": "/var/lib/docker/containers/0a3a8c958db0663f5ae227c324f761e49698a878c12c3740ea42b474e6e1d814/hostname","HostsPath": "/var/lib/docker/containers/0a3a8c958db0663f5ae227c324f761e49698a878c12c3740ea42b474e6e1d814/hosts","LogPath": "/var/lib/docker/containers/0a3a8c958db0663f5ae227c324f761e49698a878c12c3740ea42b474e6e1d814/0a3a8c958db0663f5ae227c324f761e49698a878c12c3740ea42b474e6e1d814-json.log","Name": "/tmptest","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,"ConsoleSize": [37,108],"CapAdd": null,"CapDrop": null,"CgroupnsMode": "host","Dns": [],"DnsOptions": [],"DnsSearch": [],"ExtraHosts": null,"GroupAdd": null,"IpcMode": "private","Cgroup": "","Links": null,"OomScoreAdj": 0,"PidMode": "","Privileged": false,"PublishAllPorts": false,"ReadonlyRootfs": false,"SecurityOpt": null,"UTSMode": "","UsernsMode": "","ShmSize": 67108864,"Runtime": "runc","Isolation": "","CpuShares": 0,"Memory": 0,"NanoCpus": 0,"CgroupParent": "","BlkioWeight": 0,"BlkioWeightDevice": [],"BlkioDeviceReadBps": [],"BlkioDeviceWriteBps": [],"BlkioDeviceReadIOps": [],"BlkioDeviceWriteIOps": [],"CpuPeriod": 0,"CpuQuota": 0,"CpuRealtimePeriod": 0,"CpuRealtimeRuntime": 0,"CpusetCpus": "","CpusetMems": "","Devices": [],"DeviceCgroupRules": null,"DeviceRequests": null,"MemoryReservation": 0,"MemorySwap": 0,"MemorySwappiness": null,"OomKillDisable": false,"PidsLimit": null,"Ulimits": null,"CpuCount": 0,"CpuPercent": 0,"IOMaximumIOps": 0,"IOMaximumBandwidth": 0,"Mounts": [{"Type": "tmpfs","Target": "/app"}],"MaskedPaths": ["/proc/asound","/proc/acpi","/proc/kcore","/proc/keys","/proc/latency_stats","/proc/timer_list","/proc/timer_stats","/proc/sched_debug","/proc/scsi","/sys/firmware","/sys/devices/virtual/powercap"],"ReadonlyPaths": ["/proc/bus","/proc/fs","/proc/irq","/proc/sys","/proc/sysrq-trigger"]},"GraphDriver": {"Data": {"LowerDir": "/var/lib/docker/overlay2/a36502c882207eccca4aa2d29cae30280016b001e48f46e2d0d44a3cf996bf3f-init/diff:/var/lib/docker/overlay2/87839d75fc8d8156b6e8e6dce26e33656ac0720f2d38824237b955d1869f4ab5/diff:/var/lib/docker/overlay2/7d21dabb4ec6bd6d9f2539309dd0ca6e73c1ad0ab6b17e04030b3233f57296df/diff:/var/lib/docker/overlay2/5c855af6d6078412b1c70f343d4fdf88630be1c63be7ef4593bb7ccdd016d359/diff:/var/lib/docker/overlay2/29def7eb03e7b3d07c6eba7f6105b42f2526960e257f4e4aa56dfce19be02115/diff:/var/lib/docker/overlay2/9221f66223b31550805df61a409b03861c73bf4de8bfa0df5a56ce30fea53cb4/diff:/var/lib/docker/overlay2/1c494cbe1271bf494d078d9339129ea687e925fef25aca5471dc36bcb4dc2cc4/diff","MergedDir": "/var/lib/docker/overlay2/a36502c882207eccca4aa2d29cae30280016b001e48f46e2d0d44a3cf996bf3f/merged","UpperDir": "/var/lib/docker/overlay2/a36502c882207eccca4aa2d29cae30280016b001e48f46e2d0d44a3cf996bf3f/diff","WorkDir": "/var/lib/docker/overlay2/a36502c882207eccca4aa2d29cae30280016b001e48f46e2d0d44a3cf996bf3f/work"},"Name": "overlay2"},"Mounts": [{"Type": "tmpfs","Source": "","Destination": "/app","Mode": "","RW": true,"Propagation": ""}],"Config": {"Hostname": "0a3a8c958db0","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,"AttachStderr": false,"ExposedPorts": {"80/tcp": {}},"Tty": true,"OpenStdin": true,"StdinOnce": false,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","NGINX_VERSION=1.21.5","NJS_VERSION=0.7.1","PKG_RELEASE=1~bullseye"],"Cmd": ["nginx","-g","daemon off;"],"Image": "nginx:latest","Volumes": null,"WorkingDir": "","Entrypoint": ["/docker-entrypoint.sh"],"OnBuild": null,"Labels": {"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"},"StopSignal": "SIGQUIT"},"NetworkSettings": {"Bridge": "","SandboxID": "29b18980d941c359ffad690cd674830496436a15d9554bcf86984f7545352aab","HairpinMode": false,"LinkLocalIPv6Address": "","LinkLocalIPv6PrefixLen": 0,"Ports": {"80/tcp": null},"SandboxKey": "/var/run/docker/netns/29b18980d941","SecondaryIPAddresses": null,"SecondaryIPv6Addresses": null,"EndpointID": "15e108b973ba2a69b6ffc457fba78e42940bc075e9b7812d9e85e59be7413e9e","Gateway": "172.17.0.1","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"IPAddress": "172.17.0.3","IPPrefixLen": 16,"IPv6Gateway": "","MacAddress": "02:42:ac:11:00:03","Networks": {"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"NetworkID": "7a72caeb58cd5c7d7589a06372f8136dd4b0f15e5492d5d7996ef2220423d256","EndpointID": "15e108b973ba2a69b6ffc457fba78e42940bc075e9b7812d9e85e59be7413e9e","Gateway": "172.17.0.1","IPAddress": "172.17.0.3","IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"MacAddress": "02:42:ac:11:00:03","DriverOpts": null}}}}
]
[root@docker ~]# 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/215136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jemeter,提取响应体中的数据:正则表达式、Json提取器

一、正则表达式 1、线程组--创建线程组&#xff1b; 2、线程组--添加--取样器--HTTP请求&#xff1b; 3、Http请求--添加--后置处理器--正则表达式提取器&#xff1b; 4、线程组--添加--监听器--查看结果树&#xff1b; 5、线程组--添加--取样器--调试取样器。 响应体数据…

docker mysql8 设置不区分大小写

docker安装Mysql8.0的坑之lower_case_table_names_docker mysql lower_case_table_names-CSDN博客https://blog.csdn.net/p793049488/article/details/108365929 docker run ‐di ‐‐nametensquare_mysql ‐p 33306:3306 ‐e MYSQL_ROOT_PASSWORD123456 mysql

金蝶EAS如何增加报表

金蝶EAS如何增加销售毛利报表&#xff1f; 文章目录 菜单路径&#xff1a;导入授权发布管理 菜单路径&#xff1a; 商业分析———扩展报表中心——报表工具 ——报表工具 汽车 4S——整车管理——整车销售——扩展报表 导入 选择报表文件进行导入 授权 发布管理

(纯原创)基于JavaWeb的宠物领养商城(详细源码以及开发设计报告)

摘要 本宠物领养系统以MVC分层为原则&#xff0c;数据持久化使用Mybatis&#xff0c;数据库使用MySQL&#xff0c;这些技术目前相对比较成熟&#xff0c;方便系统的维护与扩展 商城系统包括了宠物领养、用户注册、用户登录、商品查询、商品添加到购物车、删除商品等几大功能…

Linux基础项目开发2:物联网监控——视频监控方案介绍(一)

前言&#xff1a; 这次我们来做一个关于视频监控的基础小项目&#xff0c;需要我们用到网络的相关知识&#xff0c;还会学到好多优秀的网络协议&#xff0c;下面让我们开始对物联网视频监控进行一个大体框架的介绍吧 目录 项目内容&#xff1a; 1.视频监控方案介绍 2.视频监控…

手写VUE后台管理系统10 - 封装Axios实现异常统一处理

目录 前后端交互约定安装创建Axios实例拦截器封装请求方法业务异常处理 axios 是一个易用、简洁且高效的http库 axios 中文文档&#xff1a;http://www.axios-js.com/zh-cn/docs/ 前后端交互约定 在本项目中&#xff0c;前后端交互统一使用 application/json;charsetUTF-8 的请…

云计算 云原生

一、引言 云计算需要终端把信息上传到服务器&#xff0c;服务器处理后再返回给终端。在之前人手一台手机的情况下&#xff0c;云计算还是能handle得过来的。但是随着物联网的发展&#xff0c;什么东西都要联网&#xff0c;那数据可就多了去了&#xff0c;服务器处理不过来&…

MachMap:End-to-End Vectorized Solution for Compact HD-Map Construction

参考代码&#xff1a;None 动机与出发点 地平线的MapTR展现出了构建高精地图的能力&#xff0c;但是它的机制确实是有点复杂了。为了兼容不同车道线的朝向&#xff0c;环形车道线的起终点等情况&#xff0c;针对性设计了permute-equal的匹配逻辑&#xff0c;这样的逻辑真的是太…

软件测试之压力测试详解

一、什么是压力测试 软件测试中&#xff1a;压力测试&#xff08;Stress Test&#xff09;&#xff0c;也称为强度测试、负载测试。压力测试是模拟实际应用的软硬件环境及用户使用过程的系统负荷&#xff0c;长时间或超大负荷地运行测试软件&#xff0c;来测试被测系统的性能、…

appium安卓app自动化,遇到搜索框无搜索按钮元素时无法搜索的解决方案

如XX头条&#xff0c;搜索框后面有“搜索”按钮&#xff0c;这样实现搜索操作较为方便。 但有些app没有设置该搜索按钮&#xff0c;初学者就要花点时间去学习怎么实现该功能了&#xff0c;如下图。 这时候如果定位搜索框&#xff0c;再点击操作&#xff0c;再输入文本后&#x…

SpringBootWeb请求响应之前言及状态码的详细解析

SpringBootWeb请求响应 前言 在上一次的课程中&#xff0c;我们开发了springbootweb的入门程序。 基于SpringBoot的方式开发一个web应用&#xff0c;浏览器发起请求 /hello 后 &#xff0c;给浏览器返回字符串 “Hello World ~”。 其实呢&#xff0c;是我们在浏览器发起请求…

【算法与数据结构】332、LeetCode重新安排行程

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题比较属于困难题目&#xff0c;难点在于完成机票、出发机场和到达机场之间的映射关系&#xff0c;再…

使用yum/dnf管理软件包

本章主要介绍使用 yum 对软件包进行管理。 yum 的介绍搭建yum源创建私有仓库yum客户端的配置yum的基本使用使用第三方yum源 使用rpm安装包时经常会遇到一个问题就是包依赖&#xff0c;如下所示。 [rootrhel03 ~]# rpm -ivh /mnt/AppStream/Packages/httpd-2.4.37-41.modulee…

【三维重建】对极几何

极几何描述了同一场景或者物体的两个视点图像间的几何关系 可以发现&#xff30;在左右相机的投影点一定在各自的极线上&#xff0c;如果求出极线就能缩小求解对应点的范围。 本质矩阵对规范化摄像机拍摄的两个视点图像间的极几何关系进行代数描述 规范化相机指的是相机的内参…

人工智能_机器学习063_SVR支持向量机_回归拟合天猫双十一销量方程---人工智能工作笔记0103

之前我们用线性回归做过天猫双十一销量预测的数据,现在我们再来用SVR支持向量机来做一下 首先上面是给出了销量,对应2009年到2019年的,销售额 可以看到: X=np.arange(2009,2020)-2008 统一减去2008的话看起来数据比较简单了 y=np.array([0.5,9.36,52,191,350,571,912,1207,1…

使用perl的Tie::File 模块删除文件固定行

使用perl的Tie::File 模块删除文件固定行, 为了说明简单代码中处理的是固定第二行开始的3行长度。下面给出perl代码&#xff1a; #! /usr/bin/perl use v5.14; use Tie::File;if (ARGV 0) {say "请输入一个文件名 !!!";exit 1; }my $filePath $ARGV[0]; tie my ar…

java工程(ajax/axios/postman)向请求头中添加消息

1、问题概述 在项目中我们经常会遇到需要向请求头中添加消息的场景&#xff0c;然后后端通过request.getRequest()或者RequestHeader获取请求头中的消息。 下面提供几种前端向请求头添加消息的方式 2、创建一个springmvc工程用于测试 2.1、创建工程并引入相关包信息 sprin…

C++之STL算法(1)

STL容器算法主要由、、组成&#xff1b;   algorithm主要有遍历、比较、交换、查找、拷贝、修改等&#xff1b; 1.遍历容器for_each for_each()函数用于完成容器遍历&#xff0c;函数参数如下&#xff1a; for_each(_InIt _First, _InIt _Last, _Fn _Func) 形参&#xff1a…

深度学习 Day10——T10数据增强

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文章目录 前言一、我的环境二、代码实现与执行结果1.引入库2.设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;3.导入数据4.查…

Docker基础概念解析:镜像、容器、仓库

当谈到容器化技术时&#xff0c;Docker往往是第一个被提及的工具。Docker的基础概念涵盖了镜像、容器和仓库&#xff0c;它们是理解和使用Docker的关键要素。在这篇文章中&#xff0c;将深入探讨这些概念&#xff0c;并提供更丰富的示例代码&#xff0c;帮助大家更好地理解和应…