Docker技术入门与实战 第二版-学习笔记-7-数据管理(volume)

Docker 数据管理 node

为何要进行数据管理呢?由于当咱们在使用container时,可能会在里面建立一些数据或文件,可是当咱们停掉或删除这个容器时,这些数据或文件也会一样被删除,这是咱们并不想看见的事情,因此咱们要进行数据管理,实现持久化存储python

在容器中管理数据主要有两种方式: mysql

  • 数据卷(Data volumes)
  • 数据卷容器(Data volume containers)

 

一.若是使用的是-v参数的方法指定挂载的数据卷web

其实本质都是在运行docker run命令时,使用-v参数将主机的某个目录做为容器的数据卷。使用-v挂载数据卷时有两种状况:sql

  • 挂载的是本机的某个指定目录到容器的某个目录上(连接的方式)
  • 使用的是docker本身管理的数据卷volume(存放在/var/lib/docker/volumes下)

1.第一种状况好比:docker

docker run -it -v $(pwd)/hostDirectory:/containerDirectory ubuntu;14.04

这种状况挂载的就是本机的某个目录到了容器的某个目录上数据库

这种状况下须要注意下面的几点内容:ubuntu

  • 本地的目录必须是全路径,即以/或者~/开头的路径,如~/.bash_history:/.bash_history,不然会被当成第二种状况被处理
  • 若是指定的本地目录在本地不存在时,docker会在本地自动建立该目录
  • 若是指定的容器目录在容器中不存在时,docker会在容器中自动建立该目录
  • 若是指定的容器目录中已经有内容的话,这些内容都会被本地目录中的内容覆盖掉

2.第二种状况就是好比下面的一个例子:bash

userdeMacBook-Pro:~ user$ docker run -d -P --name web -v /webapp training/webapp python app.py

