Docker简单上手03

前言

在Docker简单上手01中我们一起学习了Docker的容器化。

在Docker简单上手02中我们一起学习了不同容器通过Docker网络实现相互之间的通信。

Docker数据管理

今天我们一起学习上手Docker数据管理。Docker数据的管理方式主要分为三种:

  • 数据卷(Volume),也是最为推荐的一种方式。
  • 绑定挂载(Bind Mount),Docker早期常用的数据管理方式。
  • tmpfs挂载。基于内存的数据管理。

注意

tmpfs挂载只适用于Linux操作系统。

数据卷

基本命令

数据卷(Volume)也是常见的 Docker 对象类型的一种,因此也支持 create(创建)、inspect (查看详情)、ls (列出所有数据卷)、prune (删除无用数据卷)和 rm(删除)等操作。
首先创建一个数据卷:

docker volume create my-volume

查看当前所有的数据卷

docker volume ls

可以看到输出的信息最后一条

local               my-volume

然后我们输入命令查看my-volume数据卷的详细情况:

docker volume inspect my-volume

可以看到输出了下面的信息:
Docker简单上手03_第1张图片

最后我们删除刚才创建的my-volume数据卷

docker volume rm my-volume

Docker简单上手03_第2张图片
从上图我们可以看到,数据卷在 “主机环境” 和 “容器环境” 之间架起了 “一道桥梁”。通常,我们在容器中将需要存储的数据写入数据卷所挂载的路径(位置),然后就会立即、自动地将这些数据存储到主机对应的区域。

创建数据卷的方式

在创建带有数据卷的容器时,通常有两种选择:1)命名卷(Named Volume);2)匿名卷(Anonymous Volume)。接下来我们就分别详细讲解。

创建命名卷

运行以下命令:

docker rum -it -v my:vol:/data --name container1 alpine

可以看到,我们通过 -v (或者 --volume )参数指定了数据卷的配置为 my-vol:/data ,其中(你应该猜到了)my-vol 就是数据卷的名称,/data 就是容器中数据卷的路径。

在进入容器后,向/data目录中添加一个文件后退出

touch /data/file.txt
exit

为了验证 /data 中的数据是否真的保存下来,我们删除 container1 容器,然后再创建一个新的容器 container2 ,查看其中的 /data 目录内容:

docker rm container1

docker run -it -v my-vol:/data --name container2 alpine

ls /data
// 这里可以看到会输出
file.txt

exit

可以看到刚刚在 container1 中创建的 file.txt 文件!事实上,这种在容器之间共享数据卷的模式非常常见,Docker 提供了一个方便的参数 --volumes-from 来轻松实现数据卷共享:

docker run -it -v --volumes-from container2 --name container3 alpine

ls /data
file.txt

同样,container3 中也能访问到数据卷中的内容。

创建匿名卷

创建匿名卷的方式就很简单了,之前我们通过 my-vol:/data 作为 -v 的参数,而创建匿名卷只需省略数据卷名称(my-vol 即可):

docker run -v /data --name container4 alpine

输入以下命令查看container4的情况:

docker inspect container4

Docker简单上手03_第3张图片

看一下Mount中的一些重要字段:

  • Name 即数据卷的名称,由于是匿名卷,所以 Name 字段就是一串长长的随机数,命名卷则为指定的名称。
  • Source 为数据卷在主机文件系统中的存储路径(之前说了,Windows 和 Mac 在 Docker 虚拟机中)。
  • Destination 为数据卷在容器中的挂载点。
  • RW 指可读写(Read-Write),如果为 false ,则为只读数据卷。
在 Dockerfile 中使用数据卷

在 Dockerfile 中使用数据卷非常简单,只需通过 VOLUME 关键词指定数据卷就可以了:

VOLUME /data

# 或者通过 JSON 数组的方式指定多个数据卷
VOLUME ["/data1", "/data2", "/data3"]

注意

只能创建匿名卷

当通过docker run -v指定数据卷时,Dockerfile中的配置会被覆盖

绑定挂载

绑定挂载(Bind Mount)是出现最早的 Docker 数据管理和存储解决方案,它的大致思路和数据卷是一致的,只不过是直接建立本机文件系统和容器文件系统之间的映射关系,非常适合简单、灵活地在本机和容器之间传递数据。

我们可以试着把自己机器的桌面(或者其他路径)挂载到容器中:

docker run -it --rm -v ~/Desktop:/desktop alpine

我们还是通过 -v 参数来进行配置,~/Desktop 是本机文件系统路径,/desktop 则是容器中的路径,~/Desktop:/desktop 则是将本机路径和容器路径进行绑定,仿佛架起了一道桥梁。这里的 --rm 选项是指在容器停止之后自动删除。

进入到容器之后,可以试试看 /desktop 下面有没有自己桌面上的东西,然后再在容器中创建一个文件,看看桌面上有没有收到这个文件:

/# ls /desktop

/# touch /desktop/from-container.txt

你应该能看到自己的桌面上多了容器中创建的 from-container.txt 文件!

动手实战

上面我们熟悉了Docker数据管理的两种方式,说不如练,下面我们直接动手演示。

项目准备

git clone -b volume-start https://github.com/tuture-dev/docker-dream.git
cd docker-dream

实战内容:

  • 存储和备份 Express 服务器输出的日志数据,而不是存储在” 朝生暮死 “的容器中。
  • MongoDB 镜像已经做了数据卷配置,所以我们只需实践一波怎么备份和恢复数据。

为 Express 服务器挂载数据卷

我们首先在 server/Dockerfile 中添加 VOLUME 配置,并且指定 LOG_PATH (日志输出路径环境变量,可参考 server/index.js 的源码)为 /var/log/server/access.log,代码如下:

