docker入门(4)--数据卷管理

任何有意义的应用都会产生或者使用一些数据。而容器本身是无状态的。我们使用数据卷(volumes)来解决这个问题。数据卷允许容器使用,产生和修改数据。数据卷比容器拥有更高等级的生命周期,当使用volume的容器结束时,volume依然存在。

1. 创建和挂载数据卷

1.1 修改容器内数据

在正式开始介绍数据卷之前,我们先看看直接在容器内进行数据修改操作会发生什么。
在容器内新增一个文件:

docker container run --name demo \
    alpine /bin/sh -c 'echo "This is a test" > sample.txt'

容器与基础镜像进行比较:

docker container diff demo

结果类似如下:

A /sample.txt

当停止并移除这个容器后,你新建的sample.txt文件也会随之删除,再也无法继续使用。

1.2 创建数据卷

如下命令创建一个名为my-data的数据卷:
docker volume create my-data
默认的数据卷驱动称之为本地驱动,它将数据存储在本机的文件系统上。如果你需要了解数据卷的详细信息,可使用docker volume inspect命令进行核查。
docker volume inspect my-data
得到类似如下结果:

[
    {
        "CreatedAt": "2018-10-29T13:58:22+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-data/_data",
        "Name": "my-data",
        "Options": {},
        "Scope": "local"
    }
]

tips:docker还支持以插件形式使用的,第三方的一些数据卷驱动,例如:云存储,NFS,SDN(软件定义网络)存储。只需要在创建数据卷时,使用--driver参数进行指定即可。

1.3 挂载数据卷

当我们创建了数据卷之后,就可以挂载使用它了。

docker container run --name test -it \
    > -v my-data:/data alpine /bin/sh

启动并进入容器后,执行如下命令,在容器内新建文件:

/ # cd /data
/data # echo "some data" > data.txt
/data # echo "some more data" > data1.txt
/data # exit

回到主机,我们在/var/lib/docker/volumes/my-data/_data/目录下,可以看到:

[root@node2 ~]# ll /var/lib/docker/volumes/my-data/_data/
total 8
-rw-r--r-- 1 root root 15 Oct 29 14:13 data1.txt
-rw-r--r-- 1 root root 10 Oct 29 14:13 data.txt
[root@node2 ~]# cat /var/lib/docker/volumes/my-data/_data/data.txt 
some data
[root@node2 ~]# cat /var/lib/docker/volumes/my-data/_data/data1.txt 
some more data

接下来,我们直接在主机的数据卷目录下创建文件,然后新启动一个容器,挂载这个数据卷,看看是什么效果。

[root@node2 ~]# cd /var/lib/docker/volumes/my-data/_data/
[root@node2 _data]# echo "This file we create on the host" > host_data.txt
[root@node2 _data]# docker container rm test 
test
[root@node2 _data]# docker container run --name test2 -it \
> -v my-data:/app/data \
> centos:7 /bin/bash
Unable to find image 'centos:7' locally
7: Pulling from library/centos
aeb7866da422: Pull complete 
Digest: sha256:67dad89757a55bfdfabec8abd0e22f8c7c12a1856514726470228063ed86593b
Status: Downloaded newer image for centos:7
[root@9015fe11c4dd /]# ls /app/data
data.txt  data1.txt  host_data.txt
[root@9015fe11c4dd /]# cat /app/data/host_data.txt 
This file we create on the host

1.4 删除数据卷

我们可以使用docker volume rm来删除数据卷。特别提示:由于该操作是不可逆的,当你确认数据卷已经进行了备份,或者该数据卷确实没有其他用途的时候,你可以进行删除操作。但是,如果该数据卷如果还在使用中,是无法进行删除的。

[root@node2 _data]# docker volume rm my-data 
Error response from daemon: remove my-data: volume is in use - [9015fe11c4dd6450b2587e5b36979b64796541e7d67656003d8decae1fcc735e]
[root@node2 _data]# docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                  NAMES
9015fe11c4dd        centos:7            "/bin/bash"              8 minutes ago       Exited (0) 4 minutes ago                          test2
78a0c2a1ac94        alpine              "/bin/sh"                3 days ago          Exited (0) 3 days ago                             sample
ce3d8b9082c5        alpine              "/bin/sh"                3 days ago          Exited (0) 3 days ago                             upbeat_kirch
48a55ac2ee94        nginx:alpine        "nginx -g 'daemon of…"   3 days ago          Up 3 days                  0.0.0.0:8080->80/tcp   nginx-test
0f8cf054c73d        alpine              "echo 'hello world'"     3 days ago          Exited (0) 3 days ago                             angry_colden
f5ed73fec895        hello-world         "/hello"                 3 days ago          Exited (0) 3 days ago                             dreamy_leakey
[root@node2 _data]# docker container rm 9015fe11c4dd
9015fe11c4dd
[root@node2 _data]# docker volume rm my-data 
my-data

2. 在容器之间分享数据

有些时候,容器之间是需要进行数据交互的。有可能A容器产生的数据,将用于给B容器进行读取使用,但为了避免冲突(同时对文件的修改),我们可以在挂载数据卷的时候设置一些读写权限。

