欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Docker中的数据管理

程序员文章站 2022-06-03 10:00:07
...

Manage data in Docker

默认一个容器内部创建的文件被存储到一个可写的容器层。这就意味着:

  • 当一个容器不存在的时候,他的数据不能被持久化(一起销毁了),并且其他进程需要从容器中取出数据是困难的
  • 一个容器的可写层是和正在运行容器的主机是紧耦合的,你很难移动这些数据到其他地方去
  • 向一个容器的可写层写数据需要一个管理文件系统的存储驱动。这个存储驱动使用Linux内核提供的union filesysem。相较于直接向主机的文件系统交互数据的数据卷(data volumes),这种额外的抽象降低了性能

Docker有两种方式volumes, 和 bind mounts向容器主机存储文件,因此即便容器被停止了,文件依然可以被持久化。


1. 如何正确的选择挂载方式

Docker中的数据管理

  • Volumes 是被Docker管理的存储在主机文件系统(/var/lib/docker/volumes/ 在Linux)的一部分。非Docker进程不应该修改这部分文件系统。Volumes是在Docker中最好的数据持久方式。
  • Bind mounts 可以被存储到主机文件系统的任何地方。它们可能是重要的系统文件或目录。在Docker主机上的非Docker进程或Docker容器都可以在任何时候修改它们。

2. 关于挂载类型的更多细节

  • Volumes: 被Docker创建和管理。你可以使用docker volume create命令明确的创建一个Volume,或者Docker会在创建一个容器或者服务期间创建一个Volume。
    当你创建一个Volume,它被存储到Docker主机的一个目录里。当你挂载这个Volume到一个容器,这个目录成为被挂在到容器的目录。除了那些Volumes是被Docker管理,并且与主机的核心功能相隔离,其余和bind mounts很像。
    一个给定的Volume可以同时被挂载道多个容器。当没有一个运行的容器在使用这个Volume,这个Volume对Docker来说依旧是可用的,并且不会被自动移除,你可以使用docker volume prune移除不用的Volumes。
    当你挂在一个Volume,它会是一个被命名的或匿名的。当匿名的Volume被第一次挂在到一个容器时,它们没有被指定明确的名字,因此Docker给它们分配了一个随机的名字来确保它们在Docker主机中式唯一的。除了名称不一样,命名的和匿名的Volumes使用是一致的。
    Volumes也支持Volumes Drivers的使用,Volumes Drivers 允许你存储你的数据到一个远程主机或云提供商或其他可以的方式。
  • bind mounts: 从Docker早期的版本就开始支持。bind mounts 和 Volume相比有些限制功能。当你使用bind mount,一个主机的文件或目录会被挂载到一个容器中。这个文件或目录被这个主机的全路径所引用。这个文件或目录不需要一开始就存在在这个Docker主机上。需要的时候再创建。bind mount是性能优异的,但是它依赖于一个被指定的可用的目录结构的主机文件系统。如果你开发一个新的Docker 应用,请考虑使用一个命名的Volume替代。你无法使用Docker CLI命令直接管理bind mounts。

Bind mounts allow access to sensitive files
One side effect of using bind mounts, for better or for worse, is that you can change the host filesystem via processes running in a container, including creating, modifying, or deleting important system files or directories. This is a powerful ability which can have security implications, including impacting non-Docker processes on the host system.、


3. Volumes

数据卷Volumes相较于bind mount是更好的数据持久化方案,Volumes相较于bind mount的几个优势:

  • Volumes更容易备份和迁移
  • 可以使用Docker CLI 和 Docker API管理
  • 可以工作在Linux和Windows容器上
  • 在多个容器间共享数据更安全
  • 可以存储到远程主机,加密Volumes的内容,添加其他功能
  • 可以先于容器构建
    Docker中的数据管理
    详见官网说明:Use Volumes

3.1 举例演示

-v还是选--mount
一开始,-v--volume 参数用于单容器,而--mount参数用于集群服务。然而,从Docker 17.06 版本开始,你可以使用 --mount 用于单容器。

新手应该尝试使用 --mount,它比 --volume语法更简单

MySQL 5.6的Dockerfile

...
VOLUME /var/lib/mysql
...

3.2 验证删除容器Volume依然存在

当我们新建docker run -d --name mysql01 -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.6一个mysql容器时,会自动创建随机但唯一的Volume 65125ede...

[aaa@qq.com docker]# docker run -d --name mysql01 -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.6
Unable to find image 'mysql:5.6' locally
...
Digest: sha256:60c27b50ca72d81d92a743a965a82f124a4e123c7d374a021887286408878d60
Status: Downloaded newer image for mysql:5.6
c3a5d78c0c732b63bf062ff6cef7120cb0e86d1f424a03df7d61eb518439cc84
[aaa@qq.com docker]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
c3a5d78c0c73        mysql:5.6           "docker-entrypoint.s…"   42 seconds ago      Up 39 seconds       0.0.0.0:3306->3306/tcp   mysql01
[aaa@qq.com docker]# docker volume ls
DRIVER              VOLUME NAME
local               65125ede1e3c6fee4cc29803c5f82c400c801ef69cc7dd0dc18f3692b6d0899c

查看一下mysql容器信息 docker inspect mysql01 会发现有一个名称是

"Name": "65125ede..."

