docker存储管理及实例
作者:@郑琰
本文转载请注明出处!:https://www.cnblogs.com/zhengyan6/p/16224092.html
一、Docker存储概念
1、容器本地存储与Docke存储驱动
容器本地存储:每个容器都被自动分配了内部存储,即容器本地存储。采用的是联合文件系统。通过存储驱动进行管理。
存储驱动:控制镜像和容器在 docker 主机上的存储和管理方式。
容器本地存储空间:分层结构构成,由一个可写容器层和若干只读的镜像层组成。
联合文件系统:Docker的一种底层技术,由存储驱动(Storage Driver)实现。相应的存储驱动有aufs、overlay、overlay2、devicemapper、btrfs、zfs、vfs等。
每个Docker主机只能选择一种存储驱动,不能为每个容器选择不同的存储驱动。
(1)查看主机支持的存储驱动
[root@docker ~]# docker info # 找到如下信息 Storage Driver: overlay2 # 存储驱动是overlay2 Backing Filesystem: xfs # 底层文件系统是xfs Supports d_type: true # 支持d_type Native Overlay Diff: true userxattr: false
(2)更改现有的存储驱动
可以根据需要修改现有的存储驱动
注意:
1,一个主机只能选择一个存储驱动。
2,系统版本和存储驱动的兼容问题。
3,更改存储驱动会使得现有的容器和镜像不可访问(原因:每种存储驱动存储镜像层的位置是不同的)
4,但恢复存储驱动,可以再次访问之前的镜像和容器
# 修改daemon.json文件来更改存储引擎配置 [root@docker ~]# vi /etc/docker/daemon.json { "registry-mirror":["https://registry.docker-cn.com"], "storage-driver":"overlay" <—————添加这个信息 } # 重启docker生效 [root@docker ~]# systemctl daemon-reload [root@docker ~]# systemctl restart docker [root@docker ~]# docker info # 找到如下信息 Storage Driver: overlay <——————修改生效 Backing Filesystem: xfs Supports d_type: true # 更改存储驱动会使得现有的容器和镜像不可访问 [root@docker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE # 恢复存储驱动,可以再次访问之前的镜像和容器 [root@docker ~]# vi /etc/docker/daemon.json { "registry-mirror":["https://registry.docker-cn.com"] } [root@docker ~]# systemctl daemon-reload [root@docker ~]# systemctl restart docker [root@docker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 825d55fb6340 2 weeks ago 72.8MB centos latest 5d0da3dc9764 7 months ago 231MB
2、容器和非持久化数据
非持久化数据:不需要保存的数据。容器本地存储中的数据属于非持久化数据。
容器创建时会创建非持久化存储,非持久化存储自动创建,从属于容器,生命周期与容器相同。删除容器也会删除全部非持久化数据。
非持久化数据存在问题:
- 这类数据从属于容器,生命周期与容器相同,会随着容器的删除而被删除。(易丢失)
- 当该容器不再运行时,数据不会持久保存,如果另一个进程需要,则可能很难从该容器中获取数据。(难获取)
- 容器的可写层与运行容器的Docker主机紧密耦合,无法轻松地将数据转移到其他位置。(难转移)
- 写入容器的可写层需要Docker存储驱动管理文件系统。存储驱动使用Linux内核提供的联合文件系统,其性能不如直接写入主机文件系统的Docker卷。(读写性能差)
3、容器和持久化数据
持久化数据:需要保存的数据。例如:日志、业务数据、客户信息等有用的数据。
外部存储:Docker通过将主机中的文件系统挂载到容器中供容器存取,从而实现持久化数据存储。
容器持久化数据存储方式:Docker目前支持卷、绑定挂载,这两种挂载类型实现容器的持久化。
卷(数据卷):Docker中进行持久化数据存储的最佳方式。本质是Docker主机文件系统中的目录或文件直接挂载到容器的文件系统中。
- 卷和容器是解耦的,可以独立地创建并管理卷
- 卷不与容器的生命周期绑定(容器的停止删除和卷无关)
- 可以将任意数量的卷装入容器,多个容器也可以共享一个或多个卷(多对多关系)
4、挂载类型
往容器中挂载的外部文件系统主要有:卷、绑定挂载、tmpfs挂载。无论哪种挂载,对容器内部来说是一样的,都会显示为文件或目录。
(1)卷
-
卷存储在主机文件系统中由Docker管理的位置,在Linux主机上该位置默认就是/var/lib/docker/volumes目录。
-
卷是Docker持久化存储数据的最佳方式。卷支持使用卷驱动,可以让用户将数据存储在远程主机或云提供商处等。
可以以命名方式或匿名方式挂载卷:
- 匿名卷(Anonymous Volumes):首次挂载容器未指定名称,Docker为其随机指定一个唯一名称。
- 命名卷(Named Volumes):指定明确名称,和匿名卷其他特性相同。
卷由Docker创建并管理,卷适合以下应用场景:
- 1, 在多个正在运行的容器之间共享数据。(数据共享)
- 2, 当Docker主机不能保证具有特定目录结构时,卷有助于将Docker主机的配置与容器运行时解耦。(构建新目录与主机不同)
- 3, 当需要将容器的数据存储到远程主机或云提供商处,而不是本地时。(可以远程挂载卷,公有云、灾备等场景)
- 4, 当需要在两个Docker主机之间备份、恢复或迁移数据时。(主机间备份迁移)
(2)绑定挂载
- 绑定挂载可以存储到主机系统的任意位置,甚至会存储到一些重要的系统文件或目录中。
特点:
- 主机上进程或容器可以随时修改。
- 相比卷,功能更受限、性能更高。
- 绑定挂载运行访问敏感文件。
绑定挂载适合以下应用场景:
- 在主机和容器之间共享配置文件
- 在Docker主机上的开发环境和容器之间共享源代码或构建工件。
- 当Docker主机上的目录结构保证与容器要求的绑定挂载一致时。
(3)tmpfs挂载
tmpfs挂载仅限于运行Linux操作系统的Docker主机使用,它只存储在主机的内存中,不会被写到主机的文件系统中,因此不能持久保存容器的应用数据。
在不需要将数据持久保存到主机或容器中时,tmpfs挂载最合适。
如果容器产生了非持久化数据,那么可以考虑使用tmpfs挂载避免将数据永久存储到任何位置,并且通过避免写入容器的可写层来提高容器的性能。
二、Docker卷管理
docker volume
是Docker卷的管理命令。
创建卷的时候主机上的Docker根目录(linux默认是/var/lib/docker)下的volumes子目录内会生成一个以卷名命名的子目录,这个子目录里面再创建一个_data的子目录作为卷的数据存储路径。
卷名必须唯一,不同的卷驱动不能使用相同的卷名。
# 语法 [root@localhost volumes]# docker volume Usage: docker volume COMMAND Manage volumes Commands: create Create a volume # 创建卷 inspect Display detailed information on one or more volumes # 查看卷的详细信息 ls List volumes # 列出本地docker主机上的卷 prune Remove all unused local volumes # 删除未被使用的卷 rm Remove one or more volumes # 删除指定卷
1、创建卷
# 参数所有示例 # 语法 [root@localhost volumes]# docker volume create --help Usage: docker volume create [OPTIONS] [VOLUME] Create a volume Options: -d, --driver string Specify volume driver name (default "local") # 说明卷驱动名称(默认是'local') --label list Set metadata for a volume # 设置卷元数据 -o, --opt map Set driver specific options (default map[]) # 设置驱动特殊选项 # 案例1:创建普通卷 [root@localhost volumes]# docker volume create test-vol01 test-vol01 [root@localhost volumes]# docker volume inspect test-vol01 [ { "CreatedAt": "2022-04-27T17:02:27+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/test-vol01/_data", "Name": "test-vol01", "Options": {}, "Scope": "local" } ] # 案例2:创建tmpfs卷,大小100m,uid为1000 [root@localhost volumes]# docker volume create --driver local \ > --opt type=tmpfs \ > --opt device=tmpfs \ > --opt o=size=100m,uid=1000 \ > test-vol02 test-vol02 [root@localhost volumes]# docker volume inspect test-vol02 [ { "CreatedAt": "2022-04-27T17:10:21+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/test-vol02/_data", "Name": "test-vol02", "Options": { "device": "tmpfs", "o": "size=100m,uid=1000", "type": "tmpfs" }, "Scope": "local" } ] # 案例3:设置元数据 [root@localhost volumes]# docker volume create --label city=wuhan test-vol03 test-vol03 [root@localhost volumes]# docker volume inspect test-vol03 [ { "CreatedAt": "2022-04-27T17:07:44+08:00", "Driver": "local", "Labels": { "city": "wuhan" }, "Mountpoint": "/var/lib/docker/volumes/test-vol03/_data", "Name": "test-vol03", "Options": {}, "Scope": "local" } ]
2、查看卷列表
使用 docker volume ls
命令列出当前的卷
format关键词:
Placeholder | Description |
---|---|
.Name | Volume name |
.Driver | Volume driver |
.Scope | Volume scope (local, global) |
.Mountpoint | The mount point of the volume on the host |
.Labels | All labels assigned to the volume |
.Label | Value of a specific label for this volume. For example {{.Label "project.version"}} |
# 语法 [root@localhost volumes]# docker volume ls --help Usage: docker volume ls [OPTIONS] <—————注意选项不能写在ls之前 List volumes Aliases: ls, list Options: -f, --filter filter Provide filter values (e.g. 'dangling=true') # 条件筛选 --format string Pretty-print volumes using a Go template # 内容过滤输出 -q, --quiet Only display volume names # 只打印卷名 # 案例1:普通查看 [root@localhost volumes]# docker volume ls 卷驱动 卷名称 DRIVER VOLUME NAME local test-vol01 local test-vol02 local test-vol03 # 案例2:条件筛选 # 没有被使用的卷 [root@localhost volumes]# docker volume ls -f dangling=true DRIVER VOLUME NAME local test-vol01 local test-vol02 local test-vol03 # 驱动为local的卷 [root@localhost volumes]# docker volume ls -f driver=local DRIVER VOLUME NAME local test-vol01 local test-vol02 local test-vol03 # 根据label元数据筛选 [root@localhost volumes]# docker volume ls --filter label=city DRIVER VOLUME NAME local test-vol03 # 根据名称筛选 [root@localhost volumes]# docker volume ls -f name=03 DRIVER VOLUME NAME local test-vol03 [root@localhost volumes]# docker volume ls -f name=vol DRIVER VOLUME NAME local test-vol01 local test-vol02 local test-vol03 # 案例3:只打印卷名 [root@localhost volumes]# docker volume ls -q test-vol01 test-vol02 test-vol03 # 案例4:内容过滤输出 [root@localhost volumes]# docker volume ls --format "{{.Name}}: {{.Driver}}" test-vol01: local test-vol02: local test-vol03: local [root@localhost volumes]# docker volume ls --format "{{.Name}}: {{.Mountpoint}}: {{.Labels}}" test-vol01: /var/lib/docker/volumes/test-vol01/_data: test-vol02: /var/lib/docker/volumes/test-vol02/_data: test-vol03: /var/lib/docker/volumes/test-vol03/_data: city=hb
3、查看卷详细信息
# 语法 [root@localhost ~]# docker volume inspect --help Usage: docker volume inspect [OPTIONS] VOLUME [VOLUME...] Display detailed information on one or more volumes Options: -f, --format string Format the output using the given Go template # 案例 [root@localhost ~]# docker volume create --driver local \ > --opt type=tmpfs \ > --opt device=tmpfs \ > --opt o=size=100m,uid=1000 \ > --label city=wuhan \ > --label type=tmpfs \ > test-vol 70eefb6835df2daafcc3e678395af214dae4a98241fd6886e5822bbc9e7de920 [root@localhost ~]# docker volume inspect test-vol [ { "CreatedAt": "2022-04-28T00:36:35+08:00", "Driver": "local", # 卷驱动 "Labels": { "city": "wuhan", "type": "tmpfs" }, "Mountpoint": "/var/lib/docker/volumes/test-vol/_data", # 卷挂载点 "Name": "test-vol", # 卷名称 "Options": { "device": "tmpfs", "o": "size=100m,uid=1000", "type": "tmpfs" }, "Scope": "local" # 卷作用域 } ] [root@localhost ~]# docker volume inspect --format '{{ .Mountpoint }}' test-vol /var/lib/docker/volumes/test-vol/_data [root@localhost ~]# docker volume inspect --format '{{ .Options }}' test-vol map[device:tmpfs o:size=100m,uid=1000 type:tmpfs] [root@localhost ~]# docker volume inspect --format '{{ .Options.o }}' test-vol size=100m,uid=1000 [root@localhost ~]# docker volume inspect --format '{{ .Labels.city }}' test-vol hb
4、删除卷
使用 docker volume rm
删除指定卷(不能删除正在被容器使用的卷)
# 语法 [root@localhost ~]# docker volume rm --help Usage: docker volume rm [OPTIONS] VOLUME [VOLUME...] Remove one or more volumes. You cannot remove a volume that is in use by a container. Aliases: rm, remove Options: -f, --force Force the removal of one or more volumes 强制删除 # 案例 [root@localhost ~]# docker volume rm test-vol01 test-vol01 [root@localhost ~]# docker volume rm $(docker volume ls -q) test-vol test-vol02 test-vol03
使用 docker volume prune
删除未被容器或服务使用的所有卷
# 语法 [root@localhost ~]# docker volume prune --help Usage: docker volume prune [OPTIONS] Remove all unused local volumes Options: --filter filter Provide filter values (e.g. 'label=<label>') -f, --force Do not prompt for confirmation # 案例 [root@localhost ~]# docker volume prune WARNING! This will remove all local volumes not used by at least one container. Are you sure you want to continue? [y/N] y Deleted Volumes: test-vol01 test-vol02 test-vol03 Total reclaimed space: 0B
三、容器文件系统挂载
使用 docker run
或 docker create
命令的相关选项将外部的文件系统挂载到容器中。
早期版本:
- 卷和绑定挂载都可以通过 -v 和 --mount 选项挂载到容器中,主要是两者的语法的细微区别
- -v用于独立容器,--mount用于集群服务
- tmpfs挂载可以使用 --tmpfs选项
docker 17.06或更高版本:
- 建议所有的容器或服务,绑定挂载、卷、tmpfs都使用--mount选项。(语法清晰、定制详细)
- --mount 选项也可以用于独立容器。
-v和--mount的区别:
- -v语法是将选项组合在一个字段中,--mount的语法是将它们分开。
- --mount采用键值对写法支持更多的设置选项,-v 写法更加简洁。
1、-v(--volume)选项
选项包括冒号分隔的三个字段,必须按照正确顺序排序
# 语法 [root@localhost ~]# docker run(create) -v, --volume=[host-src:]container-dest[:<options>]: Bind mount a volume. 第一个host-src字段表示挂载源,来自主机的文件系统,为绝对路径或名称变量。 第二个container-dest字段表示挂载目标,即容器的挂载点,可以是目录或文件路径(绝对路径) 第三个options字段可选,以逗号分隔选项列表,如:[rw|ro], [z|Z], [[r]shared|[r]slave|[r]private], and [nocopy]. rw:读写模式?? ro:只读模式 nocopy:禁止自动复制到卷存储地址 命名卷,copy是默认模式,copy模式不支持绑定挂载的卷。 如果既没有指定rw又没有指定ro,卷挂载为读写模式。 # 案例:卷类型 [root@localhost ~]# docker volume create test-vol test-vol [root@localhost ~]# docker run -ti -v test-vol:/world ubuntu /bin/bash # 案例:绑定挂载类型 [root@localhost ~]# docker run -d \ > -it \ > --name devtest \ > -v "$(pwd)"/target:/app \ > nginx:latest 9c9bd6c4b7898f272b162683bf7370fe2fde2d04b30a361bda7443bc6a2d2bf4 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9c9bd6c4b789 nginx:latest "/docker-entrypoint.…" 10 seconds ago Up 9 seconds 80/tcp devtest [root@localhost ~]# docker exec -ti 9c9bd6c4b789 /bin/bash root@9c9bd6c4b789:/# ls app boot docker-entrypoint.d etc lib media opt root sbin sys usr bin dev docker-entrypoint.sh home lib64 mnt proc run srv tmp var root@9c9bd6c4b789:/# df -H Filesystem Size Used Avail Use% Mounted on overlay 19G 5.5G 13G 30% / tmpfs 68M 0 68M 0% /dev tmpfs 1.1G 0 1.1G 0% /sys/fs/cgroup shm 68M 0 68M 0% /dev/shm /dev/mapper/centos-root 19G 5.5G 13G 30% /app
2、--mount选项
绑定挂载、卷、tmpfs类型都使用--mount选项
--mount
选项的参数由多个由逗号分隔的键值对组成
特殊键如下:
- type: 指定要挂载的类型,值可以是bind(绑定挂载)、volume(卷)或tmpfs。
- source(或src): 指定挂载源
- destination(或dst、target):指定挂载目标,即容器中的挂载点,必须采用绝对路径的形式
- readonly:指定只读选项,表示源以只读方式挂载到容器中。
- 其他键:可以被多次指定,由若干键值对组成。卷和绑定挂载有不同的键。
[root@localhost ~]# docker run(create) --mount <键>=<值>,<键>=<值>,... Attach a filesystem mount to the container # 案例 [root@localhost ~]# docker run -d --name devtest01 --mount source=myvol2,target=/app nginx:latest 65e5132a4a64d40f688d2bcb80fe2f6d9a2fb504e092ca628b59398dd207b2a3 [root@localhost ~]# docker volume ls DRIVER VOLUME NAME local myvol2 [root@localhost ~]# docker volume inspect myvol2 [ { "CreatedAt": "2022-04-28T02:45:45+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/myvol2/_data", "Name": "myvol2", "Options": null, "Scope": "local" } ] [root@localhost ~]# docker exec -ti devtest01 /bin/bash root@65e5132a4a64:/# cd /app/
3,tmpfs 选项
tmpfs
挂载容许两个配置选项,两个选项都不是必需的。 若是须要指定这些选项,则必须使用 --mount
标记,由于 --tmpfs
标记不支持
-
tmpfs-size
tmpfs 挂载的大小(以字节为单位)。默认无限制。 -
tmpfs-mode
tmpfs 的八进制文件模式。例如,700 或 0770。默认为 1777 或全局可写
示例将 tmpfs-mode 设置为 1770,所以在容器中它不是全局可读的
docker run -d \ -it \ --name tmptest \ --mount type=tmpfs,destination=/app,tmpfs-mode=1770 \ nginx:latest
四、卷应用示例
1、创建一个卷并让容器挂载
# 1.创建一个卷、查看当前卷列表、查看卷详细信息 [root@localhost ~]# docker volume create test-vol test-vol [root@localhost ~]# docker volume ls DRIVER VOLUME NAME local test-vol [root@localhost ~]# docker volume inspect test-vol [ { "CreatedAt": "2022-04-28T03:06:05+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/test-vol/_data", "Name": "test-vol", "Options": {}, "Scope": "local" } ] # 2.启动容器,将卷挂载到容器/world目录,在容器中查看根目录、退出容器 [root@localhost ~]# docker run -ti -v test-vol:/world ubuntu /bin/bash root@e6535eebe726:/# ls bin dev home lib32 libx32 mnt proc run srv tmp var boot etc lib lib64 media opt root sbin sys usr world root@e6535eebe726:/# ls /world/ root@e6535eebe726:/# exit exit # 3.查看容器信息,验证卷是否正确挂载 [root@localhost ~]# docker inspect --format='{{json .Mounts}}' e6535 [{"Type":"volume","Name":"test-vol","Source":"/var/lib/docker/volumes/test-vol/_data","Destination":"/world","Driver":"local","Mode":"z","RW":true,"Propagation":""}] # 4.删除卷 [root@localhost ~]# docker volume rm test-vol Error response from daemon: remove test-vol: volume is in use - [e6535eebe726069b355567be0a562131844ad04b175b2a0ee870d990f72dca95] # 使用中的卷不能直接删除,第二次是先删除容器,再删除卷 [root@localhost ~]# docker rm e6535 e6535 [root@localhost ~]# docker volume rm test-vol test-vol
2、启动容器时自动创建卷
启动带有卷的容器时,如果卷尚不存在,则Docker会自动创建这个卷。
示例:将myvol卷挂载到容器testnovol的/app目录下。
--mount
选项实现:
[root@localhost ~]# docker run -d --name testnovol01 --mount source=myvol,target=/app nginx beafe21868168531d1eeb69c7b29e234f0ceb60cabc60ed8e5deae0c4c99f28d [root@localhost ~]# docker inspect --format='{{json .Mounts}}' testnovol01 [{"Type":"volume","Name":"myvol","Source":"/var/lib/docker/volumes/myvol/_data","Destination":"/app","Driver":"local","Mode":"z","RW":true,"Propagation":""}]
-v
选项实现:
[root@localhost ~]# docker run -d --name testnovol02 -v myvol02:/app nginx d7728830916fd11dec8487ea9aaf7e6f1b306b3c4c072683cf8155f430f57887 [root@localhost ~]# docker inspect --format='{{json .Mounts}}' testnovol02 [{"Type":"volume","Name":"myvol02","Source":"/var/lib/docker/volumes/myvol02/_data","Destination":"/app","Driver":"local","Mode":"z","RW":true,"Propagation":""}]
3、使用容器填充卷
容器启动时挂载已经存在并包含数据的卷,则容器不会将其挂载点目录的数据复制到该卷,而是直接使用该卷的数据。
如果容器启动时挂载空白卷或自动创建新卷,而容器的挂载点目录有文件,则该挂载点的内容会复制到卷中。
# 1.执行以下命令启动一个nginx容器,并使用容器的/usr/share/nginx/html目录的内容填充新的卷nginx-vol。 [root@localhost ~]# docker run -d --name=nginxtest --mount source=nginx-vol,destination=/usr/share/nginx/html nginx 3f208b4cecc9bc98c0424dc891ae39314b9dab61985e1e957b294a799589fafb [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3f208b4cecc9 nginx "/docker-entrypoint.…" 20 seconds ago Up 19 seconds 80/tcp nginxtest # 2.执行docker volume inspect nginx-vol命令查看该卷的详细信息,其中挂载点设置如下。 [root@localhost ~]# docker volume ls DRIVER VOLUME NAME local nginx-vol [root@localhost ~]# docker volume inspect --format='{{json .Mountpoint}}' nginx-vol "/var/lib/docker/volumes/nginx-vol/_data" # 3.查看主机上该卷所在目录的内容,发现容器已经填充了卷。 [root@localhost ~]# cd /var/lib/docker/volumes/nginx-vol/_data/ [root@localhost _data]# ls 50x.html index.html [root@localhost _data]# cat index.html <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> # 4.启动另一个容器挂载该卷,以使用其中预先填充的内容。 [root@localhost _data]# docker run -ti --name=othercntr --mount source=nginx-vol,destination=/nginx ubuntu /bin/bash root@a68b8352663b:/# ls /nginx/ 50x.html index.html root@a68b8352663b:/# cd /nginx/ root@a68b8352663b:/nginx# cat 50x.html <!DOCTYPE html> <html> <head> <title>Error</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>An error occurred.</h1> <p>Sorry, the page you are looking for is currently unavailable.<br/> Please try again later.</p> <p>If you are the system administrator of this resource then you should check the error log for details.</p> <p><em>Faithfully yours, nginx.</em></p> </body> </html> # 5.删除容器和卷 [root@localhost _data]# docker stop $(docker ps -aq) a68b8352663b 3f208b4cecc9 d7728830916f beafe2186816 65e5132a4a64 9c9bd6c4b789 [root@localhost _data]# docker rm $(docker ps -aq) a68b8352663b 3f208b4cecc9 d7728830916f beafe2186816 65e5132a4a64 9c9bd6c4b789 [root@localhost _data]# docker volume rm $(docker volume ls -q) myvol myvol2 myvol02 nginx-vol
4、使用只读卷
同一个卷可以由多个容器挂载,并且让容器执行读写操作。设置只读权限后,在容器中是无法对卷中数据修改的,可以提升安全性。
# --mount选项 [root@localhost _data]# docker run -dti --name=nginx-test --mount source=nginx-vol01,destination=/usr/share/nginx/html,readonly nginx 44bb1ee56819a71a4fafda36ab0ea05952d51b5d3c49dbfcc14a27fd2c84f740 [root@localhost _data]# docker exec -ti nginx-test /bin/bash root@44bb1ee56819:/# cd /usr/share/nginx/html/ root@44bb1ee56819:/usr/share/nginx/html# touch sss touch: cannot touch 'sss': Read-only file system root@44bb1ee56819:/usr/share/nginx/html# echo 'adadadd' >> 50x.html bash: 50x.html: Read-only file system [root@localhost _data]# docker inspect --format='{{json .Mounts}}' nginx-test [{"Type":"volume","Name":"nginx-vol01","Source":"/var/lib/docker/volumes/nginx-vol01/_data","Destination":"/usr/share/nginx/html","Driver":"local","Mode":"z","RW":false,"Propagation":""}] # -v选项 [root@localhost _data]# docker run -dti --name=nginx-test02 -v nginx-vol02:/usr/share/nginx/html:ro nginx 5b909ace1f2533ecd637bcf5779baf8df5a90aafb9f18a21fcf1fe3573103641 [root@localhost _data]# docker exec -ti nginx-test02 /bin/bash root@5b909ace1f25:/# cd /usr/share/nginx/html/ root@5b909ace1f25:/usr/share/nginx/html# echo 'sadad' >> index.html bash: index.html: Read-only file system root@5b909ace1f25:/usr/share/nginx/html# touch asdad touch: cannot touch 'asdad': Read-only file system [root@localhost _data]# docker inspect --format='{{json .Mounts}}' nginx-test02 [{"Type":"volume","Name":"nginx-vol02","Source":"/var/lib/docker/volumes/nginx-vol02/_data","Destination":"/usr/share/nginx/html","Driver":"local","Mode":"ro","RW":false,"Propagation":""}]
注意:-v
和 --mount
选项,inspect查看输出的Mounts部分的信息有差异,主要是'Mode'显示的内容不同,一个表示读写模式,一个表示selinux的标签设置。
5、使用匿名卷
定义:匿名卷没有指定明确的名称。在创建或启动容器时可以创建匿名卷。
# --mount:启动容器时不定义source [root@localhost ~]# docker run -it --mount destination=/app ubuntu /bin/bash root@eacbc9629f0f:/# ls app boot etc lib lib64 media opt root sbin sys usr bin dev home lib32 libx32 mnt proc run srv tmp var root@eacbc9629f0f:/# exit exit [root@localhost ~]# docker volume ls DRIVER VOLUME NAME local baa55a4c1cfc3aa117630efd47b2986fb9ad775be95d4f08735fc0495340ab0e [root@localhost ~]# docker volume rm baa55a4c Error: No such volume: baa55a4c 《————指定匿名卷必须使用完整的UUID [root@localhost ~]# docker rm eacbc9629f0f eacbc9629f0f [root@localhost ~]# docker volume rm baa55a4c1cfc3aa117630efd47b2986fb9ad775be95d4f08735fc0495340ab0e baa55a4c1cfc3aa117630efd47b2986fb9ad775be95d4f08735fc0495340ab0e # -v:启动容器时省略第一个字段[host-src:] [root@localhost ~]# docker run -ti -v /app ubuntu /bin/bash root@3673f14ae07a:/# ls app boot etc lib lib64 media opt root sbin sys usr bin dev home lib32 libx32 mnt proc run srv tmp var root@3673f14ae07a:/# exit exit [root@localhost ~]# docker volume ls DRIVER VOLUME NAME local db8dfec8d223d5eb3662c73249a9545ee1d982f00b52ca8b1a5e6314d843495d [root@localhost ~]# docker container prune WARNING! This will remove all stopped containers. Are you sure you want to continue? [y/N] y Deleted Containers: 3673f14ae07a660a437d615eaca1aeb012673233010d5e7e0cbc0d30c7e601f0 Total reclaimed space: 8B [root@localhost ~]# docker volume prune WARNING! This will remove all local volumes not used by at least one container. Are you sure you want to continue? [y/N] y Deleted Volumes: db8dfec8d223d5eb3662c73249a9545ee1d982f00b52ca8b1a5e6314d843495d Total reclaimed space: 0B
6、绑定挂载主机上的目录
可以通过绑定挂载将Docker主机上现有的目录挂载到容器的目录中,需要挂载的目录可以由主机的绝对路径引用。
$(pwd)
命令可以表示linux主机的当前目录,注意要用双引号包起来,否则报错。
绑定挂载的容器,不能强制删除,应该先停止后删除,否则会有警告
(1) --mount选项
# 1.准备目录,切换到新目录的父目录 [root@localhost ~]# mkdir -p source/target [root@localhost ~]# cd source/ [root@localhost source]# pwd /root/source # 2.启动容器,将主机的source/target目录挂载到容器的/app目录下 [root@localhost source]# docker run -dti --name devtest --mount type=bind,source="$(pwd)/target",target=/app nginx 497a3e9b17926b428e22c8b424a5d566a2edd8cc1211bbadd6416d65cbe13b86 # 失败的案例:绑定挂载必须使用已经存在的目录: [root@localhost source]# docker run -dti --name devtest01 --mount type=bind,source="$(pwd)/test",target=/app nginx docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /root/source/test. # 3.查看容器的信息,验证绑定挂载是否创建 [root@localhost source]# docker inspect --format='{{json .Mounts}}' devtest [{"Type":"bind","Source":"/root/source/target","Destination":"/app","Mode":"","RW":true,"Propagation":"rprivate"}] # type说明挂载方式为绑定挂载,源和目标路径都是正确的,Propagation(传播)方式是:rprivate(私有的)。 # Mode:表示与selinux标签有关的选项。 # z选项表示绑定挂载的内容在多个容器之间共享。 # Z选项表示绑定挂载的内容是私有的。 # 4.停止并删除容器 [root@localhost source]# docker rm -f devtest devtest # 5.启动只读绑定挂载容器 [root@localhost source]# docker run -dti --name devtest --mount type=bind,source="$(pwd)"/target,target=/app,readonly nginx 586c51f2b909903e4a755a85685bb4b1d9a7b5f2bb226f2bcc4c2f8fae1cf270 # 6.查看容器的信息 [root@localhost source]# docker inspect --format='{{json .Mounts}}' devtest [{"Type":"bind","Source":"/root/source/target","Destination":"/app","Mode":"","RW":false,"Propagation":"rprivate"}] # RW为false,说明为只读模式
(2)-v选项
# 1.准备目录,切换到新目录的父目录 [root@localhost ~]# mkdir -p source/target [root@localhost ~]# cd source/ [root@localhost source]# pwd /root/source # 2.启动容器,将主机的source/target目录挂载到容器的/app目录下 [root@localhost source]# docker run -dti --name devtest -v "$(pwd)/target":/app nginx 9efef939c123a1b2e7f4b053008d4699c0dc4f1f879c40ea81614f24e9acec04 # 3.查看容器的信息,验证绑定挂载是否创建 [root@localhost source]# docker inspect --format='{{json .Mounts}}' devtest [{"Type":"bind","Source":"/root/source/target","Destination":"/app","Mode":"","RW":true,"Propagation":"rprivate"}] # type说明挂载方式为绑定挂载,源和目标路径都是正确的,Propagation(传播)方式是:rprivate(私有的)。 # 4.停止并删除容器 [root@localhost source]# docker stop devtest devtest [root@localhost source]# docker rm devtest devtest # 5.启动只读绑定挂载容器 [root@localhost source]# docker run -dti --name devtest -v "$(pwd)/target":/app:ro nginx c56f97fd97247eaa3fe02edeef6e298944944575d023e16a60365edb53911aa3 # 6.查看容器的信息 [root@localhost source]# docker inspect --format='{{json .Mounts}}' devtest [{"Type":"bind","Source":"/root/source/target","Destination":"/app","Mode":"ro","RW":false,"Propagation":"rprivate"}] # Mode为"ro",为只读模式
7、绑定挂载主机上的文件
绑定挂载文件主要用于主机与容器之间共享配置文件
配置文件置于Docker主机中,并挂载到容器,可以随时更改配置,将配置管理变简单
# 1.查看主机的时区 [root@localhost source]# date +%z +0800 # 2.启动一个ubuntu容器查看时区 [root@localhost source]# docker run -tid --rm --name test ubuntu /bin/bash a688f13a3d1eb1e2d252b68df657517f3325145823c9ce2c83cdb7e0fb6c889d [root@localhost source]# docker exec -ti test /bin/bash root@a688f13a3d1e:/# date +%z +0000 # 3.启动一个绑定挂载文件的容器查看时区 [root@localhost source]# docker run -tid --rm --name test01 -v /etc/localtime:/etc/localtime ubuntu /bin/bash bda7b3deca99bd39985df06a0c875114c3867f7411477ccbe220dcf08260e4a6 [root@localhost source]# docker exec -ti test01 /bin/bash root@bda7b3deca99:/# date +%z +0800
8、绑定挂载主机上不存在的目录或文件
绑定挂载Docker主机上不存在的目录或文件,--mount
和-v
选项的表现不同
(1)-v选项:自动创建目录
# 启动容器,查看路径,并退出 [root@localhost ~]# docker run -ti --rm -v /doestnt/exist:/foo ubuntu bash root@8fcdd361f44f:/# cd foo/ root@8fcdd361f44f:/foo# pwd /foo root@8fcdd361f44f:/foo# exit exit # 在docker主机查看新创建的路径 [root@localhost /]# ls bin dev etc lib media opt root sbin sys usr boot doestnt home lib64 mnt proc run srv tmp var [root@localhost /]# ls /doestnt/exist/
(2)--mount选项:报错
[root@localhost /]# docker run -ti --rm --mount type=bind,source=/doesnt/exist,destination=/foo ubuntu bash docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /doesnt/exist.
9、绑定挂载到容器中的非空目录
如果将主机上的目录绑定挂载到容器上的非空目录,则容器挂载的目录中的现有内容会被绑定挂载(主机上的目录)所遮盖
- 被遮盖的目录和文件不会被删除或更改,但在使用绑定挂载时不可访问
- 无论主机上的目录是否为空,绑定挂载到容器中的非空目录都会发生被遮盖的情况
[root@localhost /]# docker run -tid --name broken-test --mount type=bind,source=/tmp,target=/etc/yum.repos.d centos cb7c523f56bd7ae4293bb83a27074f35f9abd319c9d08a94d9b17d072ddffad1 [root@localhost /]# docker exec -ti broken-test /bin/bash [root@cb7c523f56bd /]# cd /etc/yum.repos.d/ [root@cb7c523f56bd yum.repos.d]# ls vmware-root <————遮盖了容器之前的内容
10、备份、恢复和迁移数据卷
可以通过卷容器(Volume Container)实现卷的备份、恢复和迁移。
卷容器(数据卷容器):一种特殊的容器,专门用来将卷(或绑定挂载)提供给其他容器挂载。
--volumes-from
选项:创建容器时使用这个选项,可基于卷容器创建一个新的容器,并挂载卷容器提供的卷。
(1)创建卷容器
# 创建卷容器,挂载一个匿名卷 [root@localhost tmp]# docker create -v /dbdata --name dbstore busybox /bin/sh e0bf42be22e492c1377112967dd113d6cfc6b0bd2483adef84f9f0da962c2806 [root@localhost tmp]# docker volume ls DRIVER VOLUME NAME local e3440f88e29fdb974db84419090554c2d61bd78819a86650446f3f69a5030783 [root@localhost tmp]# docker inspect --format='{{json .Mounts}}' dbstore [{"Type":"volume","Name":"e3440f88e29fdb974db84419090554c2d61bd78819a86650446f3f69a5030783","Source":"/var/lib/docker/volumes/e3440f88e29fdb974db84419090554c2d61bd78819a86650446f3f69a5030783/_data","Destination":"/dbdata","Driver":"local","Mode":"","RW":true,"Propagation":""}]
(2)备份卷容器
[root@localhost tmp]# docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvfP /backup/backup.tar /dbdata /dbdata/ [root@localhost tmp]# ls backup.tar vmware-root [root@localhost tmp]# du -sh * 12K backup.tar 0 vmware-root # 执行命令会完成一下操作: # 1. 启动一个新的容器并从dbstore容器中挂载卷。 # 2. 将本地主机的当前目录挂载为/backup。 # 3. 传送一个命令将dbdata卷的内容打包为/backup/backup.tar文件。
(3)从备份恢复卷容器
创建备份后,可以将它恢复到同一个容器,或另一个容器。
# 1. 创建一个新卷容器 [root@localhost tmp]# docker run -v /dbdata --name dbstore2 ubuntu /bin/bash # 2. 在新容器的数据卷中将备份文件解压 [root@localhost tmp]# docker run -tid --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /backup && tar xvf backup.tar && /bin/bash" e4a269b16d16e03e8e8fa4bd94940d03e7425c2671573bf570a3f42a2f2f29a2 [root@localhost tmp]# docker exec -ti e4a269b16d16 /bin/bash root@e4a269b16d16:/# cd /backup/ root@e4a269b16d16:/backup# ls backup.tar dbdata vmware-root <————dbdata为解压出的文件夹
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)