前言
默认情况下,写入到容器中的数据会随着容器的删除而消失,但有的情况下,数据需要被保存下来,今天主要来了解一下 Docker 中的数据如何持久化存储。
一、Docker数据持久化存储
默认情况下,在容器内创建的所有文件都存储在可写容器层上,这意味着:
- 当该容器不再存在时,数据不会持久存在,并且如果另一个进程需要数据,很难从容器中取出数据。
- 容器的可写层与运行容器的主机紧密耦合,不能轻易的将数据移动到其他地方。
- 写入容器的可写层需要存储驱动程序来管理文件系统,存储驱动程序使用 Linux 内核提供联合文件系统,与使用直接写入主机文件系统的数据卷相比,性能比较低。
Docker 有两个选项供容器将文件存储在主机上,以便在容器停止后文件仍然存在,volumes和 bind mounts。
1、volumes
volumes 的数据存储在宿主机中,Linux 系统中默认存储位置是 /var/lib/docker/volumes/,数据由 Docker 管理,其他软件是不能修改的。
###创建一个volume。
root@docker:~# docker volume create mydata
mydata
###查看创建的volume。
root@docker:~# docker volume ls
DRIVER VOLUME NAME
local mydata
###查看创建的volume信息。
root@docker:~# docker inspect mydata
[
{
"CreatedAt": "2023-05-13T04:11:12Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/docker/data/volumes/mydata/_data",
"Name": "mydata",
"Options": null,
"Scope": "local"
}
]
###启动一个httpd容器,并使用创建的数据卷mydata,将mydata卷挂载到httpd主目录。
root@docker:/# docker run -d -p 80:80 -v mydata:/usr/local/apache2/htdocs httpd
fda6770f9795265afbd4f63b00c356bda7d71fa9e44aa8e4dbb410613dc74acd
root@docker:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fda6770f9795 httpd "httpd-foreground" 11 minutes ago Up 11 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp compassionate_khayyam
###查看容器卷挂载的信息。
root@docker:/# docker inspect fda6770f9795 |grep -A 8 Mounts
"Mounts": [
{
"Type": "volume",
"Name": "mydata",
"Source": "/docker/data/volumes/mydata/_data",
"Destination": "/usr/local/apache2/htdocs",
"Driver": "local",
"Mode": "z",
"RW": true,
###查看数据卷目录和容器中挂载目录中的文件内容一样,容器中的数据被拷贝到了数据卷中。
root@docker:/# ls -l /docker/data/volumes/mydata/_data
total 4
-rw-r--r-- 1 504 staff 45 Jun 11 2007 index.html
root@docker:/# cat /docker/data/volumes/mydata/_data/index.html
<html><body><h1>It works!</h1></body></html>
root@docker:/# docker exec -it fda6770f9795 bash
root@fda6770f9795:/usr/local/apache2# ls -l /usr/local/apache2/htdocs
total 4
-rw-r--r-- 1 504 staff 45 Jun 11 2007 index.html
root@fda6770f9795:/usr/local/apache2# cat /usr/local/apache2/htdocs/index.html
<html><body><h1>It works!</h1></body></html>
###修改宿主机数据卷中的内容,容器中的内容也会更新。
root@docker:/# echo "HelloWord!" > /docker/data/volumes/mydata/_data/index.html
root@fda6770f9795:/usr/local/apache2# cat /usr/local/apache2/htdocs/index.html
HelloWord!
###宿主机上测试访问httpd的服务。
root@docker:/# curl http://192.168.1.128:80
HelloWord!
###停止并删除容器后,去数据卷查看文件依然存储。
root@docker:/# docker stop fda6770f9795
fda6770f9795
root@docker:/# docker rm fda6770f9795
fda6770f9795
root@docker:/# cat /docker/data/volumes/mydata/_data/index.html
HelloWord!
数据卷可以像上边这样,先创建,然后挂载给容器使用,也可以启动容器时使用 -v 参数,只指定容器中的挂载目录,会自动创建一个数据卷。
###运行一个容器,并指定容器中的挂载目录。
root@docker:/# docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
f14bc01e3fd08f1f69eeb6c04ab78b5424dc14d20f854aefe185de9b7857b4b8
root@docker:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f14bc01e3fd0 httpd "httpd-foreground" 11 seconds ago Up 10 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp mystifying_goldwasser
###查看数据卷,发现自动创建了一个数据卷。
root@docker:/# docker volume ls
DRIVER VOLUME NAME
local a98edacc177ef49c81e72c60fbef13c81b55ebedd2d1cc52ab57ff1d0fcb6126
local mydata
###查看数据卷信息。
root@docker:/# docker inspect a98edacc177ef49c81e72c60fbef13c81b55ebedd2d1cc52ab57ff1d0fcb6126
[
{
"CreatedAt": "2023-05-13T16:05:15Z",
"Driver": "local",
"Labels": {
"com.docker.volume.anonymous": ""
},
"Mountpoint": "/docker/data/volumes/a98edacc177ef49c81e72c60fbef13c81b55ebedd2d1cc52ab57ff1d0fcb6126/_data",
"Name": "a98edacc177ef49c81e72c60fbef13c81b55ebedd2d1cc52ab57ff1d0fcb6126",
"Options": null,
"Scope": "local"
}
]
###查看容器挂载信息。
root@docker:/# docker inspect f14bc01e3fd0 |grep -A 8 Mounts
"Mounts": [
{
"Type": "volume",
"Name": "a98edacc177ef49c81e72c60fbef13c81b55ebedd2d1cc52ab57ff1d0fcb6126",
"Source": "/docker/data/volumes/a98edacc177ef49c81e72c60fbef13c81b55ebedd2d1cc52ab57ff1d0fcb6126/_data",
"Destination": "/usr/local/apache2/htdocs",
"Driver": "local",
"Mode": "",
"RW": true,
数据卷不再使用了可以将其删除。
###删除之前创建的mydata数据卷。
root@docker:/# docker volume ls
DRIVER VOLUME NAME
local a98edacc177ef49c81e72c60fbef13c81b55ebedd2d1cc52ab57ff1d0fcb6126
local mydata
root@docker:/# docker volume rm mydata
mydata
root@docker:/# docker volume ls
DRIVER VOLUME NAME
local a98edacc177ef49c81e72c60fbef13c81b55ebedd2d1cc52ab57ff1d0fcb6126
2、bind mounts
bind mounts 是将宿主机上已有的目录或文件 mount 到容器中,文件或目录由其在宿主机上的绝对路径引用。bind mounts 性能非常好,但是它依赖于主机的文件系统具有特定的目录结构。
- 挂载目录
###停止并删除前面创建的容器。
root@docker:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f14bc01e3fd0 httpd "httpd-foreground" 10 hours ago Up 10 hours 0.0.0.0:80->80/tcp, :::80->80/tcp mystifying_goldwasser
root@docker:/# docker stop f14b
f14b
root@docker:/# docker rm f14b
f14b
###创建一个目录,启动容器,将目录挂载到容器中。
root@docker:/# mkdir /docker/htdocs
root@docker:/# docker run -d -p 80:80 -v /docker/htdocs:/usr/local/apache2/htdocs httpd
02d708764fe163e885e3c8985862f9bfbda7d9265e0d0dcb7a1146ac805af822
root@docker:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
02d708764fe1 httpd "httpd-foreground" 6 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp wizardly_bhaskara
###访问测试页发现返回的是空的内容,因为新建的目录里没有文件,创建文件后,可以访问。
root@docker:/# curl http://localhost:80
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>Index of /</title>
</head>
<body>
<h1>Index of /</h1>
<ul></ul>
</body></html>
root@docker:/# ls -l /docker/htdocs/
total 0
root@docker:/# echo hello > /docker/htdocs/index.html
root@docker:/# curl http://localhost:80
hello
###停止删除容器后,不会影响宿主机上的文件。
root@docker:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
02d708764fe1 httpd "httpd-foreground" 24 minutes ago Up 24 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp wizardly_bhaskara
root@docker:/# docker stop 02d7
02d7
root@docker:/# docker rm 02d7
02d7
root@docker:/# ls -l /docker/htdocs/index.html
-rw-r--r-- 1 root root 6 May 14 10:47 /docker/htdocs/index.html
- 挂载文件
官方的 Docker 镜像往往使用的是 UTC 时区,为了和宿主机保持时区上的一致,比较常用的是把宿主机上的 /etc/localtime 挂载到容器中。
###查看宿主机时区时间。
root@docker:/# date
Sun May 14 11:33:41 CST 2023
###先运行一个httpd容器,查看默认时区时间,与宿主机相差8个小时。
root@docker:/# docker run --rm -d -p 80:80 httpd
68a5119ee10fb4a30f6e7df8d9e5e5279717ae5f6631bc2e4cdebf60afe68b84
root@docker:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
68a5119ee10f httpd "httpd-foreground" 32 seconds ago Up 29 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp angry_carson
root@docker:/# docker exec -it 68a5 bash
root@68a5119ee10f:/usr/local/apache2# date
Sun May 14 03:35:59 UTC 2023
###将容器停止,因为运行时带了--rm参数,停止后,会自动删除容器。
root@docker:/# docker stop 68a5
68a5
###再次运行一个容器,将宿主机的localtime挂载到容器中,再查看时区时间,已于宿主机一致。
###我们不希望容器对这个文件进行修改,ro参数代表容器对挂载的文件只有只读权限。
root@docker:/# docker run --rm -d -p 80:80 -v /etc/localtime:/etc/localtime:ro httpd
bfdb7ad054c4322e5c908dfc212fc59233d794723a2bdcf10c47e492aad5b932
root@docker:/# date
Sun May 14 11:44:06 CST 2023
root@docker:/# docker exec -it bfdb bash
root@bfdb7ad054c4:/usr/local/apache2# date
Sun May 14 11:44:14 CST 2023
二、数据卷容器
数据卷容器也是一个容器,专门用来提供数据卷供其他容器挂载。如果用户需要在多个容器之间共享一些持续更新的数据,则最简单的方式是使用数据卷容器。
###创建一个数据卷容器myapp。
root@docker:/# docker run -d -v /docker/data/htdocs:/usr/local/apache2/htdocs -p 80:80 --name myapp httpd
634a325af9bf3e07be4e33fdba16b687fccad5e519a2da78dacc63b5e739dca8
root@docker:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
634a325af9bf httpd "httpd-foreground" 4 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp myapp
###查看容器myapp挂载信息。
root@docker:/# docker inspect myapp |grep -A 8 Mounts
"Mounts": [
{
"Type": "bind",
"Source": "/docker/data/htdocs",
"Destination": "/usr/local/apache2/htdocs",
"Mode": "",
"RW": true,
"Propagation": "rslave"
}
###再创建一个容器myapp1,使用--volumes-from引用myapp中的卷。
root@docker:/# docker run -d -p 81:80 --name myapp1 --volumes-from myapp httpd
6882ff39c92be837dfce55414332ff7c5cdc1d278977641a24cdfd486391843e
root@docker:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6882ff39c92b httpd "httpd-foreground" 4 seconds ago Up 2 seconds 0.0.0.0:81->80/tcp, :::81->80/tcp myapp1
634a325af9bf httpd "httpd-foreground" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp myapp
###查看myapp1挂载信息,和myapp一模一样。
root@docker:/# docker inspect myapp1 |grep -A 8 Mounts
"Mounts": [
{
"Type": "bind",
"Source": "/docker/data/htdocs",
"Destination": "/usr/local/apache2/htdocs",
"Mode": "",
"RW": true,
"Propagation": "rslave"
}
###修改/docker/data/hodocs中的index.html文件,访问myapp和myapp1测试。
root@docker:/# echo HelloWord > /docker/data/htdocs/index.html
root@docker:/# curl http://localhost:80
HelloWord
root@docker:/# curl http://localhost:81
HelloWord
###将myapp删除后,myapp1仍然可以使用。
root@docker:/# docker stop myapp
myapp
root@docker:/# docker rm myapp
myapp
root@docker:/# curl http://localhost:81
HelloWord
总结
以上就是今天学习了解的内容。