[aaa@qq.com docker]# docker inspect mysql01
[
    {
        ...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "65125ede1e3c6fee4cc29803c5f82c400c801ef69cc7dd0dc18f3692b6d0899c",
                "Source": "/var/lib/docker/volumes/65125ede1e3c6fee4cc29803c5f82c400c801ef69cc7dd0dc18f3692b6d0899c/_data",
                "Destination": "/var/lib/mysql",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
       ...
]

删除这个容器实例docker rm -f mysql01,容器的Volume还依然存在

[aaa@qq.com docker]# docker rm -f mysql01
mysql01
[aaa@qq.com docker]# docker volume ls
DRIVER              VOLUME NAME
local               65125ede1e3c6fee4cc29803c5f82c400c801ef69cc7dd0dc18f3692b6d0899c
[aaa@qq.com docker]#

3.3 验证容器共享Volume

先创建一个未指定端口的mysql01(上面mysql01的已被删除)
docker run -d --name mysql01 -v mysql:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.6

[aaa@qq.com docker]# docker run -d --name mysql01 -v mysql:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.6
2149914dbbaa0092a9437ba1a91e7944828ddb61fd76d553b031e95d01aaebe0

展示volume docker volume ls

[aaa@qq.com docker]# docker volume ls
DRIVER              VOLUME NAME
local               mysql

进入mysql01创建一个docker数据库
docker exec -it mysql01 /bin/bash

[aaa@qq.com docker]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
2149914dbbaa        mysql:5.6           "docker-entrypoint.s…"   22 seconds ago      Up 21 seconds       3306/tcp            mysql01
[aaa@qq.com docker]# docker exec -it mysql01 /bin/bash
aaa@qq.com:/# mysql -uroot
...
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)

mysql> create database docker;
Query OK, 1 row affected (0.01 sec)

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

mysql> exit
Bye
aaa@qq.com:/# exit
exit

删除mysql01但是不影响Volume mysql
docker rm -f 2149914dbbaa

[aaa@qq.com docker]# docker rm -f 2149914dbbaa
2149914dbbaa
[aaa@qq.com docker]# docker volume ls
DRIVER              VOLUME NAME
local               mysql

创建mysql02,同时使用Volume mysql
docker run -d --name mysql02 -v mysql:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.6

[aaa@qq.com docker]# docker run -d --name mysql02 -v mysql:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.6
54f4f0d5ec70ed69d49598e99d43a511212e7e603e57f1a57e1f5f230174ed9c
[aaa@qq.com docker]# docker ps

进入mysql02,查看数据库列表发现docker数据已存在
docker exec -it mysql02 /bin/bash

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
54f4f0d5ec70        mysql:5.6           "docker-entrypoint.s…"   4 seconds ago       Up 3 seconds        3306/tcp            mysql02
[aaa@qq.com docker]# docker exec -it mysql02 /bin/bash
aaa@qq.com:/# mysql -uroot
...
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| docker             |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)

mysql> exit
Bye
aaa@qq.com:/# exit
exit
[aaa@qq.com docker]#

4. bind mount

Use bind mounts

bind mount 源于早期的Docker版本。bind mount 相较于 volumes功能有限。当你使用bind mount时,一个主机的文件或目录被挂载到一个容器中。这个文件或目录被主机的全路径或相对路径所引用。相较之下,当你创建一个Volume,一个新的目录会被创建到这个主机的Docker存储目录中,并且Docker管理这些目录。需要的时候再创建。bind mount是性能优异的,但是它依赖于一个被指定的可用的目录结构的主机文件系统。如果你开发一个新的Docker 应用,请考虑使用一个命名的Volume替代。你无法使用Docker CLI命令直接管理bind mounts。
Docker中的数据管理
启动一个nginx,把主机的目录/usr/local/nginx挂载到容器的/usr/share/nginx/html
docker run -d --name mynginx -p 80:80 -v /usr/local/nginx:/usr/share/nginx/html nginx:latest

[aaa@qq.com nginx]# docker run -d --name mynginx -p 80:80 -v /usr/local/nginx:/usr/share/nginx/html nginx:latest
28bf0fc82e89da5f49281386ad3ed2e369b377e4c5dd8494a91474a124eaa84b
[aaa@qq.com nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
28bf0fc82e89        nginx:latest        "nginx -g 'daemon of…"   6 seconds ago       Up 5 seconds        0.0.0.0:80->80/tcp   mynginx
[aaa@qq.com nginx]#

我们知道默认的nginx的首页是
Docker中的数据管理
现在我们在/usr/local/nginx下创建一个index.html

<!doctype html>
<html><head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to my docker nginx!</h1>
</body>
</html>

访问nginx首页
Docker中的数据管理
在修改一下index.html

<!doctype html>
<html><head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to my docker nginx!</h1>
<h1>Welcome to my docker nginx!</h1>
<h1>Welcome to my docker nginx!</h1>
</body>
</html>

在访问首页
Docker中的数据管理

进入到nginx容器中

[aaa@qq.com nginx]# docker exec -it mynginx /bin/bash
aaa@qq.com:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr
aaa@qq.com:/# cd /usr/share/nginx/html/
aaa@qq.com:/usr/share/nginx/html# ls
index.html
aaa@qq.com:/usr/share/nginx/html# touch myfile.txt
aaa@qq.com:/usr/share/nginx/html# ls
index.html  myfile.txt
this is container addr/share/nginx/html# echo "this is container add" > myfile.tx
aaa@qq.com:/usr/share/nginx/html# cat myfile.txt
this is container add
aaa@qq.com:/usr/share/nginx/html# exit
exit

进入/usr/local/nginx查看,容器内部做的修改容器外是可见的

[aaa@qq.com nginx]# ll
total 8
-rwxr--r-- 1 root root 340 May 26 10:13 index.html
-rw-r--r-- 1 root root  22 May 26 10:16 myfile.txt
[aaa@qq.com nginx]# less myfile.txt
[aaa@qq.com nginx]# cat myfile.txt
this is container add
[aaa@qq.com nginx]#
相关标签: Docker