返回 登录
0

用Docker构建与环境无关的系统

引言:很多的工作和软件安装或维护机器有关,这些工作还处理环境的特殊性。这些特殊性作为全局范围的依赖关系(如已知主机文件系统的位置)、硬编码的部署架构(代码或配置的环境检查),或数据局部性(存储在特定的不在部署体系结构以内的机器上的数据)。如果你的目标是建立低维护的系统,你应该努力减少这些事情。

Docker 有三个特定的功能,以帮助建立与环境无关的系统:

  • 只读文件系统
  • 环境变量注入
  • 存储卷

处理卷是一个大主题,为了学习前两个功能,在本文的其余部分将改变对示例的需求。
WordPress 使用一个名为MySQL 的数据库程序来存储大部分数据,所以先确保运行WordPress 的容器是只读文件系统,是一个好主意。

1 只读文件系统

使用只读文件系统产生以下两个积极效果。首先,你对容器不能更改它所包含的文件产生信心;其次,你也会进一步树立信念:容器中的攻击者无法破坏文件。
为了在客户系统上使用–read-only 标志,从WordPress 镜像创建和启动一个容器:

docker run -d --name wp --read-only wordpress:4

完成这些步骤后,检查容器是否正在运行。你可使用任何先前介绍的方法,也可以直接检查容器元数据。如果指定的wp 容器正在运行,以下命令将输出为真,否则为假。

docker inspect --format "{{.State.Running}}" wp

docker inspect 命令将显示Docker 为该容器保留的所有元数据(一个JSON 文件)。
格式选项会改变元数据。除了该容器的运行状态,本例中其会滤除元数据的所有字段。这个命令将简单地输出为错误。
在这种情况下,容器没有运行。为了找出原因,检查容器中的日志:

docker logs wp

输出是这样的:

error: missing WORDPRESS_DB_HOST and MYSQL_PORT_3306_TCP environment variables
Did you forget to --link some_mysql_container:mysql or set an external db with -e WORDPRESS_DB_HOST=hostname:port?

看起来WordPress 有一个MySQL 数据库的依赖关系。数据库是一个程序,根据检索和搜索方式存储数据。好消息是,你可以使用Docker 安装MySQL,就像安装WordPress:

docker run -d --name wpdb \
-e MYSQL_ROOT_PASSWORD=ch2demo \
mysql:5

一旦启动后,会创建一个不同的WordPress 容器,并链接到这个新的数据库容器中:
图片描述
再检查一次,WordPress 是否正常运行:

docker inspect --format "{{.State.Running}}" wp2

你可以得知WordPress 失败后重新启动。检查日志以确定原因:

docker logs wp2

应该有类似以下的日志:

... Read-only file system: AH00023: Couldn't create the rewrite-map mutex (file /var/lock/apache2/rewrite-map.1)

同样是WordPress 失败后重新启动,但这次的问题是,它试图写一个锁定文件到特定的位置。这是启动的必要组成部分,并无特殊。在这个示例中,需要为只读文件系统增加异常处理。你需要使用卷来做这个异常处理。使用下面的命令启动WordPress,不会有任何问题:
【2】
更新版本后你能用的脚本看上去像是这样:

SQL_CID=$(docker create -e MYSQL_ROOT_PASSWORD=ch2demo mysql:5)

docker start $SQL_CID
MAILER_CID=$(docker create dockerinaction/ch2_mailer)
docker start $MAILER_CID

WP_CID=$(docker create --link $SQL_CID:mysql -p 80 \
-v /run/lock/apache2/ -v /run/apache2/ \
--read-only wordpress:4)

docker start $WP_CID

AGENT_CID=$(docker create --link $WP_CID:insideweb \
--link $MAILER_CID:insidemailer \
dockerinaction/ch2_agent)

docker start $AGENT_CID

恭喜你,现在你应该有了一个正在运行的WordPress 容器!通过使用只读文件系统,以及链接WordPress 到另一个运行着数据库的容器,可以确保运行WordPress 镜像的容器永远不会改变。这意味着,如果运行客户的WordPress 博客程序的机器出了问题,可轻松在其他地方启动该容器的另一个副本。
但是这一设计有两个问题。首先,数据库和WordPress 的容器运行在同一个机器上。其次,WordPress 对重要的设置,如数据库名称、管理用户、管理密码、数据库加盐等使用默认值。为了解决这个问题,你可以创建多个版本的WordPress 软件,每一个客户都有一个特殊的配置。这样做会使简单的配置脚本变成一个在创建镜像时写入文件的怪物。通过使用环境变量来注入配置则是一个更好的方式。

