手动构建 WordPress 的 Docker 容器

原文来自 How to Manually Build Docker Containers for WordPress

前中本专栏已经介绍过 Docker 的基础知识,本文开始进行 Docker 实战:手动使用 Docker 构建 WordPress 容器。同时介绍一下 Docker 官方 MySQL 镜像的爬坑方法,同时演示 Docker 生产中常见的问题以及解决办法。

在我以前的文章中,我们已经介绍了 Docker 的基础知识和基础命令。当然,虽然我们已经介绍了这些知识,我们还没有使用它们做出有价值的东西。构建 WordPress 的 Docker 容器有多种方法,本文将会介绍手动构建容器。如果你还没有认识 Docker,可以戳这里

设置 MySQL

数据库是 WordPress 的基础,本文使用 Docker Hub 来获取 MySQL 镜像。

Docker 官方已经构建了 MySQL 镜像。在使用 MySQL 镜像之前,请先读镜像手册。在写本文时,镜像的最新版本是 5.7。

clipboard.png

按照通常的方法,使用 MySQL 镜像的方法如下:

docker run --name wordpressdb -d mysql:5.7

clipboard.png

执行这条命令的时候,如果本机没有 MySQL 镜像,那么 Docker 会从 Docker Pull 先下载镜像。使用 --name 参数指定容器运行时的名字,使用 -d 参数指定再后台运行。

使用 docker ps 命令可以发现,并没有名叫 wordpressdb 的容器在后台运行,但是不应该这样啊。使用 docker logs wordpressdb 查看镜像日志:

error: database is uninitialized and MYSQL_ROOT_PASSWORD not set
  Did you forget to add -e MYSQL_ROOT_PASSWORD=... ?

那么问题出在哪儿?

我们运行了 MySQL,但是没有指明数据库的 root 密码,所以容器并不能运行。所以为了修正这个错误,我们需要删除容器 wordpressdb,然后重新建立容器。Docker 不允许两个容器使用相同的名字。

再次运行容器的时候我们用 -e 参数指定容器内的环境变量MYSQL_ROOT_PASSWORD:

docker run --name wordpressdb -e MYSQL_ROOT_PASSWORD=password -d mysql:5.7

再次运行 docker logs wordpressdb 的时候,我们会看到非常长的信息。实际上 MySQL 容器已经在后台运行了,运行 docker ps 也可以看到正在运行的容器 wordpressdb

当然你也可以使用 MYSQL_DATABASE 参数指定运行容器之前就创建名为 wordpress 的数据库:

docker run --name wordpressdb -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=wordpress -d mysql:5.7

当然,MySQL 数据库还有其他的参数,例如指定创建用户和密码。当然,更多的用法就需要参考他们 官方的文档 了。

容器的 IP 会随启动而变化,需要使用 docker inspect --format='{{.NetworkSettings.IPAddress}}' wordpressdb 获取容器的 IP。

当然,Dockerfile 中有很多的容器构建信息。MySQL 基于 debian wheezy 镜像构建,然后启动 mysqld 命令。当使用这个容器的时候,其实只启动了 mysqld 命令。

clipboard.png

现在我们已经有了 MySQL 容器,用户名 root,密码 password,数据库名称 wordpress。下一步就是构建 WordPress 了。

构建 WorePress 容器

这一步我们使用PHP 镜像,PHP 镜像镜像也有很多,我们使用官方提供的带有 Apache 的 php 镜像。

docker run --name wordpress php:5.6-apache

不加 -d 参数,容器便会在前台运行,也能看到应该由 docker logs 输出的数据。

使用 docker inspect --format='{{.NetworkSettings.IPAddress}}' wordpress 命令获取 wordpress 容器的 IP。本文是 172.17.0.35

如果你直接访问这个 IP,会得到一个 403 的错误。因为容器中的网站目录在 /var/www/html,但是实际上目录中没有东西,所以 403 forbidden。

那么怎么将文件放入容器的那个文件夹?
第一步:宿主机创建文件夹,然后进入文件夹。
第二部:进入这个文件夹,创建 index.php 文件,文件内容是 <?php phpinfo(); ?>
第三部:使用命令启动容器:docker run --name wordpress -v "$PWD/":/var/www/html php:5.6-apache

这样访问 wordpress 容器的 IP(因为是新容器,所以 IP 有变化),便会得到经典的 phpinfo 页面。

