前中本专栏已经介绍过 Docker 的基础知识,本文开始进行 Docker 实战:手动使用 Docker 构建 WordPress 容器。同时介绍一下 Docker 官方 MySQL 镜像的爬坑方法,同时演示 Docker 生产中常见的问题以及解决办法。
在我以前的文章中,我们已经介绍了 Docker 的基础知识和基础命令。当然,虽然我们已经介绍了这些知识,我们还没有使用它们做出有价值的东西。构建 WordPress 的 Docker 容器有多种方法,本文将会介绍手动构建容器。如果你还没有认识 Docker,可以戳这里。
设置 MySQL
数据库是 WordPress 的基础,本文使用 Docker Hub 来获取 MySQL 镜像。
Docker 官方已经构建了 MySQL 镜像。在使用 MySQL 镜像之前,请先读镜像手册。在写本文时,镜像的最新版本是 5.7。
按照通常的方法,使用 MySQL 镜像的方法如下:
docker run --name wordpressdb -d mysql:5.7
执行这条命令的时候,如果本机没有 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
命令。
现在我们已经有了 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:
走到这一步,大部分的事情我们都做的差不多了,只有一个问题:
万一重启 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.X
为 wordpressdb
的 IP。
除此之外,还会修改 wordpress
的环境变量。
因此,安装的时候只需指定数据库主机为 mysql
即可。
但是还有点蛋疼的问题:
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)等。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。