docker存储管理

docker存储概念

容器本地存储与Docke存储驱动

容器本地存储:每个容器都被自动分配了内部存储,即容器本地存储。采用的是联合文件系统。通过存储驱动进行管理。

容器本地存储空间:分层结构构成,由一个可写容器层和若干只读的镜像层组成。

联合文件系统:Docker的一种底层技术,由存储驱动(Storage Driver)实现。相应的存储驱动有aufs、overlay、overlay2、devicemapper、btrfs、zfs、vfs等。

存储驱动:控制镜像和容器在 docker 主机上的存储和管理方式。

每个Docker主机只能选择一种存储驱动,不能为每个容器选择不同的存储驱动。

查看主机支持的存储驱动
[root@localhost ~]# docker info
# 找到如下信息
 Storage Driver: overlay2           # 存储驱动是overlay2
  Backing Filesystem: xfs           # 底层文件系统是xfs
  Supports d_type: true             # 支持d_type
  Native Overlay Diff: true
  userxattr: false
更改现有的存储驱动

可以根据需要修改现有的存储驱动。

注意:

  • 一个主机只能选择一个存储驱动。
  • 系统版本和存储驱动的兼容问题。
  • 更改存储驱动会使得现有的容器和镜像不可访问(原因:每种存储驱动存储镜像层的位置是不同的)
  • 但恢复存储驱动,可以再次访问之前的镜像和容器
# 修改daemon.json文件来更改存储引擎配置
[root@localhost ~]# vi /etc/docker/daemon.json 
{
  "registry-mirror":["https://registry.docker-cn.com"],
  "storage-driver":"overlay"                           《————————添加这个信息
}
# 重启docker生效
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker
[root@localhost ~]# docker info
# 找到如下信息
 Storage Driver: overlay                 《————————修改生效
  Backing Filesystem: xfs
  Supports d_type: true
# 更改存储驱动会使得现有的容器和镜像不可访问
[root@localhost ~]# docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE
# 恢复存储驱动,可以再次访问之前的镜像和容器
[root@localhost ~]# vi /etc/docker/daemon.json  
{
  "registry-mirror":["https://registry.docker-cn.com"]
}
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker
[root@localhost ~]# docker images
REPOSITORY         TAG       IMAGE ID       CREATED        SIZE
ubuntu             latest    825d55fb6340   2 weeks ago    72.8MB
centos             latest    5d0da3dc9764   7 months ago   231MB

容器和非持久化数据

非持久化数据:不需要保存的数据。容器本地存储中的数据属于非持久化数据。

容器创建时会创建非持久化存储,非持久化存储自动创建,从属于容器,生命周期与容器相同。删除容器也会删除全部非持久化数据。

非持久化数据存在问题:

  1. 这类数据从属于容器,生命周期与容器相同,会随着容器的删除而被删除。(易丢失)
  2. 当该容器不再运行时,数据不会持久保存,如果另一个进程需要,则可能很难从该容器中获取数据。(难获取)
  3. 容器的可写层与运行容器的Docker主机紧密耦合,无法轻松地将数据转移到其他位置。(难转移)
  4. 写入容器的可写层需要Docker存储驱动管理文件系统。存储驱动使用Linux内核提供的联合文件系统,其性能不如直接写入主机文件系统的Docker卷。(读写性能差)

容器和持久化数据

持久化数据:需要保存的数据。例如:日志、业务数据、客户信息等有用的数据。

外部存储:Docker通过将主机中的文件系统挂载到容器中供容器存取,从而实现持久化数据存储。

容器持久化数据存储方式:Docker目前支持卷、绑定挂载,这两种挂载类型实现容器的持久化。

卷(数据卷):Docker中进行持久化数据存储的最佳方式。本质是Docker主机文件系统中的目录或文件直接挂载到容器的文件系统中。

卷和容器是解耦的,可以独立地创建并管理卷
卷不与容器的生命周期绑定(容器的停止删除和卷无关)
可以将任意数量的卷装入容器,多个容器也可以共享一个或多个卷(多对多关系)

挂载类型

往容器中挂载的外部文件系统主要有:卷、绑定挂载、tmpfs挂载。无论哪种挂载,对容器内部来说是一样的,都会显示为文件或目录。

卷存储在主机文件系统中由Docker管理的位置,在Linux主机上该位置默认就是/var/lib/docker/volumes目录。

卷是Docker持久化存储数据的最佳方式。卷支持使用卷驱动,可以让用户将数据存储在远程主机或云提供商处等。

可以以命名方式或匿名方式挂载卷:

  1. 匿名卷(Anonymous Volumes):首次挂载容器未指定名称,Docker为其随机指定一个唯一名称。
  2. 命名卷(Named Volumes):指定明确名称,和匿名卷其他特性相同。