测试完成,我们的容器可以执行 php 文件。

将 wordpress 文件放入本文件夹,chmod 777,然后重新启动 wordpress 容器,但是会这么提示:

您的PHP似乎没有安装运行WordPress所必需的MySQL扩展。

官方 php 镜像并未提供 mysql 扩展,所以我们必须要自己手动写 Dockerfile 安装扩展:

FROM php:5.6-apache
# 使用 php:5.6-apache 镜像
RUN docker-php-ext-install mysqli
# 使用 docker-php-ext-install 命令安装 mysqli 扩展
CMD ["apache2-foreground"]
# 默认启动 apache2-foreground 命令

然后我们构建这个镜像,镜像名为 phpwithmysql。

docker build -t phpwithmysql .

-t 参数指定构建出的镜像的名称。. 表示使用本目录的 Dockerfile

构建完成,便会得 phpwithmysql 镜像,tag 名为 latest。

再次启动 WordPress:

docker run --name wordpress -v "$PWD/":/var/www/html phpwithmysql

这次再使用 IP 访问你的 wordpress:

clipboard.png

走到这一步,大部分的事情我们都做的差不多了,只有一个问题:
万一重启 wordpressdb 容器,数据库容器的 IP 变了怎么办?

Docker 提供了连接参数,让我们可以将一个容器连接到另一个容器。

docker run --name wordpress --link wordpressdb:mysql -v "$PWD/":/var/www/html phpwithmysql

新参数是 --link,作用是将 wordpressdb 连接到 wordpress 容器内,具体为在 wordpress 容器内的 hosts 文件中增加 mysql 172.17.0.X
172.17.0.Xwordpressdb 的 IP。
除此之外,还会修改 wordpress 的环境变量。

因此,安装的时候只需指定数据库主机为 mysql 即可。

clipboard.png

但是还有点蛋疼的问题:

wordpress 并不能上传文件,也不能安装主题。因为 wordpress 容器内的 apache 对文件系统没有写权限,所以我们还得调整 phpwithmysql 镜像的 Dockerfile:

FROM php:5.6-apache
RUN docker-php-ext-install mysqli
COPY entrypoint.sh /entrypoint.sh 
RUN chmod 777 /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["apache2-foreground"]

接下来创建 encrypting.sh 文件:

#!/bin/bash
chown -R www-data:www-data .
exec "$@"

这是官方 WordPress 镜像构建方法的简化版,但是已经解决了文件系统的写权限问题。
现在构建新的镜像:

docker build -t phpwithmysql:v2 .

删除旧容器并重启:

docker rm -f wordpress
docker rm -f wordpressdb
docker run --name wordpressdb -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=wordpress -d mysql:5.7
docker run --name wordpress --link wordpressdb:mysql -v "$PWD/":/var/www/html phpwithmysql:v2

最后,删除 wp-config.php 文件。

这一次访问 wordpress 的 IP,重新安装 WordPress,便可构建完成。

构建过程可能有些麻烦,所以 WordPress 有官方的各种语言的 Docker 镜像。Docker 不允许容器内的应用对宿主机文件系统有写权限,这到底是好是坏?我觉得应该是好事。我们可以创立一个数据容器专门负责放文件,这样可以实现架构的多样化。但是对于现有架构的应用例如 WordPress,我们只能如此变通。

最终调整

最后一步大概很多人猜得到,就是万一关机了怎么办?wordpress 容器 IP 变化了怎么办?要知道,WordPress 没有配置的情况下爱,是使用 IP 保存站点 URL 的,所以我们必须要这样修改 wp-config.php 文件:

define('WP_HOME',$_SERVER['SERVER_ADDR']);
define('WP_SITEURL',$_SERVER['SERVER_ADDR']);

要注意的是,在 wp-config.php 文件中改变的设置,是无法再在 WordPress 的仪表盘中再改动的。

结论

本文中我们手动使用 Docker 构建了 WordPress 镜像,但是使用了一个非常曲折的方法。当然,还有更简便的方法,因为 Docker 官方已经构建了 WordPress 镜像。有了官方镜像,我们手动构建的镜像其实意义不大了。不过,通过调试,我们演示了 Docker 可能出现的常见问题,例如 IP 变化,以及解决办法(--link)等。

阅读 12k

推荐阅读
大舒的博客
用户专栏

我都不写PHP了你们还挤兑我。。

139 人关注
36 篇文章
专栏主页