容器存储

时间:Nov. 30, 2018 分类:

目录:

容器存储

容器存储分为两种

  • storage driver管理的镜像层和容器层
  • Data Volume数据卷

storage driver

镜像分层

容器由最上面一个可写的容器层,以及若干只读的镜像层组成,容器的数据就存放在这些层中。这样的分层结构最大的特性是 Copy-on-Write:

  1. 新数据会直接存放在最上面的容器层。
  2. 修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变。
  3. 如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。

分层结构使镜像和容器的创建、共享以及分发变得非常高效,而这些都要归功于 Docker storage driver。正是 storage driver 实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图。

Docker 支持多种 storage driver,有 AUFS、Device Mapper、Btrfs、OverlayFS、VFS 和 ZFS。它们都能实现分层的架构,同时又有各自的特性。对于 Docker 用户来说,具体选择使用哪个 storage driver 是一个难题,因为:

  1. 没有哪个driver能够适应所有的场景。
  2. driver本身在快速发展和迭代。

Docker优先使用Linux发行版默认的storage driver,Docker安装时会根据当前系统的配置选择默认的driver。默 driver具有最好的稳定性,因为默认driver在发行版上经过了严格的测试。

$ docker info | grep 'Storage Driver'
Storage Driver: overlay2

各层数据存放在/var/lib/docker/overlay2/

Data Volume

Data Volume和数据层的应用场景

  1. Database 软件 vs Database 数据
  2. Web 应用 vs 应用产生的日志
  3. 数据分析软件 vs input/output 数据

有持久化数据的需求,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据,也就是说,这类容器是有状态的。

Data Volume的特点

  1. Data Volume是目录或文件,而非没有格式化的磁盘(块设备)
  2. 容器可以读写volume中的数据
  3. volume数据可以被永久的保存,即使使用它的容器已经销毁

bind mount

将主机上已存在的目录或文件挂载到容器,通过-v的参数,格式为<host path>:<container path>

$ mkdir htdocs
$ echo testfile > htdocs/index.html
$ docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
40799eaff89805f66bf3eb8014965c34b0f9f8207a2906380e4358cf5a8a3dfc
$ curl 127.0.0.1:80
testfile

/usr/local/apache2/htdocs是httpd镜像存放静态文件的地方,由于/usr/local/apache2/htdocs已经存在,原来的数据被隐藏,取而代之是挂载的目录,和linux的mount命令是一致的。

更新一下主机上的文件

$ echo change > htdocs/index.html 
$ curl 127.0.0.1:80
change

销毁容器

$ docker stop 40799eaff89805f66bf3eb8014965c34b0f9f8207a2906380e4358cf5a8a3dfc
40799eaff89805f66bf3eb8014965c34b0f9f8207a2906380e4358cf5a8a3dfc
$ docker rm 40799eaff89805f66bf3eb8014965c34b0f9f8207a2906380e4358cf5a8a3dfc
40799eaff89805f66bf3eb8014965c34b0f9f8207a2906380e4358cf5a8a3dfc
[root@VM_146_207_centos ~]# cat htdocs/index.html
change

容器没有本机数据依然正常

bind的时候默认容器是可写可读bind的目录下文件,可以通过一下方式进行只读操作

docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs:ro httpd

这样bind有一些局限性就是需要考虑主机的一些目录结构

docker managed volume

$ docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
26f042d2779e9ef5940a0036c3df3cb017e5c2e30a8a01a83da771d81a74e803
$ docker inspect 26f042d2779e9ef5940a0036c3df3cb017e5c2e30a8a01a83da771d81a74e803
...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "ada1620ee7c986b5d17fc16ba4aecf3fa55ca9693964eae2345cda74bb670cfe",
                "Source": "/var/lib/docker/volumes/ada1620ee7c986b5d17fc16ba4aecf3fa55ca9693964eae2345cda74bb670cfe/_data",
                "Destination": "/usr/local/apache2/htdocs",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
...

当然也可以看到docker volume inspect 26f042d2779e9ef5940a0036c3df3cb017e5c2e30a8a01a83da771d81a74e803

可以看到在启动容器后在/var/lib/docker/volumes/目录生成了一个目录

$ cat /var/lib/docker/volumes/ada1620ee7c986b5d17fc16ba4aecf3fa55ca9693964eae2345cda74bb670cfe/_data/index.html
<html><body><h1>It works!</h1></body></html>

数据和容器中的完全一致,是因为对原有目录或文件数据会拷贝的volume,这样数据依然是data volume管理数据,而不是storage driver

两个的区别

区别 bind mount managed volume
volume位置 任意指定 /var/lib/docker/volumes/
对已有mount point的影响 隐藏并替换 将原有数据复制到volume
是否支持单个文件 支持 不支持
权限控制 默认为读写,可设置为只读 无控制,均为只读

容器数据共享

volume container

docker create创建一个只提供数据的容器,不需要运行