FROM node:10

# 指定工作目录为 /usr/src/app,接下来的命令全部在这个目录下操作
WORKDIR /usr/src/app

VOLUME /var/log/server

# 将 package.json 拷贝到工作目录
COPY package.json .

# 安装 npm 依赖
RUN npm config set registry https://registry.npm.taobao.org && npm install

# 拷贝源代码
COPY . .

# 设置环境变量(服务器的主机 IP 和端口)
ENV MONGO_URI=mongodb://dream-db:27017/todos
ENV HOST=0.0.0.0
ENV PORT=4000
ENV LOG_PATH=/var/log/server/access.log

# 开放 4000 端口
EXPOSE 4000

# 设置镜像运行命令
CMD [ "node", "index.js" ]

然后 build 服务器镜像:

docker build -t dream-server server/

现在我们把整个项目走起来,也就是进来前两篇文章的内容:

# 创建网络,便于容器互联
docker network create dream-net

# 启动 MongoDB 容器(dream-db)
docker run --name dream-db --network dream-net -d mongo

# 启动 Express API 容器(dream-api)
docker run -p 4000:4000 --name dream-api --network dream-net -d dream-server

# 构建提供 React 前端页面的 Nginx 服务器
docker build -t dream-client client

# 启动 Nginx 服务器容器(client)
docker run -p 8080:80 --name client -d dream-client

项目起来之后我们docker ps确保三个容器都已经开启:
容器开启

然后访问localhost:8080(服务器域名:8080)

日志数据的备份

创建一个新的临时容器,通过共享数据卷的方式来备份数据。

  • 实现 dream-api 容器和数据卷之间的数据共享(已实现)。
  • 创建临时容器,获取 dream-api 的数据卷。运行以下命令:
docker run -it --rm --volumes-from dream-api -v $(pwd):/backup alpine

上面这句命令同时用到了上面讲解的数据卷和绑定挂载:

--volumes-from dream-api 用于容器之间共享数据卷,这里我们获取 dream-api 的数据卷

-v $(pwd):/backup 用于建立当前本机文件路径(pwd 命令获取)和临时容器内 /backup 路径的绑定挂载

  • 进入临时容器之后,我们把日志数据压缩成 tar 包放到 /backup 目录下,然后退出:
  / # tar cvf /backup/backup.tar /var/log/server/
  tar: removing leading '/' from member names
  var/log/server/
  var/log/server/access.log
  / # exit

退出之后用下面的命令在当前目录查看日志的备份backup.tar

docker run -it --rm --volumes-from dream-api -v $(pwd):/backup alpine tar cvf /backup/backup.tar /var/log/server

数据库备份与恢复

提示

我们这里使用 MongoDB 自带的备份与恢复命令(mongodump 与 mongorestore ),其他数据库(例如 MySQL)也有类似的命令,都可以借鉴本文的方式。

临时容器 + 容器互联

首先,我们的临时容器得连接上 dream-db 容器,并配置好绑定挂载,命令如下:

docker run -it --rm -v $(pwd):/backup --network dream-net mongo sh

和之前备份日志数据相比,我们要把这个临时容器连接到 dream-net 网络中,它才能访问到 dream-db 的数据进行备份。

第二步,进入到这个临时容器后,运行 mongodump 命令:

/ # mongodump -v --host dream-db:27017 --archive --gzip > /backup/mongo-backup.gz

此时,由于绑定挂载,输出到 /backup 的文件将保存到当前目录(pwd)中。退出后,就可以在当前目录下看到 mongo-backup.gz 文件了。

提前做好绑定挂载

在创建数据库容器的时候,运行以下命令:

docker run --name dream-db --network dream-net -v $(pwd):/backup -d mongo

然后再通过 docker exec 执行 mongodump 命令:

docker exec dream-db sh -c 'mongodump -v --archive --gzip > /backup/mongo-backup.gz'

这样就可以实现创建数据库容器的时候就做好绑定挂载,然后通过 mongodump 把数据备份到挂载区域.这里我们用 sh -c 来执行一整条 Shell 命令(字符串形式),这样避免了重定向符 > 引发的歧义(不理解的话可以把 sh -c ‘xxx’ 替换成 xxx)。可以看到,mongodump 的命令简单了许多,我们再也不需要指定 --host 参数,因为数据库就在本容器内。

但是有个问题:如果已经创建了数据库,并且没有提前做绑定挂载,这种方法就行不通了!

注意,这不是演习!

有了数据库备份文件,我们就可以肆无忌惮地来做一波” 演习 “了。通过以下命令,直接端了目前的数据库和 API 服务器:

docker rm -f --volumes dream-db
docker rm -f dream-api

没错,通过 --volumes 开关,我们不仅把 dream-db 容器删了,还顺带把挂载的数据卷全部删除!演习就是要足够逼真才行。这时候再访问 localhost:8080 ,之前的待办数据全部丢失!

现在让我们再次创建新的 dream-db 容器:

docker run --name dream-db --network dream-net -v $(pwd):/backup -d mongo

注意到,我们通过绑定挂载的方式把当前目录映射到容器的 /backup 目录,这意味着可以在这个新的容器中通过 /backup/mongo-backup.gz 来恢复数据,运行以下命令:

docker exec dream-db sh -c 'mongorestore --archive --gzip < /backup/mongo-backup.gz'

我们应该会看到输出了一些日志,提示我们数据恢复成功。最后重新开启 API 服务器:

docker run -p 4000:4000 --name dream-api --network dream-net -d dream-server

现在再次访问应用是不是发现数据都找回来了!

今天的docker上手到这里就结束了,共勉加油!

教程:图灵社区:上手容器数据管理

你可能感兴趣的:(linux,docker,git,node.js,reactjs)