其并无指定要链接本地的什么目录,因此docker就会自动建立一个匿名的volume,并将其挂载到容器中的/webapp目录上,从其返回的挂载信息可见:app

         "Mounts": [
            {
                "Type": "volume",
                "Name": "2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105",
                "Source": "/var/lib/docker/volumes/2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105/_data",
                "Destination": "/webapp",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

可见其匿名生成了一个2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105/_data目录,将其挂载到了容器的/webapp目录上

 

除了docker自动帮咱们建立volume外,咱们还能够本身建立并查看相应的信息:

userdeMBP:~ user$ docker volume create myVolume
myVolume
userdeMBP:~ user$ docker volume ls
DRIVER              VOLUME NAME
local               6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637
local               49bfc006ae2ebc343cdf59c0af674d7e16f70466f2e9a186ac34e61deb0cb027
local               71a809c56c488bc15078d7b715ddda461eef698643bec14fe53237e66c12eb62
local               933a418456d65bafb6f77989ea120a2da8dd62c7efccd2828d2e716e3111c530
local               myVolume
userdeMBP:~ user$ docker volume inspect myVolume
[
    {
        "CreatedAt": "2018-12-18T09:23:22Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/myVolume/_data",
        "Name": "myVolume",
        "Options": {},
        "Scope": "local"
    }
]

而后就可以使用这个数据卷,将其挂载到相应的容器中:

docker run -it -v myVolume:/mydata ubuntu:14.04

须要注意的内容是:

若是volume是空的,容器目录非空,那么docker会将容器目录里面的内容拷贝到volume中

若是volume中已经有内容,无论容器中有没有内容,都会将容器中的内容覆盖

 

二.使用的是Dockerfile

1.

固然,除了使用-v参数外,还可以在Dockerfile中使用VOLUME挂载数据卷

#Dockerfile
VOLUME /mydata

这样docker也会建立一个匿名的volume,而后将其挂载到相应容器的/mydata目录上,这样,若是/mydata中是有数据的,将会拷贝到匿名volume中

它的效果和docker run -it -v /mydata imageName是同样的

由于Dockerfile的方法每一次运行时都会自动生成一个匿名的volume,若是你想要在不一样的容器之间共享数据的话,仍是要使用上面本身建立一个myVolume,而后将其挂载的方法

docker run -it -v myVolume:/mydata ubuntu:14.04

 

2.

⚠️须要注意的一点:

在Dockerfile的VOLUME指令后面是不能对该volume进行任何更改的,好比:

FROM debian:wheezy
RUN useradd foo
VOLUME /data
RUN touch /data/x  //生成新文件夹
RUN chown -R foo:foo /data  //更改权限

上面执行的结果与你预期是不符的,咱们原本但愿touch命令在镜像的文件系统上运行,可是实际上它是在一个临时容器的Volume上运行,因此应该作的是:

FROM debian:wheezy
RUN useradd foo
RUN mkdir /data && touch /data/x
RUN chown -R foo:foo /data
VOLUME /data

 

3.当咱们的镜像是经过Dockerfile生成的,若是在Dockerfile中使用的本地目录下的代码须要更改时,为了避免用每次更改都要从新运行build去生成一个新的镜像,方法就是将将代码所在的相应目录挂在到数据卷上,好比:

COPY . /mydata  #把当前的目录拷贝到 skeleton
WORKDIR /mydata

解决办法就是运行镜像时,写成:

docker run -d -p 80:5000 -v $(pwd):/mydata ubuntu:14.04

使用-v $(pwd):/mydata,这样$(pwd)中的数据就会与容器/mydata中的数据同步,这样修改时,会自动刷新数据

 

下面是比较详细的讲解

1) 数据卷

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,能够提供不少有用的特性:

  • 数据卷能够在容器之间共享和重用
  • 对数据卷的修改会立马生效
  • 对数据卷的更新,不会影响镜像
  • 数据卷默认会一直存在,即便容器被删除

⚠️数据卷的使用,相似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的数据卷。

 

建立一个数据卷

在用 docker run命令的时候,使用 -v 标记来建立一个数据卷并挂载到容器里。

在一次 run 中屡次使用能够挂载多个数据卷。

userdeMacBook-Pro:~ user$ docker run -d -P --name web -v /webapp training/webapp python app.py
Unable to find image 'training/webapp:latest' locally
latest: Pulling from training/webapp
e190868d63f8: Pull complete 
909cd34c6fd7: Pull complete 
0b9bfabab7c1: Pull complete 
a3ed95caeb02: Pull complete 
10bbbc0fc0ff: Pull complete 
fca59b508e9f: Pull complete 
e7ae2541b15b: Pull complete 
9dd97ef58ce9: Pull complete 
a4c1b0cb7af7: Pull complete 
Digest: sha256:06e9c1983bd6d5db5fba376ccd63bfa529e8d02f23d5079b8f74a616308fb11d
Status: Downloaded newer image for training/webapp:latest
1ad71e9d38081c38dcd355fd7a438cd9f94503e8bc28e99a48c0738b51e7efef

注意:也能够在 Dockerfile 中使用 VOLUME来添加一个或者多个新的卷到由该镜 像建立的任意容器。

 

 

删除数据卷

数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器 被删除后自动删除数据卷,而且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。

若是须要在删除容器的同时移除数据卷。能够在删除容器的时候使用 docker rm -v 这个命令。

 

挂载一个主机目录做为数据卷

使用 -v 标记也能够指定挂载一个本地主机的目录到容器中去

docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py

上面的命令加载主机的 /src/webapp目录到容器的 /opt/webapp目录。

这个功能在进行测试的时候十分方便,好比用户能够放置一些程序到本地目录/src/webapp中,来查看容器是否正常工做。

本地目录的路径必须是绝对路径,若是目录不存在 Docker 会自动为你建立它。

⚠️Dockerfile 中不支持这种用法,这是由于 Dockerfile 是为了移植和分享用 的。然而,不一样操做系统的路径格式不同,因此目前还不能支持。

 

Docker 挂载数据卷的默认权限是读写,用户也能够经过 :ro 指定为只读。

docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py

 

查看数据卷的具体信息

查看的是上面运行的docker run -d -P --name web -v /webapp training/webapp python app.py命令生成的volume

userdeMacBook-Pro:~ user$ docker inspect web
[
    {
        "Id": "1ad71e9d38081c38dcd355fd7a438cd9f94503e8bc28e99a48c0738b51e7efef",
        "Created": "2018-12-15T09:34:23.600548467Z",
        "Path": "python",
        "Args": [
            "app.py"
        ],

        ...

         "Mounts": [
            {
                "Type": "volume",
                "Name": "2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105",
                "Source": "/var/lib/docker/volumes/2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105/_data",
                "Destination": "/webapp",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

        ...

在输出的内容中找到其中和数据卷相关的部分,能够看到全部的数据卷都是建立在主机的 /var/lib/docker/volumes/下面的

 

挂载一个本地主机文件做为数据卷——不推荐

-v 标记也能够从主机挂载单个文件到容器中:

docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
这样就能够记录在容器输入过的命令了

⚠️若是直接挂载一个文件,不少文件编辑工具,包括 vi 或者sed --in-place ,可能会形成文件 inode 的改变,从 Docker 1.1 .0起,这会致使报错误信息。

因此最简单的办法就直接挂载文件的父目录。

 

2) 数据卷容器——实现持续更新数据在容器间共享

数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。

首先,建立一个名为 dbdata 的数据卷容器:

docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres

而后其余的容器就可以使用--volumes-from来挂载dbdata容器中的数据卷/dbdata :

$docker run -d --volumes-from dbdata --name db1 training/postgres
$docker run -d --volumes-from dbdata --name db2 training/postgres

一个容器可使用超过一个的 --volumes-from参数来指定从多个容器挂载不一样的数据卷

也能够挂载其余已经挂载了数据卷容器的容器来实现级联挂载数据卷:

docker run -d --name db3 --volumes-from db1 training/postgres

⚠️:使用--volumes-from参数所挂载数据卷的容器本身不须要保持在运行状态

若是删除了挂载的容器(包括 dbdatadb1 db2),数据卷并不会被自动删除。

因此若是想要删除一个数据卷,必须在删除最后一个还挂载着它的容器时使用docker rm -v命令来指定同时要删除的数据卷

 

 

3)利用数据卷容器来备份、恢复、迁移数据卷

备份

首先使用 --volumes-from标记来建立一个加载 dbdata 容器卷的容器,并从主机挂载当前目录到容器的 /backup 目录,如:

docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

容器启动后,使用了 tar命令来将 /dbdata 卷备份为容器中的/backup/backup.tar 文件,同时也就会在主机当前目录下生成名为 backup.tar的文件。

 

恢复

若是要恢复数据到一个容器,首先建立一个带有空数据卷的容器 dbdata2

docker run -v /dbdata --name dbdata2 ubuntu /bin/bash

而后建立另外一个容器busybox,挂载 dbdata2 容器卷中的数据卷,也指定将数据卷中的内容挂载到容器中的/backup下,这样该容器的/backup下就有了backup.tar文件,而后使用untar解压备份文件/backup/backup.tar到挂载的容器卷中:

docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar

为了查看/验证恢复的数据,能够再启动一个容器busybox挂载一样的容器卷,而后运行ls /dbdata来查看:

docker run --volumes-from dbdata2 busybox /bin/ls /dbdata

 

 

 4)学习docker volume命令的使用

1> 首先查看该命令的使用方式

userdeMBP:~ user$ docker volume --help  //查看该命令的使用方式

Usage:    docker volume COMMAND

Manage volumes //管理数据卷

Commands:
  create      Create a volume ,建立一个数据卷
  inspect     Display detailed information on one or more volumes 展现一个或多个数据卷的详细信息
  ls          List volumes 列举出全部现有的数据卷
  prune       Remove all unused local volumes 移除全部如今并无在使用的数据卷
  rm          Remove one or more volumes 移除指定的一个或多个数据卷

Run 'docker volume COMMAND --help' for more information on a command.

 

2> 列举查看本地现有的volume

userdeMBP:~ user$ docker volume ls //查看以前生成的数据卷,都是匿名数据卷
DRIVER              VOLUME NAME
local               2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105
local               4f059cc319550b606b40d1198866fcc8822267a9d6631c8f44a24619d4fe312e
local               6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637
local               49bfc006ae2ebc343cdf59c0af674d7e16f70466f2e9a186ac34e61deb0cb027
local               71a809c56c488bc15078d7b715ddda461eef698643bec14fe53237e66c12eb62
local               933a418456d65bafb6f77989ea120a2da8dd62c7efccd2828d2e716e3111c530
local               a49c6e5e7497f3d1bfcb11159a5144030e03fd7cba21e3bd6ac9b12cc6e8ea76

 

3> 详细查看其中某一个volume的信息:

userdeMBP:~ user$ docker volume inspect 2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105 //详细查看其中某一个数据卷的信息
[
    {
        "CreatedAt": "2018-12-15T09:34:23Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105/_data",
        "Name": "2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105",
        "Options": null,
        "Scope": "local"
    }
]

 

4> 将其中不在使用的本地数据卷给删除

userdeMBP:~ user$ 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:  //这是被删除掉的数据卷
a49c6e5e7497f3d1bfcb11159a5144030e03fd7cba21e3bd6ac9b12cc6e8ea76
2e8085436ec33315c8c034a87097df301e9ce1c04a9a9f5ce007344c6cef3105
4f059cc319550b606b40d1198866fcc8822267a9d6631c8f44a24619d4fe312e

Total reclaimed space: 77.23kB
userdeMBP:~ user$ docker volume ls //这些是还剩下的数据卷
DRIVER              VOLUME NAME
local               6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637
local               49bfc006ae2ebc343cdf59c0af674d7e16f70466f2e9a186ac34e61deb0cb027
local               71a809c56c488bc15078d7b715ddda461eef698643bec14fe53237e66c12eb62
local               933a418456d65bafb6f77989ea120a2da8dd62c7efccd2828d2e716e3111c530

 

5>本身手动建立一个非匿名的volume

userdeMBP:~ user$ docker volume create myVolume 而后能够建立一个非匿名的数据卷myVolume
myVolume
userdeMBP:~ user$ docker volume ls
DRIVER              VOLUME NAME
local               6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637
local               49bfc006ae2ebc343cdf59c0af674d7e16f70466f2e9a186ac34e61deb0cb027
local               71a809c56c488bc15078d7b715ddda461eef698643bec14fe53237e66c12eb62
local               933a418456d65bafb6f77989ea120a2da8dd62c7efccd2828d2e716e3111c530
local               myVolume
userdeMBP:~ user$ docker volume inspect myVolume
[
    {
        "CreatedAt": "2018-12-18T09:23:22Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/myVolume/_data",
        "Name": "myVolume",
        "Options": {},
        "Scope": "local"
    }
]

 

 

6)删除容器

userdeMBP:~ user$ docker volume inspect 6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637
[
    {
        "CreatedAt": "2018-12-15T07:28:50Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637/_data",
        "Name": "6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637",
        "Options": null,
        "Scope": "local"
    }
]
userdeMBP:~ user$ docker volume rm 6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637 
Error response from daemon: remove 6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637: volume is in use - [b4a512f0230fa598e7e40171e0597ea6db0740105449314a1a3767dcaa4a0edb]
userdeMBP:~ user$ docker inspect b4a512f0230fa598e7e40171e0597ea6db0740105449314a1a3767dcaa4a0edb //该容器正在运行,因此其挂载的数据卷是不能被删除的
[
    {
        "Id": "b4a512f0230fa598e7e40171e0597ea6db0740105449314a1a3767dcaa4a0edb",
        "Created": "2018-12-15T07:28:26.800359991Z",
        "Path": "/entrypoint.sh",
        "Args": [
            "/etc/docker/registry/config.yml"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 3006,
            "ExitCode": 0,
            "Error": "",
            ...

userdeMBP:~ user$ docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
2084e92eea8c        ubuntu:14.04        "/bin/bash"              7 hours ago         Up 7 hours                                   boring_jackson
b4a512f0230f        registry            "/entrypoint.sh /etc…"   3 days ago          Up 8 hours          0.0.0.0:5000->5000/tcp   registry

userdeMBP:~ user$ docker volume rm myVolume //而后删除一个没有使用的数据卷就成功了
myVolume

 

5)如今咱们进行一个例子小实验:

1> 首先建立一个mysql1容器,生成mysql数据卷挂载在该容器的/var/lib/mysql目录上

userdeMBP:~ user$ docker run -d -v mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
a5a6f2f73cd8: Already exists 
936836019e67: Pull complete 
283fa4c95fb4: Pull complete 
1f212fb371f9: Pull complete 
e2ae0d063e89: Pull complete 
5ed0ae805b65: Pull complete 
0283dc49ef4e: Pull complete 
a7e1170b4fdb: Pull complete 
88918a9e4742: Pull complete 
241282fa67c2: Pull complete 
b0fecf619210: Pull complete 
bebf9f901dcc: Pull complete 
Digest: sha256:b7f7479f0a2e7a3f4ce008329572f3497075dc000d8b89bac3134b0fb0288de8
Status: Downloaded newer image for mysql:latest
71f78959d2a823e55a723cde747ee833f52138bf04f0f8ec33189ea902bb2356

 

2>查看生成的mysql数据卷

userdeMBP:~ user$ docker volume ls //如今可见生成了一个mysql数据卷
DRIVER              VOLUME NAME
local               6dcce8fa7b5bed65b8bdf8cb91603cfa4e993439ec20e921a6742808b6478637
local               49bfc006ae2ebc343cdf59c0af674d7e16f70466f2e9a186ac34e61deb0cb027
local               71a809c56c488bc15078d7b715ddda461eef698643bec14fe53237e66c12eb62
local               933a418456d65bafb6f77989ea120a2da8dd62c7efccd2828d2e716e3111c530
local               mysql
userdeMBP:~ user$ docker volume inspect mysql //查看该数据卷的详细内容
[
    {
        "CreatedAt": "2018-12-18T10:21:16Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/mysql/_data",
        "Name": "mysql",
        "Options": null,
        "Scope": "local"
    }
]

 

3> 而后对朝该数据卷中写入数据

userdeMBP:~ user$ docker exec -it mysql1 /bin/bash
root@71f78959d2a8:/# mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.13 MySQL Community Server - GPL

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql> create database docker; //生成一个新的数据库
Query OK, 1 row affected (0.08 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| docker             |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

mysql> exit
Bye
root@71f78959d2a8:/# exit
exit
userdeMBP:~ user$ docker rm -f mysql1 //而后移除mysql1这个容器
mysql1

 

4> 而后从新打开一个mysql2容器,挂载以前生成的mysql数据卷,以验证数据是否成功共享:

userdeMBP:~ user$ docker run -d -v mysql:/var/lib/mysql --name mysql2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
6f242e6fc8341f2b809f2d54bef294e718658a3db8c595dfc84955b5b4b0f7a8

userdeMBP:~ user$ docker exec -it mysql2 /bin/bash
root@6f242e6fc834:/# mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.13 MySQL Community Server - GPL

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases; //而后查看数据库,是能够看见以前在容器mysql1上生成的docker数据库的,可见数据成功共享了
+--------------------+
| Database           |
+--------------------+
| docker             |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

mysql> 
相关文章
相关标签/搜索