WordPress 容器中的 WordPress 数据和 MySQL 容器中的数据库数据可能不是我们想要的。将数据保存在服务容器之外被认为是好的做法,因为您可能希望将数据与服务容器分开。在本章中,我们将涵盖以下主题:
- 数据量
- 创建数据卷映像
- GitHub 上的主机
- 在 Docker 注册中心发布
- 在 Docker 注册表中心上运行
- 将参数传递给容器
- 创建参数化映像
有两种方法可以在我们的容器上安装外部卷。数据卷允许您在容器之间共享数据,如果您更新、停止甚至删除服务容器,数据卷内的数据将保持不变。
使用docker run
语句中的–v
选项装载数据卷:
docker run –v /host/dir:container/dir
只需添加多个–v
指令,就可以向一个容器中添加任意数量的数据卷。
关于数据量的一个非常好的事情是,将数据量传递到其中的容器不知道它,也不需要知道它。容器不需要任何更改;它的工作方式就像它正在写入本地文件系统一样。您可以覆盖容器中的现有目录,这是一件常见的事情。这种方法的一种用法是将 web 根目录(通常在容器内的/var/www
处)放在 Docker 主机的一个目录中。
您可以从您的主机在您的容器上挂载一个目录(或文件):
docker run –d --name some-wordpress –v /home/web/wp-one:/var/www wordpress
这将把主机的本地目录/home/web/wp-one
作为/var/www
装载到容器上。如果您只想授予容器读取权限,可以将指令更改为–v /home/web/wp-one:/var/www:ro
,其中:ro
是只读标志。
在生产中使用host
目录作为数据卷并不常见,因为目录中的数据不是很容易移植。但是在测试源代码改变时服务容器的行为时,这非常方便。
您在主机目录中所做的任何更改都是直接在容器的装载数据卷中进行的。
更常见的处理数据的方式是使用一个容器,它的唯一任务是保存数据。容器中运行的服务应该尽可能少,从而保持尽可能稳定。
数据卷容器可以通过 Dockerfile 的VOLUME
关键字公开卷,当使用带有--volumes-from
指令的数据卷容器时,这些卷将被装载到服务容器上。
带有VOLUME
指令的非常简单的 Dockerfile 可能如下所示:
FROM ubuntu:latest
VOLUME ["/var/www"]
使用前面 Dockerfile 的容器将安装/var/www
。要将数据容器中的卷装入服务容器,我们创建数据容器,然后装入,如下所示:
docker run –d --name data-container our-data-container
docker run –d --name some-wordpress --volumes-from data-container wordpress
由于数据卷中的数据是在容器之间共享的,因此通过将数据装载到临时容器中来访问数据是很容易的。以下是如何从数据卷容器中的数据创建一个.zip
文件(从您的主机),该数据卷容器的 Dockerfile 中有VOLUME ["/var/www"]
:
docker run --volumes-from data-container -v $(pwd):/host ubuntu zip -r /host/data-containers-www /var/www
这个创建一个名为data-containers-www.zip
的.zip
文件,包含中的内容。www
数据容器来自var
目录。这个.zip
文件将该内容放在您当前的主机目录中。
由于我们的数据量容器将只保存我们的数据,我们应该一开始就尽可能地保持它的小,这样它就不会占用服务器上大量不必要的空间。当然,容器中的数据可以增长到与服务器磁盘上的空间一样大。我们根本不需要任何花哨的东西;我们只需要一个工作文件存储系统。
对于这本书,我们将把所有的数据(MySQL 数据库文件和 WordPress 文件)保存在同一个容器中。当然,您可以将它们分成两个名为dbdata
和webdata
的数据量容器。
除了可以读写的工作文件系统之外,我们的数据卷映像不需要任何东西。这就是为什么我们选择的基本形象将是 BusyBox。这就是 BusyBox 对本身的描述:
“BusyBox 将许多常见 UNIX 实用程序的微小版本组合成一个小的可执行文件。它为您通常在 GNU fileutils、shellutils 等中找到的大多数实用程序提供了替代品。BusyBox 中的实用程序通常比它们功能齐全的 GNU 同类程序有更少的选项;然而,所包含的选项提供了预期的功能,并且表现得非常像它们的 GNU 对应物。BusyBox 为任何小型或嵌入式系统提供了一个相当完整的环境。”
听起来很棒!我们将继续将此添加到我们的 Dockerfile 中:
FROM busybox:latest
Dockerfile 有一个指令VOLUME
,当使用--volumes-from
属性添加这个数据卷容器时,您可以定义哪些目录暴露给其他容器。在我们的数据量容器中,我们首先需要为 MySQL 数据添加一个目录。让我们看一下将要使用的 MySQL 映像内部,看看哪个目录用于数据存储,并将该目录公开给我们的数据卷容器,以便我们可以拥有它:
RUN mkdir –p /var/lib/mysql
VOLUME ["/var/lib/mysql"]
我们也希望我们的 WordPress 安装在这个容器中,包括所有.php
文件和图形映像。再次,我们转到我们将使用的映像,并找出将使用哪个目录。这种情况下就是/var/www/html
。当您将此添加到 Dockerfile 时,不要添加新行;只需将这些行附加到 MySQL 数据目录:
RUN mkdir -p /var/lib/mysql && mkdir -p /var/www/html
VOLUME ["/var/lib/mysql", "/var/www/html"]
以下是数据映像的简单 Dockerfile:
FROM busybox:latest
MAINTAINER Oskar Hane <oh@oskarhane.com>
RUN mkdir -p /var/lib/mysql && mkdir -p /var/www/html
VOLUME ["/var/lib/mysql", "/var/www/html"]
就这样!当向 Docker 注册表中心发布映像时,最好在 Dockerfiles 中包含一个MAINTAINER
指令,这样如果有人出于某种原因想要,就可以联系到您。
当我们使用我们关于如何在 GitHub 上托管 Docker 映像源以及如何在 Docker 注册表 Hub 上发布映像的知识时,创建我们的数据卷映像将没有问题。
让我们创建一个分支和一个 Dockerfile,并为我们的数据卷映像添加内容:
git checkout -b data
vi Dockerfile
git add Dockerfile
在前面代码的第 2 行,您可以使用自己选择的文本编辑器。我只是碰巧发现vi
适合我的需求。您应该添加到 Dockerfile 中的内容如下:
FROM busybox:latest
MAINTAINER Oskar Hane <oh@oskarhane.com>
RUN mkdir /var/lib/mysql && mkdir /var/www/html
VOLUME ["/var/lib/mysql", "/var/www/html"]
用您的姓名和电子邮件替换维护人员信息。
在提交和推送至 GitHub 之前,您可以——也应该——始终确保它能够工作。为此,您需要从 Docker 文件构建 Docker 映像:
docker build –t data-test .
确保您注意到了行尾的点,这意味着 Docker 应该在当前目录中查找 Dockerfile。Docker 将尝试从我们 docker 文件中的指令构建一个映像。它应该相当快,因为它是一个小的基础映像,上面除了几个VOLUME
指令什么都没有。
截图如下:
当一切如我们所愿时,是时候提交更改并将其推送到我们的 GitHub 存储库了:
git commit –m "Dockerfile for data volume added."
git push origin data
当你把它推送到存储库时,越过到 GitHub 去验证你的新分支是否在那里。
下面的截图显示了 GitHub 存储库:
现在在 GitHub 上有了新的分支,我们可以去 Docker Hub 注册中心创建一个新的自动化构建,命名为data
。它将我们的 GitHub 数据分支作为源。
等待构建完成,然后尝试用你的 Docker 守护程序拉取映像,验证它在那里并且正在工作。
截图如下:
太神奇了!检查映像的大小;只是不到 2.5 MB。这是完美的,因为我们只想在其中存储数据。当然,这个映像上面的容器可以是硬盘允许的最大尺寸。这只是为了显示映像有多大。映像是只读的,记得吗?
数据量容器比较特殊;他们可以被阻止,仍然可以实现他们的目的。就我个人而言,我喜欢在执行docker ps
命令时看到所有正在使用的容器,因为我喜欢偶尔删除停止的容器。
这完全取决于你。如果您不介意让容器停止,可以使用以下命令启动它:
docker run –d oskarhane/data true
true
参数只是输入一个有效的命令,而–d
参数将容器置于分离模式,在后台运行。
如果您想保持容器运行,您需要在前台放置一个服务,如下所示:
docker run –d oskarhane/data tail –f /dev/null
前面命令的输出如下:
tail –f /dev/null
命令是一个永不结束的命令,所以容器将一直运行,直到我们停止它。就资源而言,tail
命令是相当无害的。
我们已经看到了在启动官方 MySQL 容器时如何给容器参数或者环境变量:
docker run --name mysql-one -e MYSQL_ROOT_PASSWORD=pw -d mysql
–e MYSQL_ROOT_PASSWORD=pw command
是一个展示你如何做到的例子。这意味着容器内的MYSQL_ROOT_PASSWORD
环境变量有pw
作为值。
这是一种非常方便的拥有可配置容器的方式,你可以有一个设置脚本作为ENTRYPOINT
或者前台脚本配置密码;主持人;测试、试运行或生产环境;以及容器需要的其他设置。
为了掌握这个非常好的特性,让我们创建一个小的 Docker 映像,根据环境变量的状态,将字符串转换为大写或小写。
Docker 映像将基于最新的 Debian 发行版,并且只有一个ENTRYPOINT
命令。这就是Dockerfile
:
FROM debian:latest
ADD ./case.sh /root/case.sh
RUN chmod +x /root/case.sh
ENTRYPOINT /root/case.sh
这将从我们当前的目录中获取case.sh
文件,将其添加到容器中,使其可执行,并将其指定为ENTRYPOINT
。
case.sh
文件可能如下所示:
#!/bin/bash
if [ -z "$STR" ]; then
echo "No STR string specified."
exit 0
fi
if [ -z "$TO_CASE" ]; then
echo "No TO_CASE specified."
exit 0
fi
if [ "$TO_CASE" = "upper" ]; then
echo "${STR^^*}"
exit 0
fi
if [ "$TO_CASE" = "lower" ]; then
echo "${STR,,*}"
exit 0
fi
echo "TO_CASE was not upper or lower"
该文件检查是否设置了$STR
和$TO_CASE
环境变量。如果检查$TO_CASE
是upper
还是lower
完成,如果检查失败,将显示错误信息,表示我们只处理upper
和lower
。
如果$TO_STR
设置为upper
或lower
,则环境变量$STR
的内容分别转换为大写或小写,然后打印到stdout
。
让我们试试这个!
以下是我们可以尝试的一些命令:
docker run –i case
docker run –i -e STR="My String" case
docker run –i -e STR="My String" –e TO_CASE=camel case
docker run –i -e STR="My String" –e TO_CASE=upper case
docker run –i -e STR="My String" –e TO_CASE=lower case
这个似乎如预期的那样工作,至少是为了这个目的。现在我们已经创建了一个容器,它接受参数并对它们进行操作。
在本章中,您学习了如何使用数据量将数据保留在服务容器之外。数据卷可以是目录、主机文件系统中的文件或数据卷容器中的任何一种。
我们探索了如何将参数传递给容器,以及如何从内部读取它们。参数是配置容器的一个很好的方法,可以更容易地创建更通用的 Docker 映像。
我们创建了一个数据量容器,并将其发布到 Docker Registry Hub,为下一章做准备,在下一章中,我们将连接我们的三个容器来创建一个松散耦合的单元。