卷由Docker创建并管理,卷适合以下应用场景。

  1. 在多个正在运行的容器之间共享数据。(数据共享)
  2. 当Docker主机不能保证具有特定目录结构时,卷有助于将Docker主机的配置与容器运行时解耦。(构建新目录与主机不同)
  3. 当需要将容器的数据存储到远程主机或云提供商处,而不是本地时。(可以远程挂载卷,公有云、灾备等场景)
  4. 当需要在两个Docker主机之间备份、恢复或迁移数据时。(主机间备份迁移)

绑定挂载

绑定挂载可以存储到主机系统的任意位置,甚至会存储到一些重要的系统文件或目录中。

特点:

  1. 主机上进程或容器可以随时修改。
  2. 相比卷,功能更受限、性能更高。
  3. 绑定挂载运行访问敏感文件。

绑定挂载适合以下应用场景。

  1. 在主机和容器之间共享配置文件。
  2. 在Docker主机上的开发环境和容器之间共享源代码或构建工件。
  3. 当Docker主机上的目录结构保证与容器要求的绑定挂载一致时。

tmpfs挂载

tmpfs挂载仅限于运行Linux操作系统的Docker主机使用,它只存储在主机的内存中,不会被写到主机的文件系统中,因此不能持久保存容器的应用数据。
在不需要将数据持久保存到主机或容器中时,tmpfs挂载最合适。
如果容器产生了非持久化数据,那么可以考虑使用tmpfs挂载避免将数据永久存储到任何位置,并且通过避免写入容器的可写层来提高容器的性能。

docker卷

docker volume是Docker卷的管理命令。

# 语法
[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                                 # 删除指定卷

创建卷

使用 docker volume create命令创建卷。

# 语法
[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"
    }
]

查看卷列表

使用 docker volume ls 命令列出当前的卷。

format关键词:

PlaceholderDescription
.NameVolume name
.DriverVolume driver
.ScopeVolume scope (local, global)
.MountpointThe mount point of the volume on the host
.LabelsAll labels assigned to the volume
.LabelValue 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=wuhan

查看卷详细信息

使用 docker volume inspect 命令查看卷详细信息。包含卷在Docker主机文件系统中的具体位置。

