如何将数据持久化
我们在之前的文章一起学Docker4:如何更新正在运行中的应用中,发现了一个问题,每次更新,启动容器后,所有待办任务都会清空。这是什么原因造成的呢?今天就来一探究竟。
容器的文件系统
当一个容器运行时,它会使用镜像中的层作为它的文件系统。每个容器也有自己的临时空间,用来 创建/更新/删除 文件。任何更改都不会影响其它容器,即便几个容器使用相同的镜像也不会。
实践
为了亲眼见证,我们会启动2个容器,在其中一个容器中创建一个文件。你会发现,在一个容器中创建的文件,在另一个容器中是看不到的。
1、启动一个 ubuntu 容器,然后在这个容器中,通过Linux命令太多了!之shuf中提到的 shuf 命令生成一个随机排列,并在排列中取第一个数,存入 /data.txt 文件。之后再以 follow 模式运行 tail 命令,监听 /dev/null 文件,虽然听不到什么,目的只是为了保持容器运行。
docker run -d ubuntu bash -c “shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null”
2、通过 exec 进入容器来验证我们能否看到输出。打开仪表盘,点击正在运行 Ubuntu 镜像的容器的第一个动作按钮。
点击以后,你会看到一个终端,它是Ubuntu容器中,正在运行的shell。
运行以下命令,查看 /data.txt 文件的内容。然后关闭终端。
cat /data.txt
如果你更喜欢宿主机上的命令行,也可以使用 docker exec 命令做同样的操作。你需要获取容器的ID(使用 docker ps 命令获取)并通过以下命令查看 /data.txt 文件的内容。
docker exec <容器id> cat /data.txt
其实对于容器id,你并不需要输入完整的容器id。只需要输入前面几个字符,能够让docker区分出是哪个容器就行。因为我的容器id第一个字母是d,只有这一个容器是以d开头的,所以我直接用 d 来指定容器了。
这样,你会看到一个在1-10000 之间的一个随机数字。
3、再启动一个容器,基于相同的 ubuntu 镜像。你会发现,无法找到 /data.txt 文件。
docker run -it ubuntu ls /
找不到 /data.txt 文件的原因在于,它仅存在于第一个容器的临时空间当中。
4、使用 docker rm -f 命令移除第一个容器。
docker rm -f d
我们会发现,第一个容器已经被删除了。
容器卷
有了之前的实验,我们见证了每个容器,每次启动的时候,都是基于镜像的定义启动的。尽管容器能够创建、更新、删除文件,容器被删除的时候,那些变更都会丢失,并且所有的变更在容器之间都是隔离开的。但是有了卷,事情就变得不一样了。
卷能够让容器中指定的路径连接到宿主机。如果挂载了容器中的一个路径,路径中的修改在宿主机上也能看到。如果每次重启都挂载相同的路径,我们也就能看到相同的文件了。
卷主要有2种类型,最后我们2种都会用上。不过让我们先从具名卷开始。
持久化我们的待办数据
默认状态下,待办应用把它的数据保存在了 SQLite 数据库中,位于 /etc/todos/todo.db 。
如果你不熟悉 SQLite 也不用担心。它就是一个关系型数据库,然后所有的数据都保存在一个文件中。
尽管对于大规模应用来说,它并不是最好的选择,不过对于小demo来说,足够了。
之后我们会讨论:把它切换成另一个数据库引擎。
因为数据库就只是一个文件,如果我们能够把这个文件持久化,放在宿主机上。并且后续的容器也能访问到这个文件的话,那么后续的容器就能够续上之前的容器中的数据了。通过创建一个卷,并把卷关联(通常叫挂载)到数据所在的路径,我们就能够持久化数据了。因为我们的容器是往 todo.db 文件写入数据的,所以我们会把这个文件持久化到宿主机的卷中。
如上所述,我们会使用一个具名卷。把具名卷想象成一桶数据就好。docker会维护卷在硬盘上的物理位置,你只需要记住卷的名字就行。每次你使用卷的时候,docker都会确保提供正确的数据。
1、使用 docker volume create 命令创建一个卷。
docker volume create todo-db
2、因为待办应用容器仍旧在运行,又没有使用持久化卷,所以我们在仪表盘中再次停止这个容器,或者使用 docker rm -f 的方式删除容器。
3、启动待办应用容器,不过这次我们会带上 -v 旗标,用来指定卷的挂载位置。我们会使用具名卷并将它挂载到 /etc/todos ,这样会捕获路径中创建的所有文件。
docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
4、容器启动后,网页浏览器打开应用,并给待变列表添加几个待办任务
5、删除待办应用的容器。使用仪表盘删,或者用 docker ps 获取容器ID,再通过 docker rm -f 来删除。
6、使用上面启动容器的命令,再启动一个新容器。
docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
7、网页浏览器打开应用,你会看到你的任务列表还在!
8、看完列表后,接着删除容器。
牛皮!你已经知道怎么持久化数据了!
专家提示
尽管具名卷和绑定挂载(我们后续会讲)是默认docker引擎安装程序所支持的最主要的2种类型的卷,但是仍旧有许多卷驱动器插件,可以支持NFS,SFTP,NetApp等等!如果你开始使用 Swarm,Kubernetes 等等,在机群环境中的多台宿主机上,运行容器的话,这会显得特别重要。
深入了解我们的卷
很多人会问:我使用具名卷的时候,docker到底把数据保存在哪里了?如果你想知道的话,可以使用 docker volume inspect 命令。
docker volume inspect todo-db
Mountpoint 是硬盘上存储数据的真正位置。注意,在大多数机器上,你需要根访问权限来访问宿主机上的这个路径。但是,数据就在那。
直接在Docker Desktop上访问卷数据
Docker命令在Dcoker Desktop中运行的时候,它们实际上是在机器的小型虚拟机中运行。如果你想看看 Mountpoint 路径的实际内容,你首先需要进入这个虚拟机。
回顾
现在,我们有了一个功能完善的应用,即便是重启容器都不会妨碍应用的正常运作。我们可以向我们的投资者展示这个应用,希望他们能够明白我们的愿景。
不过,我们之前也看到了,每次有小改动都要重新构建镜像有点太耗时了。对应用做改动,一定有更好的办法,对吧?有了绑定挂载,就有了更好的办法。我们接下去就来一睹为快!
如果感觉本文对你有用,麻烦长按点赞。后续还会继续更新教程,欢迎关注,以便第一时间看到哦。我们下期,不见不散。
推荐文章: