Docker 数据管理
数据管理
Docker的数据管理是指在Docker容器中对数据进行存储、共享、备份和持久化的方法和技术。它允许用户在保持容器轻量级的同时,确保容器产生的数据能够安全、高效地存储和管理。主要的技术有三种数据挂载方式
![](3-Docker 数据管理/cd09b2d732da72b743dc5c5d68f7e0f6.png)
数据卷(Volumes)
- 数据卷是Docker管理的、独立于容器的存储区域,提供了数据持久化和容器间共享的能力。
- 数据卷存储在Docker主机上的特定目录,默认是
/var/lib/docker/volumes/
(Linux系统),并且可以在容器间共享而不依赖于任何单一容器的生命周期。 - 即使容器被删除,数据依然存在。
绑定挂载(Bind mounts)
- 绑定挂载是将宿主机上的文件系统路径直接挂载到容器内的过程。
- 这种方式允许直接利用宿主机的文件系统资源,但可能带来数据管理上的复杂性和安全性考量。
- 绑定挂载的存储位置和数据格式完全由宿主机控制,不受到Docker的直接管理。
- 需要注意的是,bind mount 在不同的宿主机系统时不可移植的,比如 Windows 和 Linux 的目录结构是不一样的,bind mount 所指向的 host 目录也不一样。这也是为什么 bind mount 不能出现在 Dockerfile 中的原因所在,因为这样 Dockerfile 就不可移植了。
tmpfs挂载(Tmpfs mounts)
- Tmpfs挂载是将数据存储在宿主机的内存中而不是磁盘上,适用于临时文件或对速度有高要求的场景。
- 这种类型的存储不会持久化,容器停止或宿主机重启后数据将会丢失。
- 适合存储敏感信息或缓存数据,因其不会写入磁盘,可以增加安全性。
数据卷
数据卷是一个可供一个或多个容器使用的特殊目录,他将主机操作系统目录直接映射到容器,它绕过 UFS,可以提供很多有用的特性:
数据卷
可以在容器之间共享和重用- 对
数据卷
的修改会立马生效 - 对
数据卷
的更新,不会影响镜像 数据卷
默认会一直存在,即使容器被删除
注意:
数据卷
的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会复制到数据卷中(仅数据卷为空时会复制)。
常用命令
volume create | 创建数据卷 |
---|---|
volume inspect | 查看数据卷详情 |
volume ls | 列出数据卷 |
volume prune | 清理无用数据卷 |
volume rm | 删除数据卷 |
创建一个数据卷
创建数据卷,数据卷路径:
/var/lib/docker/volumes/
1
$ docker volume create my-vol
查看所有的
数据卷
1
2
3
4$ docker volume ls
DRIVER VOLUME NAME
local my-vol在主机里使用以下命令可以查看指定
数据卷
的信息, 通过Mountpoint, 直接在宿主机上通过找到的路径修改数据卷内的文件。1
2
3
4
5
6
7
8
9
10
11$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data", # 在宿主机上的路径
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
启动一个挂载数据卷的容器
在用 docker run
命令的时候,使用 --mount
标记来将 数据卷
挂载到容器里。在一次 docker run
中可以挂载多个 数据卷
。--mount source=要挂载的数据卷,target=挂载到容器的路径 镜像名
下面创建一个名为 web
的容器,并加载一个 数据卷
到容器的 /usr/share/nginx/html
目录。
1 | $ docker run -d -P \ |
查看数据卷的具体信息
在主机里使用以下命令可以查看 web
容器的信息
1 | $ docker inspect web |
数据卷
信息在 “Mounts” Key 下面
1 | "Mounts": [ |
删除数据卷
1 | $ docker volume rm my-vol |
数据卷
是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 数据卷
,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 数据卷
。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v
这个命令。
无主的数据卷可能会占据很多空间,要清理请使用以下命令
1 | $ docker volume prune |
读写权限
在用docker run命令时,使用-mount选项使用数据卷
1
[root@docker ~]# docker run -d -P --name nginx --mount source=test,target=/webapp nginx
默认挂载的镜像是读写权限,可以设置为只读
1
[root@docker ~]# docker run -d -P --name nginx --mount source=test,target=/webapp:ro nginx
直接挂载主机目录到容器
1
2
3# docker run -it -v /宿主机绝对目录:/容器内目录 镜像名
# 带权限的命令: docker run -it -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
[root@docker ~]# docker run -it -v /myDataVolume:/dataVolumerContainer centos
权限问题
Docker挂载主机目录Docker访问出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个
--privileged=true
参数即可例如:
docker run -t -i --privileged centos:latest bash
挂载一个主机目录作为数据卷
使用 --mount
标记可以指定挂载一个本地主机的目录到容器中去。
1 | $ docker run -d -P \ |
上面的命令加载主机的 /src/webapp
目录到容器的 /usr/share/nginx/html
目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,以前使用 -v
参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,现在使用 --mount
参数时如果本地目录不存在,Docker 会报错。
Docker 挂载主机目录的默认权限是 读写
,用户也可以通过增加 readonly
指定为 只读
。
1 | $ docker run -d -P \ |
加了 readonly
之后,就挂载为 只读
了。如果你在容器内 /usr/share/nginx/html
目录新建文件,会显示如下错误
1 | /usr/share/nginx/html # touch new.txt |
挂载一个本地主机文件作为数据卷
--mount
标记也可以从主机挂载单个文件到容器中
1 | $ docker run --rm -it \ |
这样就可以记录在容器输入过的命令了。
数据卷容器
数据卷容器是Docker中管理数据卷的一种高级用法,它允许用户创建一个专门用于数据存储的容器,并将其数据卷挂载到其他容器中。这种方式使得数据可以跨容器共享,同时保持数据的持久性和可移植性。
数据卷容器主要用于数据的持久化存储和跨容器共享,它本身并不运行任何实际的应用服务,而是作为一个存储媒介存在。
创建数据卷, 启动一个挂载数据卷的容器
1
[root@docker ~]# docker run -it -d -v /dbdata --name dbdata ubuntu
创建db1和db2都挂载到同一个数据卷/dbdata目录下
1
2[root@docker ~]# docker run -it --volumes-from dbdata --name db1 ubuntu
[root@docker ~]# docker run -it --volumes-from dbdata --name db2 ubuntu可以使用
--volumes-from
参数来从多个容器挂载多个数据卷,也可以从其他已挂载的数据卷容器来挂载数据卷,向三个容器中任意一个/dbdata目录下写入,其他容器都可以看到1
[root@docker ~]# docker run -d --name db3 --volumes-from db1 training/postgres
停止了卷容器创建新容器也可以引用他
1
2
3
4
5
6
7
8
9
10
11
12
13
14[root@localhost ~]# docker stop volume_v1
volume_v1
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9bff8f66a04d nginx "/docker-entrypoint.…" 5 minutes ago Up 5 minutes 0.0.0.0:8091->80/tcp, :::8091->80/tcp web2
c036bb587750 nginx "/docker-entrypoint.…" 5 minutes ago Up 5 minutes 0.0.0.0:8090->80/tcp, :::8090->80/tcp web1
c9cff2a314fe nginx "/docker-entrypoint.…" 8 minutes ago Exited (0) 4 seconds ago volume_v1
#停止卷容器volume_v1
[root@localhost ~]# docker run -itd --name web3 -p 8092:80 --volumes-from volume_v1 nginx
7e8a3e82e6aacf32e5194d4a47d827f718685e0811ffc478b09a6e1748fd997f
[root@localhost ~]# curl -s 192.168.112.60:8092
my_volume_test
#可以获取my_volume数据卷的内容删除卷容器后无法依据卷容器创建新容器,之前创建好的容器不会有任何影响
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15[root@localhost ~]# docker rm -f volume_v1
volume_v1
[root@localhost ~]# docker run -itd --name web4 -p 8093:80 --volumes-from volume_v1 nginx
docker: Error response from daemon: No such container: volume_v1.
See 'docker run --help'.
[root@localhost ~]# curl 192.168.112.60:8089
curl: (7) Failed connect to 192.168.112.60:8089; 拒绝连接
[root@localhost ~]# curl 192.168.112.60:8090
my_volume_test
[root@localhost ~]# curl 192.168.112.60:8091
my_volume_test
[root@localhost ~]# curl 192.168.112.60:8092
my_volume_test
#之前创建好的容器不会有任何影响如果删除了挂载卷的容器,数据卷并不会自动删除,如果要删除数据卷,必须在删除最后一个挂载着他的容器时使用
1
2# 删除容器 nginx01, 并删除容器挂载的数据卷:
docker rm -v nginx01
数据备份案例
MySQL5.6版本迁移到5.7
创建一个命名的数据卷
1
2[root@localhost ~]# docker volume create mysql_data
mysql_dataDocker安装MySQL5.6版本
-d
: 表示后台运行容器(detached模式),即容器会在后台运行而不是与当前终端交互。--name mysql-5.6
: 为容器指定一个名字,这里是mysql-5.6
,便于后续管理和识别。-p 3306:3306
: 端口映射配置,将宿主机的3306端口映射到容器内的3306端口。-v mysql_data:/var/lib/mysql/
: 数据卷挂载,mysql_data
是数据卷的名称(如果没有事先创建,Docker会自动创建一个匿名数据卷),这个数据卷挂载到容器内的/var/lib/mysql/
目录。-e MYSQL_ROOT_PASSWORD=123
: 设置环境变量,这里设置了MySQL的root用户的密码为123
。mysql:5.6
: 这是Docker镜像的名称和标签,表示使用mysql
镜像的5.6
版本来创建容器。
1
2
3
4[root@localhost ~]# docker run -d --name mysql-5.6 -p 3306:6606 -v mysql_data:/var/lib/mysql/ -e MYSQL_ROOT_PASSWORD=123 mysql:5.6
[root@localhost ~]# cd /var/lib/docker/volumes/mysql_data/_data/
[root@localhost _data]# ls
auto.cnf ibdata1 ib_logfile0 ib_logfile1 mysql performance_schema进入容器创建数据
1
2
3
4
5
6
7
8
9
10[root@localhost _data]# docker exec -it mysql-5.6 /bin/bash
root@7ef4b48ecbcf:/# cd /var/lib/mysql
root@7ef4b48ecbcf:/var/lib/mysql# ls
auto.cnf ib_logfile0 ib_logfile1 ibdata1 mysql performance_schema
root@7ef4b48ecbcf:/var/lib/mysql# mysql -uroot -p123
# 创建了个stu表插入了一条数据
mysql> create database test;
mysql> use test;
mysql> create table stu (id int(5),name varchar(20),age int(5));
mysql> insert into stu values(1,"zhangsan",18);删除mysql-5.6容器
1
docker rm -f mysql-5.6
Docker安装MySQL5.7版本
1
[root@localhost ~]# docker run -d --privileged=true --name mysql-5.7 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123 -v mysql_data:/var/lib/mysql/ mysql:5.7
进入容器进行验证 可以看到之前mysql-5.6创建的数据还在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33[root@localhost ~]# docker exec -it mysql-5.7 /bin/bash
bash-4.2# mysql -uroot -p123
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| stu |
+----------------+
1 row in set (0.00 sec)
mysql> select * from stu;
+------+----------+------+
| id | name | age |
+------+----------+------+
| 1 | zhangsan | 18 |
+------+----------+------+
1 row in set (0.00 sec)
数据卷容器中的数据进行进行备份
备份:首先使用
--volumes-from
命令创建一个加载 dbdata 的容器卷容器,并将宿主机当前目录挂载到容器的 /backup 目录,命令如下:1
2
3
4
5
6[root@docker ~]# docker run --volumes-from dbdata -v $(pwd):/backup --name worker ubuntu tar cvf /backup/backup.tar /dbdata
# --name worker ubuntu 使用ubuntu镜像创建名为worker的容器
# --volumes-from dbdata 让worker容器挂载dbdata容器的数据卷
# -v $(pwd):/backup 挂载本地的当前目录到worker容器的/backup目录
# tar cvf /backup/backup.tar /dbdata 将/dbdata下内容备份为容器内的/backup/backup.tar容器启动后,使用了
tar
命令来将 dbdata 数据卷备份为容器中 /backup/backup.tar 文件,因为挂载了的关系,宿主机的当前目录下也会生成backup.tar
备份文件。恢复:如果要恢复数据到一个容器,
1
2
3
4
5
6# 首先创建一个带有空数据卷的容器 dbdata2。
$ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
# 然后创建另一个容器,挂载 dbdata2 容器卷中的数据卷,并使用 untar 解压备份文件到挂载的容器卷中
$ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf
/backup/backup.tar为了查看/验证恢复的数据,可以再启动一个容器挂载同样的容器卷来查看:
1
$ sudo docker run --volumes-from dbdata2 busybox /bin/ls /dbdata
-v
和 --mount
区别
都是挂载命令,使用 -v
挂载时,如果宿主机上没有指定文件不会报错,会自动创建指定文件;当使用 –mount时,如果宿主机中没有这个文件会报错找不到指定文件,不会自动创建指定文件。
bind mount 使用
通过 bind mount 模式可以挂载到宿主机的任意位置,示例如下:
1 | docker run -d -it --name=test-nginx -p 8011:80 -v /docker/nginx1:/usr/share/nginx/html nginx:1.13.12 |
-v /docker/nginx1:/usr/share/nginx/html
: 将宿主机中的 `` 目录挂载到容器中的/usr/share/nginx/html
目录;bind mount 这种方式会隐藏目录中的内容(非空情况下),这里的
/usr/share/nginx/html
目录下的 html 文件被隐藏了,所以我们看不到。1
2
3
4
5# 容器运行成功后,进入容器中:
docker exec -it test-nginx /bin/bash
# 目录下的 html 文件被隐藏
cd /usr/share/nginx/html
# ls 结果为空如果将宿主机中创建文件, 该目录中的文件立刻挂载到容器中
1
2
3
4cd /docker/nginx1
touch index.html
# 容器内访问 ls会得到 index.html