# 语法
[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
wuhan

删除卷

使用 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

实战

[root@localhost ~]# docker volume create volume-01
volume-01
[root@localhost ~]# docker volume inspect volume-01 
[
    {
        "CreatedAt": "2022-04-27T19:09:29+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/volume-01/_data",
        "Name": "volume-01",
        "Options": {},
        "Scope": "local"
    }
]
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     volume-01
[root@localhost ~]# docker run -it -v volume-01:/world centos /bin/bash
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
a1d0c7532777: Pull complete 
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
[root@d09338cc1750 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  world
[root@d09338cc1750 /]# ls /world/
[root@d09338cc1750 /]# exit
exit
[root@localhost ~]# docker inspect --format="{{json .Mounts}}" d09338cc1750
[{"Type":"volume","Name":"volume-01","Source":"/var/lib/docker/volumes/volume-01/_data","Destination":"/world","Driver":"local","Mode":"z","RW":true,"Propagation":""}]
[root@localhost ~]# docker  rm -f d09338cc1750
d09338cc1750
[root@localhost ~]# docker volume rm  volume-01 
volume-01

容器文件系统挂载

使用 docker rundocker create 命令的相关选项将外部的文件系统挂载到容器中。

早期版本:

  1. 卷和绑定挂载都可以通过 -v--mount 选项挂载到容器中,主要是两者的语法的细微区别。
  2. -v用于独立容器,--mount用于集群服务。
  3. tmpfs挂载可以使用 --tmpfs选项。

docker 17.06或更高版本:

  1. 建议所有的容器或服务,绑定挂载、卷、tmpfs都使用--mount选项。(语法清晰、定制详细)
  2. --mount 选项也可以用于独立容器。

-v--mount的区别:

  1. -v语法是将选项组合在一个字段中,--mount的语法是将它们分开。
  2. --mount采用键值对写法支持更多的设置选项,-v 写法更加简洁。

-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 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

–mount选项

绑定挂载、卷、tmpfs类型都使用--mount选项。

--mount选项的参数由多个由逗号分隔的键值对组成。

特殊键如下:

  • type:指定要挂载的类型,值可以是bind(绑定挂载)、volume(卷)或tmpfs。
  • source(或src):指定挂载源
  • destination(或dst、target):指定挂载目标,即容器中的挂载点,必须采用绝对路径的形式
  • readoly:指定只读选项,表示源以只读方式挂载到容器中。
  • 其他键:可以被多次指定,由若干键值对组成。卷和绑定挂载有不同的键。
[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/

卷应用示例

创建一个卷并让容器挂载

# 1.创建一个卷、查看当前卷列表、查看卷详细信息
[root@localhost ~]# docker volume create test-vol
test-vol
[root@hqs ~]# docker volume ls
DRIVER    VOLUME NAME
local     test-vol
[root@hqs ~]# 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@hqs ~]# 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@hqs ~]# 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@hqs ~]# docker volume rm test-vol
Error response from daemon: remove test-vol: volume is in use - [e6535eebe726069b355567be0a562131844ad04b175b2a0ee870d990f72dca95]
# 使用中的卷不能直接删除,第二次是先删除容器,再删除卷
[root@hqs ~]# docker rm e6535
e6535
[root@hqs ~]# docker volume rm test-vol
test-vol

启动容器时自动创建卷

启动带有卷的容器时,如果卷尚不存在,则Docker会自动创建这个卷。
示例:将myvol卷挂载到容器testnovol的/app目录下。
--mount选项实现:

[root@hqs ~]# docker run -d --name testnovol01 --mount source=myvol,target=/app nginx
beafe21868168531d1eeb69c7b29e234f0ceb60cabc60ed8e5deae0c4c99f28d
[root@hqs ~]# 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@hqs ~]# docker run -d --name testnovol02 -v myvol02:/app nginx
d7728830916fd11dec8487ea9aaf7e6f1b306b3c4c072683cf8155f430f57887
[root@hqs ~]# 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":""}]

使用容器填充卷

容器启动时挂载已经存在并包含数据的卷,则容器不会将其挂载点目录的数据复制到该卷,而是直接使用该卷的数据。

如果容器启动时挂载空白卷或自动创建新卷,而容器的挂载点目录有文件,则该挂载点的内容会复制到卷中。

# 1.执行以下命令启动一个nginx容器,并使用容器的/usr/share/nginx/html目录的内容填充新的卷nginx-vol。
[root@hqs ~]# docker run -d --name=nginxtest --mount source=nginx-vol,destination=/usr/share/nginx/html nginx
3f208b4cecc9bc98c0424dc891ae39314b9dab61985e1e957b294a799589fafb
[root@hqs ~]# 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@hqs ~]# docker volume ls
DRIVER    VOLUME NAME
local     nginx-vol
[root@hqs ~]# docker volume inspect --format='{{json .Mountpoint}}' nginx-vol
"/var/lib/docker/volumes/nginx-vol/_data"

# 3.查看主机上该卷所在目录的内容,发现容器已经填充了卷。
[root@hqs ~]# cd /var/lib/docker/volumes/nginx-vol/_data/
[root@hqs _data]# ls
50x.html  index.html
[root@hqs _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@hqs _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@hqs _data]# docker stop $(docker ps -aq)
a68b8352663b
3f208b4cecc9
d7728830916f
beafe2186816
65e5132a4a64
9c9bd6c4b789
[root@hqs _data]# docker rm $(docker ps -aq)
a68b8352663b
3f208b4cecc9
d7728830916f
beafe2186816
65e5132a4a64
9c9bd6c4b789
[root@hqs _data]# docker volume rm  $(docker volume ls -q)
myvol
myvol2
myvol02
nginx-vol

启动容器时指定一个不存在的卷,则自动创建一个空白卷。

如果是把空白卷挂载到容器已有文件的目录,则将这些文件复制到卷中。(常用于预填充容器所需数据)

使用只读卷

同一个卷可以由多个容器挂载,并且让容器执行读写操作。设置只读权限后,在容器中是无法对卷中数据修改的,可以提升安全性。

# --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的标签设置。

使用匿名卷

定义:匿名卷没有指定明确的名称。在创建或启动容器时可以创建匿名卷。

# --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

绑定挂载主机上的目录

可以通过绑定挂载将 Docker主机上现有的目录 挂载到容器的目录中,需要挂载的目录可以由 主机的绝对路径 引用。

$(pwd) 命令可以表示linux主机的当前目录,注意要用双引号包起来,否则报错。

绑定挂载的容器,不能强制删除,应该先停止后删除,否则会有报警。

–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,说明为只读模式

-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",为只读模式

绑定挂载主机上的文件

绑定挂载文件主要用于主机与容器之间共享配置文件。

配置文件置于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

绑定挂载主机上不存在的目录或文件

绑定挂载Docker主机上不存在的目录或文件,--mount-v选项的表现不同。

-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/

–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.

绑定挂载到容器中的非空目录

如果将主机上的目录绑定挂载到容器上的非空目录,则容器挂载的目录中的现有内容会被绑定挂载(主机上的目录)所遮盖。

  1. 被遮盖的目录和文件不会被删除或更改,但在使用绑定挂载时不可访问
  2. 无论主机上的目录是否为空,绑定挂载到容器中的非空目录都会发生被遮盖的情况。
[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      《————遮盖了容器之前的内容
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值