Dockerfile_volume

Docker 数据卷

2020-01-28  本文已影响0人  _于曼丽_

介绍

镜像本身是只读的,保持不变。从镜像启动一个容器的时候,会在镜像的最上一层创建一个可写层。容器对于文件系统的写操作只会修改可写层,不会修改镜像。

容器运行的过程中产生的数据全都存储到可写层中,当我们删除掉这个容器的时候,同时也会删除掉可写层上的文件。如果有些数据你想一直保存,比如 Web 服务器的日志、数据库管理系统里的数据,怎么办?

我们可以创建一个数据卷,然后将数据卷挂载到容器上指定的目录,这样容器的这个目录便不属于容器的镜像文件系统了,而属于数据卷都对应着的主机上的一个物理目录 /var/lib/docker/volumes/数据卷名/_data。因此将容器的数据保存在数据卷上,就相当于保存到了对应的主机目录上,即便容器被删除了,数据卷中的数据也会一直保存。

命令

docker volume create
docker volume inspect
docker volume ls
docker volume prune
docker volume rm
docker create -v
docker create --volumes-from
docker run -v
docker run --volumes-from

docker volume create

使用 docker volume create 命令创建一个数据卷,该数据卷并没有挂载到任何容器。以下代码创建了一个名称为 foo 的数据卷,该数据卷对应着主机上的 /var/lib/docker/volumes/foo/_data 物理目录。

$ docker volume create foo

docker create -v / docker run -v

使用 docker create -vdocker run -v 命令创建容器时,可以使用 -v 参数将容器的指定目录挂载到指定的数据卷。以下代码创建了一个容器 db1 ,然后将容器的 /data 目录挂载到已经存在的名为 foo 的数据卷。

$ docker create -v foo:/data --name db1 centos

以下代码创建了一个名为 db2 的容器,然后将容器的 /data 目录挂载到名为 bar 的数据卷,由于 bar 数据卷不存在,所以在创建容器的时候会先创建一个名为 bar 的数据卷,然后将 /data 目录挂载到 bar 数据卷,该数据卷对应着主机上的 /var/lib/docker/volumes/bar/_data 物理目录。

$ docker create -v bar:/data --name db2 centos

以下代码创建了一个名为 db3 的容器,然后将容器的 /data 目录挂载到匿名的数据卷。创建容器的时候会先创建一个名为随机字符串的数据卷,然后将 /data 目录挂载到该数据卷,该数据卷对应着主机上的 /var/lib/docker/volumes/随机字符串/_data 物理目录。

$ docker create -v /data --name db3 centos

以下代码创建了一个名为 db4 的容器,然后将容器的 /data 目录挂载到指定的主机目录的绝对路径,这个主机目录并不是数据卷,因此通过数据卷命令 docker volume 无法管理该主机目录。

$ docker create -v /Users/yumanli/Desktop/data:/data --name db4 centos

可以使用 :ro 来绑定只读的数据卷,只能绑定具名数据卷或者主机目录。

$ docker create -v foo:/data:ro --name db1 centos
$ docker create -v /Users/yumanli/Desktop/data:/data:ro --name db4 centos

不能使用 :ro 来绑定匿名数据卷,以下代码会报错。

$ docker create -v /data:ro --name db3 centos

docker volume ls

使用 docker volume ls 命令查看所有的数据卷。

$ docker volume ls
DRIVER              VOLUME NAME
local               6cda7f4532a18c226ae419cee91c7d08ca6fe6e409914b25f368b8edea641a09
local               bar
local               foo

使用 docker volume ls -f dangling=true 命令查看没有被挂载到容器的数据卷。

$ docker volume create baz
$ docker volume ls -f dangling=true
DRIVER              VOLUME NAME
local               baz

docker volume inspect

使用 docker volume inspect 命令查看数据卷的信息,Name 字段为数据卷的名字,Mountpoint 字段为数据卷挂载的主机目录。

$ docker volume inspect foo bar baz 6cda7f4532a18c226ae419cee91c7d08ca6fe6e409914b25f368b8edea641a09
[
    {
        "CreatedAt": "2020-01-28T02:29:32Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/foo/_data",
        "Name": "foo",
        "Options": {},
        "Scope": "local"
    },
    {
        "CreatedAt": "2020-01-28T02:29:46Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/bar/_data",
        "Name": "bar",
        "Options": null,
        "Scope": "local"
    },
{
        "CreatedAt": "2020-01-28T03:02:30Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/baz/_data",
        "Name": "baz",
        "Options": {},
        "Scope": "local"
    },
    {
        "CreatedAt": "2020-01-28T02:29:53Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/6cda7f4532a18c226ae419cee91c7d08ca6fe6e409914b25f368b8edea641a09/_data",
        "Name": "6cda7f4532a18c226ae419cee91c7d08ca6fe6e409914b25f368b8edea641a09",
        "Options": null,
        "Scope": "local"
    }
]

docker volume rm

使用 docker volume rm 命令删除数据卷,该命令只能删除没有被挂载到容器的数据卷。

