【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.hqwc.cn/news/266981.html

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

相关文章

Linux——Web网站服务(二)

一、httpd服务的访问控制 1、客户机地址限制 通过Require配置项&#xff0c;可以根据主机的主机名或P地址来决定是否允许客户端访问。在 httpd服务器的主配置文件的<Location>&#xff0c;<Directory>、<Files>、<Limit>配置段中均可以使用Require配置…

Day57力扣打卡

打卡记录 最小体力消耗路径 链接 Dijkstra 将Dijkstra算法从计算最短路径转化为计算路径最大差值。 class Solution:def minimumEffortPath(self, heights: List[List[int]]) -> int:n, m len(heights), len(heights[0])dist [0] [0x3f3f3f3f] * (n * m - 1)vis set…

软件测试之压力测试详解

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

mysql数据库学习笔记(1)

今天开始学mysql数据库&#xff0c;为什么要学这个呢&#xff0c;因为数据库可结构化存储大量的数据信息&#xff0c;方便用户进行有效的检索和访问。数据库可有效地保持数据信息的一致性、完整性、降低数据冗余。数据库可满足应用的共享和安全方面的要求&#xff0c;把数据放在…

大数据技术10:Flink从入门到精通

导语&#xff1a;前期入门Flink时&#xff0c;可以直接编写通过idea编写Flink程序&#xff0c;然后直接运行main方法&#xff0c;无需搭建环境。我碰到许多初次接触Flink的同学&#xff0c;被各种环境搭建、提交作业、复杂概念给劝退了。前期最好的入门方式就是直接上手写代码&…

开源治理典型案例分享(汇编转)

当前&#xff0c;越来越多的企业申请通过信通院的开源治理成熟度评估和认证&#xff0c;获得增强级或先进级评估。这些企业包括中国工商银行股份有限公司、中国农业银行、上海浦东发展银行股份有限公司、中信银行股份有限公司、中国太平洋保险&#xff08;集团&#xff09;股份…

Maven项目引入本地jar

Maven项目引入本地jar 1.对应maven模块项目中建lib目录&#xff0c;将jar放入进去 2.在对应的模块pom.xml中引入此依赖jar 3.在对应的maven-plugin插件打包的pom.xml中指定需要includeSystemScope为true的jar

VSCode使用Remote-SSH连接服务器时报错:无法与“***”建立连接: XHR failed.

关于VSCode的报错问题&#xff1a;无法与“***”建立连接: XHR failed 问题描述问题理解解决方法手动在本地下载安装包&#xff0c;然后手动传到服务器端 问题描述 是的&#xff0c;我又踩坑了&#xff0c;而且这个弄了好久&#xff0c;也重新装了VSCode软件&#xff0c;好像结…

赛宁网安多领域亮相第三届网络空间内生安全发展大会

2023年12月8日&#xff0c;第三届网络空间内生安全发展大会在宁开幕。两院院士、杰出专家学者和知名企业家相聚南京&#xff0c;围绕数字经济新生态、网络安全新范式进行广泛研讨&#xff0c;为筑牢数字安全底座贡献智慧和力量。 大会围绕“一会、一赛、一展”举办了丰富多彩的…

实现React18加TS,解决通用后台管理系统,实战方案落地有效实践经验

随着前端技术的不断发展和更新&#xff0c;使用React 18结合TypeScript&#xff08;TS&#xff09;来构建通用后台管理系统已成为一种常见的选择。本文将介绍如何在项目中应用React 18和TS&#xff0c;并分享一些实战方案的有效实践经验。 一、搭建React 18 TS项目 首先&…

CDH6.3.2安装

文章目录 [toc]一、CM简介1、ClouderaManager的概念2、ClouderaManager的功能3、ClouderaManager的架构 二、准备清单1、部署步骤2、集群规划3、软件环境准备 三、安装清单1、操作系统iso包2、JDK包3、MySQL包4、CM和CDH包5、部署ansible 四、基础环境准备1、配置网络2、配置ho…

MAC配置环境变量

1、配置 JAVA JDK 1.1、查看 JDK 安装目录 &#xff08;1&#xff09;可以在Android Studio中查看&#xff0c;复制该路径 &#xff08;2&#xff09;也可以在官网下载 Java JDK下载地址 mac中的安装地址是"资源库->Java->JavaVirtualMachines"中 1.2、…