首先我得承认,我对 Docker 还很陌生,我可能从错误的假设出发来解决这个问题……如果是这样的话请告诉我。我已经看到很多关于 Docker 如何用于部署的讨论,但没有实际操作的示例。
这是我的方式想法它会起作用:
- 创建数据容器来保存机器 A 上的一些持久数据
- 创建使用数据容器中的卷的应用程序容器
- 做一些工作,可能会改变数据容器中的数据
- 停止应用程序容器
- 提交并标记数据容器
- 将数据容器推送到(私有)存储库
- 在机器 B 上拉取并运行第 6 步中的镜像
- 从 B 机器上你上次停下的地方继续
这里的关键步骤是第 5 步,我认为这一步会保存当前状态(包括文件系统的内容)。然后,您可以将该状态推送到存储库并从其他地方提取,从而为您提供一个与原始容器基本相同的新容器。
但似乎不是这样。我发现要么步骤 5 没有按照我的想法执行,要么步骤 7(拉取并运行镜像)将容器“重置”到其初始状态。
我组装了一组三个 Docker 镜像和容器来测试这一点:一个数据容器、一个每 30 秒将随机字符串写入数据容器中文件的写入器,以及一个简单地读取echo
数据容器文件中的值并退出的读取器。
数据容器
创建于
docker run \
--name datatest_data \
-v /datafolder \
myrepository:5000/datatest-data:latest
Dockerfile:
FROM ubuntu:trusty
# make the data folder
#
RUN mkdir /datafolder
# write something to the data file
#
RUN echo "no data here!" > /datafolder/data.txt
# expose the data folder
#
VOLUME /datafolder
作家
创建于
docker run \
--rm \
--name datatest_write \
--volumes-from datatest_data \
myrepository:5000/datatest-write:latest
Dockerfile:
FROM ubuntu:trusty
# Add script
#
ADD run.sh /usr/local/sbin/run.sh
RUN chmod 755 /usr/local/sbin/*.sh
CMD ["/usr/local/sbin/run.sh"]
运行
#!/bin/bash
while :
do
sleep 30s
NEW_STRING=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
echo "$NEW_STRING" >> /datafolder/data.txt
date >> /datafolder/data.txt
echo "wrote '$NEW_STRING' to file"
done
该脚本将随机字符串和日期/时间写入/datafolder/data.txt
数据容器中。
读者
创建于
docker run \
--rm \
--name datatest_read \
--volumes-from datatest_data \
myrepository:5000/datatest-read:latest
Dockerfile:
FROM ubuntu:trusty
# Add scripts
ADD run.sh /run.sh
RUN chmod 0777 /run.sh
CMD ["/run.sh"]
运行.sh:
#!/bin/bash
echo "reading..."
echo "-----"
cat /datafolder/data.txt
echo "-----"
当我构建并运行这些容器时,它们运行良好并按我预期的方式工作:
在开发机器上停止并启动:
- 创建数据容器
- 运行作家
- 立即运行阅读器,看到“这里没有数据!”消息
- 稍等片刻
- 运行阅读器,查看随机字符串
- 停止作家
- 重新启动写入器
- 运行阅读器,看到相同的随机字符串
但提交和推动并没有达到我预期的效果:
- 创建数据容器
- 运行作家
- 立即运行阅读器,看到“这里没有数据!”消息
- 稍等片刻
- 运行阅读器,查看随机字符串
- 停止作家
- 提交并标记数据容器
docker commit datatest_data myrepository:5000/datatest-data:latest
- 推送到存储库
- 删除所有容器并重新创建它们
此时,我期望运行读取器并看到相同的随机字符串,因为数据容器已提交、推送到存储库,然后从存储库中的同一映像重新创建。然而,我实际看到的是“这里没有数据!”消息。
有人能解释一下我哪里做错了吗?或者,给我举一个如何使用 Docker 进行部署的例子?
答案1
你对卷在 docker 中的工作原理有一个错误的假设。我将尝试解释卷与 docker 容器和 docker 镜像之间的关系,并希望解释它们之间的区别数据量和数据卷容器将会变得清晰。
首先让我们回顾一下几个定义
Docker 镜像
Docker 镜像本质上是联合文件系统 + 元数据。您可以使用以下命令检查 docker 镜像联合文件系统的内容docker export
命令,你可以使用以下命令检查 docker 镜像元数据docker inspect
命令。
数据量
来自Docker 用户指南:
数据卷是一个或多个容器内专门指定的目录,它绕过联合文件系统,为持久数据或共享数据提供多种有用的功能。
这里需要注意的是,给定卷(作为包含数据的目录或文件)仅在至少有一个 docker 容器使用它时才可重复使用。Docker 镜像没有卷,它们只有元数据,最终会告诉卷将在联合文件系统上挂载到哪里。数据卷不是 docker 容器联合文件系统的一部分,那么它们在哪里?在/var/lib/docker/volumes
docker 主机下(而容器存储在 下/var/lib/docker/containers
)。
数据卷容器
这种特殊类型的容器没有什么特别之处。它们只是使用数据卷的已停止容器,其唯一目标是让至少一个容器使用该数据卷。请记住,一旦使用给定数据卷的最后一个容器(正在运行或已停止)被删除,该卷将无法通过docker 运行 --volumes-from
选项。
使用数据卷容器
如何创建数据卷容器
用于创建数据卷容器的映像并不重要,因为这样的容器可以保持停止状态并仍能实现其目的。因此,要创建datatest_data
以卷命名的数据容器,/datafolder
您只需运行:
docker run --name datatest_data --volume /datafolder busybox true
这base
是图像名称(一个方便的小名称),也是true
我们提供的命令,只是为了避免看到 docker 守护程序抱怨缺少命令。无论如何,在您停止容器之后,命名的唯一目的是允许您使用命令选项datatest_data
访问该卷。--volumes-from
docker run
如何从数据卷容器中读取
我知道两种读取数据卷的方法:第一种是通过容器。如果您无法通过 shell 进入现有容器来访问该数据卷,则可以运行一个新容器,该容器的--volumes-from
唯一目的是读取该数据。
例如:
docker run --rm --volumes-from datatest_data busybox cat /datafolder/data.txt
另一种方法是从文件夹复制卷/var/lib/docker/volumes
。您可以通过检查使用该卷的容器之一的元数据来发现该文件夹中卷的名称。请参阅这个答案了解详情。
使用卷(自 Docker 1.9.0 起)
如何创建卷(自 Docker 1.9.0 起)
Docker 1.9.0 引入了一个新命令docker volume
允许创建卷:
docker volume create --name hello
如何从卷中读取(自 Docker 1.9.0 起)
假设您创建了一个名为的卷hello
,docker volume create --name hello
您可以使用以下选项将其挂载到容器中-v
:
docker run -v hello:/data busybox ls /data
关于提交和推送容器
现在应该清楚的是,由于数据卷不是容器(联合文件系统)的一部分,提交容器来生成新的 docker 镜像不会保留数据卷中的任何数据。
备份数据卷
docker 用户指南中有一篇很好的文章备份数据卷。
关于卷的好文章:http://container42.com/2014/11/03/docker-indepth-volumes/
答案2
您还可以使用 Docker 数据容器来部署代码
我不知道这是否是一个好的做法,但我是这样做的:
FROM ubuntu:trusty
# make the data folder
#
RUN mkdir /data-image
# in my case, I have a
# ADD dest.tar /data-image/
#
# but to follow your example :
# write something to the data file
RUN echo "no data here!" > /data-image/data.txt
# expose the data folder
#
VOLUME /datafolder
ENTRYPOINT cp -r /data-image/* /datafolder/
您现在可以推送您的图像并使用 volumes-from 等...