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

news/2024/10/17 19:28:59/

【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.ppmy.cn/news/1266271.html

相关文章

到底什么是DevOps

DevOps不是一组工具&#xff0c;也不是一个特定的岗位。在我看来DevOps更像是一种软件开发文化&#xff0c;一种实现快速交付能力的手段。 DevOps 强调的是高效组织团队之间如何通过自动化的工具协作和沟通来完成软件的生命周期管理&#xff0c;从而更快、更频繁地交付更稳定的…

Word插件-好用的插件-批量插入图片-大珩助手

现有100张图片&#xff0c;需要批量插入word中&#xff0c;并在word中以每页6张图片的形式呈现&#xff0c;请问怎样做&#xff1f; 使用word大珩助手&#xff0c;多媒体-插入图片&#xff0c;根据图片的长宽&#xff0c;选择连续图片、一行2个图或一行3个图&#xff0c;可一次…

解决HTTP 429错误的Scrapy中间件配置

引言 在进行网络数据抓取时&#xff0c;经常会遇到HTTP 429错误&#xff0c;表示请求速率已超出API限制。为避免封禁或限制访问&#xff0c;需要调整Scrapy的请求速率&#xff0c;以在不触发HTTP 429错误的情况下完成数据抓取。针对这一问题&#xff0c;可使用Scrapy的AutoThr…

云原生的 CI/CD 框架tekton - Trigger(二)

上一篇为大家详细介绍了tekton - pipeline&#xff0c;由于里面涉及到的概念比较多&#xff0c;因此需要好好消化下。同样&#xff0c;今天在特别为大家分享下tekton - Trigger以及案例演示&#xff0c;希望可以给大家提供一种思路哈。 文章目录 1. Tekton Trigger2. 工作流程3…

[排序篇] 冒泡排序

目录 一、概念 二、冒泡排序 2.1 冒泡降序(从大到小排序) 2.2 冒泡升序(从小到大排序) 三、冒泡排序应用 总结 一、概念 冒泡排序核心思想&#xff1a;每次比较两个相邻的元素&#xff0c;如果它们不符合排序规则&#xff08;升序或降序&#xff09;则把它们交换过来。…

计算机网络常见的缩写

计算机网络常见缩写 通讯控制处理机&#xff08;Communication Control Processor&#xff09;CCP 前端处理机&#xff08;Front End Processor&#xff09;FEP 开放系统互连参考模型 OSI/RM 开放数据库连接&#xff08;Open Database Connectivity&#xff09;ODBC 网络操作系…

第三十一章 控制到 XML 模式的映射 - %ListOfDataTypes

文章目录 第三十一章 控制到 XML 模式的映射 - %ListOfDataTypes%ListOfDataTypes%ArrayOfDataTypes 第三十一章 控制到 XML 模式的映射 - %ListOfDataTypes %ListOfDataTypes 本部分显示从支持 XML 的类生成的 XML 架构的一部分&#xff0c;该类包含中定义为%ListOfDataType…

JavaDay17

创建不可变集合 import java.util.Iterator; import java.util.List;public class Test {public static void main(String[] args) {/*创建不可变的List集合* "张三" "李四" "王五" "赵六*///一旦创建之后 是无法进行修改的 在下面的代码…