$ docker volume rm baz

对于已经被挂载到容器的数据卷,必须先删除相关容器,再删除数据卷。db1 容器挂载了 foo 数据卷,要想删除 foo 数据卷,必须先删除 db1 容器。

$ docker rm db1
$ docker volume rm foo

可以使用 docker rm -v 命令,在删除容器的同时删除该容器挂载的数据卷。该命令只能删除匿名数据卷(名字为一串随机字符串的数据卷),不会删除具名数据卷。db2 容器挂载了 bar 数据卷,db3 容器挂载了匿名数据卷 6cda7f4532a18c226ae419cee91c7d08ca6fe6e409914b25f368b8edea641a09,使用以下命令不会删除 bar 数据卷。

$ docker rm -v db2 db3
$ docker volume ls
local               bar

docker volume prune

使用 docker volume prune 命令删除所有没有被挂载到容器的数据卷,不管该数据卷是具名的还是匿名的。

$ 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:
bar

docker create --volumes-from / docker run --volumes-from

使用 docker create --volumes-fromdocker run --volumes-from 命令创建容器时,可以使用 --volumes-from 参数使得新创建的容器与已有的容器共享数据卷。

以下代码将 db2 容器的 /data 目录与 db1 容器的 /data 目录绑定到同一个具名数据卷 foo (对应着主机上的同一个物理目录 /var/lib/docker/volumes/foo/_data),因此 db1 和 db2 容器可以共享数据。

$ docker create -v foo:/data --name db1 centos
$ docker create --volumes-from db1 --name db2 centos

以下代码可以通过另一种方式实现同样的功能。首先创建一个具名数据卷 foo,然后分别创建两个容器 db1 和 db2,并绑定到这个数据卷 foo,这样也可以实现多个容器共享数据卷。

$ docker volume create foo
$ docker create -v foo:/data --name db1 centos
$ docker create -v foo:/data --name db2 centos

如果一些数据,比如配置文件、数据文件等,要在多个容器之间共享,一种常见的做法是创建一个数据容器,其他容器与之共享 volume。

以下代码先创建了一个名为 db 的容器作为数据容器,将该容器 /data 目录挂载到一个匿名数据卷(也可以挂载到具名数据卷或主机目录)。然后又创建了 db1 和 db2 两个容器,并通过 --volumes-from 参数指定 db1 和 db2 容器与 db 容器共享数据卷,这样 db 容器的 /data 目录、db1 容器的 /data 目录和 db2 容器的 /data 目录都挂载到一个相同的数据卷(对应着主机上的同一个物理目录),因此他们可以共享数据。

$ docker create -v /data --name db centos
$ docker create --volumes-from db --name db1 centos
$ docker create --volumes-from db --name db2 centos

Dockerfile VOLUME

使用 Dockerfile 文件的 VOLUME 参数可以事先指定某个镜像挂载的数据卷。

FROM centos
VOLUME ["/data"]

使用 docker build 命令基于该 Dockerfile 创建一个镜像。

$ docker build -t yumanli/centos .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM centos
 ---> 470671670cac
Step 2/2 : VOLUME ["/data"]
 ---> Running in 89f3f2cf040f
Removing intermediate container 89f3f2cf040f
 ---> d2cf56c8d1bd
Successfully built d2cf56c8d1bd
Successfully tagged yumanli/centos:latest

通过该镜像创建容器的时候,就不需要通过 -v 参数挂载数据卷了,该容器会使用 Dockerfile 文件的 VOLUME 参数挂载数据卷。

$ docker run --name db yumanli/centos
$ docker inspect db
"Mounts": [
    {
        "Type": "volume",
        "Name": "740bba034eb3e28d0f7fd4227651c0364ec15011db73abdfcd299fce51aa2cbd",
        "Source": "/var/lib/docker/volumes/740bba034eb3e28d0f7fd4227651c0364ec15011db73abdfcd299fce51aa2cbd/_data",
        "Destination": "/data",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
]

使用 docker run -v 命令创建容器可以在 Dockerfile 文件的 VOLUME 参数基础上挂载新的数据卷。

$ docker run -v /foo --name db2 yumanli/centos
$ docker inspect db2
"Mounts": [
    {
        "Type": "volume",
        "Name": "9b159b8b28e99424937b54b205daa7708db3839e5baa23557cc03bcdc72e60ac",
        "Source": "/var/lib/docker/volumes/9b159b8b28e99424937b54b205daa7708db3839e5baa23557cc03bcdc72e60ac/_data",
        "Destination": "/foo",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    },
    {
        "Type": "volume",
        "Name": "b5cd187a31c03f175f4d576f45b74f8d04f552a5d00d85efe149f0cfa720a9c0",
        "Source": "/var/lib/docker/volumes/b5cd187a31c03f175f4d576f45b74f8d04f552a5d00d85efe149f0cfa720a9c0/_data",
        "Destination": "/data",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
]
上一篇 下一篇

猜你喜欢

热点阅读