[root@node2 ~]# docker volume create shared-data
shared-data
# 创建一个写文件的容器
[root@node2 ~]# docker container run --name writer -it \
> -v shared-data:/data \
> alpine /bin/sh
/ # cd /data
/data # touch data-from-writer.txt
/data # ls
data-from-writer.txt
# 创建一个只能读的容器,并挂载shared-data数据卷
[root@node2 ~]# docker container run --name only-reader -it \
> -v shared-data:/data:ro \
> centos:7 /bin/bash
[root@cf058c0af6af /]# cd /data/
[root@cf058c0af6af data]# touch data.txt
touch: cannot touch 'data.txt': Read-only file system

3. 使用主机目录进行挂载

除了数据卷,我们还可以将主机上的某个目录直接挂载到容器内,如下:

docker container run -d -v /my-web:/usr/share/nginx/html -p 8080:80 nginx:alpine

4. 在Dockerfile中定义数据卷

对于一些应用,例如数据库,我们肯定是需要进行数据持久化的,但是面对不同的使用者和不同的使用环境,我们的官方镜像是如何在面对不同环境时,主动的去定义一个数据卷呢?答案是:在Dockerfile中就定义好数据卷,这样生成的镜像在启动时,就会自动的创建数据卷。

# 列出目前已有的volume
[root@node2 ~]# docker volume ls
DRIVER              VOLUME NAME
local               shared-data
# 创建一个mongo容器
[root@node2 ~]# docker container run -d --name my-mongo mongo:3.7
e65ac72b9c3fc7abdcc05121b55c87543baccc3b27bf17be6ad0ec1212211141
# 查看自动添加的volume
[root@node2 ~]# docker volume ls
DRIVER              VOLUME NAME
local               065a116f6ef50622aa3e1f674f81cc61d13e4618b6f726b5fd77f4813fcc5e84
local               10242f5b75f1ba88e1e2abdbb2cc874887f4181353ea62ca6f2c6735c32b0e7b
local               shared-data

我们也可以使用docker image inspect命令来审查镜像的数据卷相关配置。

[root@node2 ~]# docker image inspect \
> --format='{{json .ContainerConfig.Volumes}}' \
> mongo:3.7 | jq
{
  "/data/configdb": {},
  "/data/db": {}
}

上面的结果显示,mongo:3.7这个image会创建两个volume。
我们也可以通过docker container inspect命令来审查当前运行容器的数据卷挂载情况。

[root@node2 ~]# docker container inspect --format '{{json .Mounts}}' my-mongo | jq
[
  {
    "Type": "volume",
    "Name": "065a116f6ef50622aa3e1f674f81cc61d13e4618b6f726b5fd77f4813fcc5e84",
    "Source": "/var/lib/docker/volumes/065a116f6ef50622aa3e1f674f81cc61d13e4618b6f726b5fd77f4813fcc5e84/_data",
    "Destination": "/data/configdb",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  },
  {
    "Type": "volume",
    "Name": "10242f5b75f1ba88e1e2abdbb2cc874887f4181353ea62ca6f2c6735c32b0e7b",
    "Source": "/var/lib/docker/volumes/10242f5b75f1ba88e1e2abdbb2cc874887f4181353ea62ca6f2c6735c32b0e7b/_data",
    "Destination": "/data/db",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  }
]

5. 关于使用volume还是bind mounts(本机目录)的建议

首先请参考这几篇官方文章:
Manage data in Docker
Use volumes
Use bind mounts
以下内容为谷歌翻译:

卷的好处:
  • 在多个运行容器之间共享数据。如果未显式创建它,则会在第一次将其装入容器时创建卷。当该容器停止或被移除时,该卷仍然存在。多个容器可以同时安装相同的卷,可以是
    读写也可以是只读。仅在您明确删除卷时才会删除卷。
  • 当Docker主机不能保证具有给定的目录或文件结构时。Volumes可帮助您将Docker主机的配置与容器运行时分离。
  • 如果要将容器的数据存储在远程主机或云提供程序上,而不是本地存储。
  • 当您需要备份,还原或将数据从一个Docker主机迁移到另一个Docker主机时,卷是更好的选择。您可以使用卷停止容器,然后备份卷的目录(例如/var/lib/docker/volumes/<volume-name>)。
绑定挂载的好处:

通常,您应该尽可能使用卷。绑定适用于以下类型的用例:

  • 将配置文件从主机共享到容器。这就是Docker默认通过/etc/resolv.conf从主机安装到每个容器中来为容器提供DNS解析的方式 。
  • 在Docker主机上的开发环境和容器之间共享源代码或构建工件。例如,您可以将Maven target/ 目录安装到容器中,每次在Docker主机上构建Maven项目时,容器都可以访问重建的工件。
    如果您以这种方式使用Docker进行开发,您的生产Dockerfile会将生产就绪工件直接复制到映像中,而不是依赖于绑定装载。
  • 当Docker主机的文件或目录结构保证与容器所需的绑定装载一致时。

6. 关于使用-v参数还是--mount参数的建议

docker新用户,我们建议使用--mount,但是这个参数只能在docker 17.06版本以后才可以使用。
--mount参数使用如下:

$ docker service create \
     --mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"'
    --name myservice \
    <IMAGE>

--mount与-v的区别:

As opposed to bind mounts, all options for volumes are available for both --mount and -v flags.
When using volumes with services, only --mount is supported.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349