$ docker create --name vc_data -v ~/htdocs:/usr/local/apache2/htdocs -v /other busybox
a817043acb216c6786c5b4402944041a9776ac343607e07a4026e19de0f7b57b
$ docker inspect vc_data

        "Mounts": [
            {
                "Type": "bind",
                "Source": "/root/htdocs",
                "Destination": "/usr/local/apache2/htdocs",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "volume",
                "Name": "4dd49c4339df779f42cb3c36db287c5da8b40f679387868cd82c73a4420286f0",
                "Source": "/var/lib/docker/volumes/4dd49c4339df779f42cb3c36db287c5da8b40f679387868cd82c73a4420286f0/_data",
                "Destination": "/other",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
$ docker run --name web-01 -d -p 80 --volumes-from vc_data httpd
c0e37573f51dd7d8886cdc9ce11b9ee804f49a9aeec541bdc176b6e58db57542
$ docker run --name web-02 -d -p 80 --volumes-from vc_data httpd
ff955643844a9b3cebb86757f66257e2fa9faf7d0064b5b37bf7bc97231eef9f

查看以容器为volume的信息

$ docker inspect ff955643844a9b3cebb86757f66257e2fa9faf7d0064b5b37bf7bc97231eef9f
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/root/htdocs",
                "Destination": "/usr/local/apache2/htdocs",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "volume",
                "Name": "4dd49c4339df779f42cb3c36db287c5da8b40f679387868cd82c73a4420286f0",
                "Source": "/var/lib/docker/volumes/4dd49c4339df779f42cb3c36db287c5da8b40f679387868cd82c73a4420286f0/_data",
                "Destination": "/other",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

可以看到和原来的endpoint都一样

$ docker ps  -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
ff955643844a        httpd               "httpd-foreground"       10 minutes ago      Up 10 minutes       0.0.0.0:32770->80/tcp    web-02
c0e37573f51d        httpd               "httpd-foreground"       10 minutes ago      Up 10 minutes       0.0.0.0:32769->80/tcp    web-01
a817043acb21        busybox             "sh"                     39 minutes ago      Created                                      vc_data
$  curl 0.0.0.0:32770
change
$ curl 0.0.0.0:32769
change
$ echo change2 > htdocs/index.html 
$ curl 0.0.0.0:32770
change2
$ curl 0.0.0.0:32769
change2

测试了一下修改也是可以共享存储

volume container的容器和mount point是一致的,有利于配置的规范和标准化,但也带来一定的局限

data-packed volume container

将数据打包进容器

Dockerfile

FROM busybox
ADD htdocs /usr/local/apache2/htdocs
VOLUME /usr/local/apache2/htdocs

VOLUME的作用与-v等效,用来创建docker managed volumemount point/usr/local/apache2/htdocs

构建镜像

 docker build -t datapacked .
Sending build context to Docker daemon  32.77kB
Step 1/3 : FROM busybox
 ---> 59788edf1f3e
Step 2/3 : ADD htdocs /usr/local/apache2/htdocs
 ---> 851f80870f62
Step 3/3 : VOLUME /usr/local/apache2/htdocs
 ---> Running in d331b29e9958
Removing intermediate container d331b29e9958
 ---> c9baf47f1acc
Successfully built c9baf47f1acc
Successfully tagged datapacked:latest

创建volume container

$ docker create --name vc_data datapacked
115d3ab27af31a132cb1292ee89409764c6f7622a2a10f98d81e0778d9affa52

启动容器使用心得volume

$ docker run --name web -d -p 80:80 --volumes-from vc_data httpd
7057e2014b3d635b6101691f7bc6abbc1107b3ca5ab802886d6ea3fb4acb86c0
$ curl 127.0.0.1
change2

data-packed volume container是自包含的,不依赖host提供数据,具有很强的移植性,非常适合只使用静态数据的场景,比如应用的配置信息、web server的静态文件等

备份

直接备份本地挂载点数据即可

恢复

将备份数据拷贝到挂载点

迁移

数据和容器一起拷贝并启动

销毁

  • docker不会销毁bind mount,需要在主机进行删除
  • docker managed volume,在执行docker rm删除容器时可以带上-v参数,docker会将容器使用到的volume一并删除,但前提是没有其他容器mount该volume
$ docker volume ls
DRIVER              VOLUME NAME
$ docker run --name bbox -v /test/data busybox
$ docker volume ls
DRIVER              VOLUME NAME
local               1b0c55f6797e20040e0b51cb7922c370b2e7f0ae735f605daa3a4fe554e2af84
$ docker rm bbox
bbox
$ docker volume ls
DRIVER              VOLUME NAME
local               1b0c55f6797e20040e0b51cb7922c370b2e7f0ae735f605daa3a4fe554e2af84
$ docker volume rm 1b0c55f6797e20040e0b51cb7922c370b2e7f0ae735f605daa3a4fe554e2af84
1b0c55f6797e20040e0b51cb7922c370b2e7f0ae735f605daa3a4fe554e2af84
$ docker volume ls
DRIVER              VOLUME NAME

对于没有使用-v参数的孤儿volume,可以使用docker volume rm删除