2 环境变量的注入

环境变量是通过其执行上下文提供给程序的键值对。它可以让你在改变一个程序的配置时,无须修改任何文件或更改用于启动该程序的命令。
Docker 使用环境变量来传达相关信息,包括容器的守护选项、容器的主机名,以及其他在容器中运行程序的实用信息。Docker 还为用户提供了一个机制,可将环境变量注入到一个新的容器。那些期望通过环境变量获取重要信息的程序,可在容器创建时就进行配置。幸运的是,WordPress 就是这样一个程序。

在深入WordPress 的细节之前,尝试注入和观察你的环境变量。UNIX 命令env 显示当前执行上下文(终端)中的所有环境变量。要查看注入的环境变量,请使用以下命令:
【3】

–env 标志或-e 缩写,可用于注入任何环境变量。如果变量已经由镜像或Docker 设置,则该值将被覆盖。容器内部运行程序的方式,可以依赖于这种变量。WordPress 遵循以下环境变量:


 WORDPRESS_DB_HOST
 WORDPRESS_DB_USER
 WORDPRESS_DB_PASSWORD
 WORDPRESS_DB_NAME
 WORDPRESS_AUTH_KEY
 WORDPRESS_SECURE_AUTH_KEY
 WORDPRESS_LOGGED_IN_KEY
 WORDPRESS_NONCE_KEY
 WORDPRESS_AUTH_SALT
 WORDPRESS_SECURE_AUTH_SALT
 WORDPRESS_LOGGED_IN_SALT
 WORDPRESS_NONCE_SALT

提示 这个示例忽略了KEY 和SALT 变量,但任何实际的生产系统绝对应该设置这些值。

开始之前,你应该解决数据库和WordPress 容器在同一个机器上运行的问题。不是使用链接来满足WordPress 的数据库依赖,而是注入WORDPRESS_DB_HOST 变量的值:

docker create --env WORDPRESS_DB_HOST=<my database hostname> wordpress:4

这个示例会创建(并不启动)WordPress 容器。不管你在中指定的是什么,该容器都会试着连上一个MySQL 数据库。
由于远程数据库可能不会使用任何默认的用户名和密码,你就必须同时注入这些设置。假设数据库管理员是养猫爱好者且痛恨强密码:

docker create \
--env WORDPRESS_DB_HOST=<my database hostname> \
--env WORDPRESS_DB_USER=site_admin \
--env WORDPRESS_DB_PASSWORD=MeowMix42 \
wordpress:4

使用环境变量注入这一方法,能帮助你区分WordPress 容器和MySQL 容器之间的物理联系。由于数据库和客户的WordPress 网站都在同一台机器上,你仍然需要解决前面提到的第二个问题——所有的网站都使用相同的默认数据库名称。你需要为每一个独立的站点设置数据库名称以环境变量的方式注入:
【4】
你已经解决了这些问题,现在可以修改配置脚本了。首先,设置机器只能运行一个MySQL 容器:

DB_CID=$(docker run -d -e MYSQL_ROOT_PASSWORD=ch2demo mysql:5)
MAILER_CID=$(docker run -d dockerinaction/ch2_mailer)

那么网站配置脚本将是这样的:
【5】
这个新脚本将为每一位客户启动WordPress 实例和监控器,并将这些容器以及一个单独的邮件程序和MySQL 数据库彼此连接。WordPress 容器在被销毁、重新启动、升级的同时,完全不用担心数据会丢失。如图所示就是这种架构。
【6】
每个WordPress 和监控器容器使用相同的数据库和邮件服务

客户对当前交付的所有工作成果很满意。但有一件事可能会比较烦人。在早期的测试中,你发现监视器在该网站不可用时,的确可以准确通知邮件服务器,但重新启动该网站和监控器需要手动实现。要是系统在检测到故障时,能尝试自动恢复就更好了。Docker 对此提供了重启的策略,但仍不够稳定。

本文选自《Docker实战》。
图片描述

想及时获得更多精彩文章,可在微信中搜索“博文视点”或者扫描下方二维码并关注。
图片描述

评论