WordPress Docker化迁移实战

小柊 发表于 2017年12月24日 23时17分37秒

序、扯淡

很久没有正儿八经的写一份算得上是干货的文章了,不知道有没有细心的朋友注意到本站更新日志里悄悄的更新了一条吗?是的,本站在2017年12月05日完成了Docker化迁移,现在你们看到的网站其实已经部署在Docker里面了。

之前一直是非常正规的在Linux服务器上部署了httpd(apache)+PHP+MySQL。本来也就打算这样一直下去算了,但一是阿里云的CDN不支持Apache的HTTPS,也不知道是不是我Apache配置的有问题,总之如果我的Apache只开了HTTPS,没有开HTTP,那么阿里云的CDN直接会回源失败;第二是我的这个服务器里,除了这个博客,其他都是静态网站,对于静态网站来说,Nginx的效率高于Apache,所以很早就有想换HTTP服务器软件的冲动了;第三是因为之前不怎么熟练虚拟机的时候,很多时候都是拿这台服务器搞测试的,所以折腾服务器里装了很多乱七八糟的环境,比如Mono之类的每次用yum makecache的时候总要去那几个项目的仓库里下载数据,要卡很久,非常不爽。

终于最近几次WordPress的在线升级总是失败,终于点燃了我的怒火(当然,大家都知道WordPress在线升级失败大多都是“Girl Friend Wall”的缘故),一气之下决定直接重置虚拟机,也准备趁着这次重置的机会,改Apache为Nginx,把WordPress关进Docker里,这样就不用再在服务器系统上装一堆东西了。

 

之前也没怎么正经给大伙介绍过Docker。

Docker这个东西,您可以简单的想象成是一个和宿主机相对隔离的沙盒,它不像虚拟机一样和宿主机隔离的那么彻底,但也正是因此,Docker相比于虚拟机,它少了虚拟机系统这一层,所以Docker在资源利用率和运行速度上都优于虚拟机。

 

如果要问笔者觉得在Docker上最“丧心病狂”的一件事大概就是,一个容器的启动可以在短短几秒钟内完成,这是任何一个虚拟机都实现不了的。

除了执行速度和效率占优以外,Docker另一个非常吸引人的地方就是可以通过它构建各种自己想要的应用,并且这些构建完的镜像可以直接拷贝到任何一台装有Docker的系统上,不用做任何的修改,仍能直接运行。正如Docker的口号一般:Build,Ship,and Run Any App,Anywhere!

 

一、准备工作

在之前笔者写的《WordPress跨平台迁移实战》中,已经简单的提过迁移WordPress需要准备好数据库和网站文件,首先是数据库,我们直接用mysqldump导出WordPress数据库为SQL文件:

mysqldump -u[数据库用户名] -p [WordPress数据库名称] > [导出的SQL文件路径]

 

根据您自己的博客情况修改上面命令中的红色部分,回车后会提示输入数据库用户密码,密码输入无误后,整个数据库就被导出为SQL文件放在指定的位置上了。

 

至于网站的文件,其实不需要全部都拷下来,就只要把下面几个目录和您放在其他目录里的个性化文件拷下来就好了:

1.已安装的插件目录:

wp-content/plugins

2.网站主题目录:

wp-content/ themes

3.网站文件上传目录:

wp-content/ uploads

 

当然,如果您博客没有安装插件,插件目录也可以不用拷,没有装第三方主题,也可以不拷主题目录,没有上传过文件,也可以不拷上传目录……

需要注意的是,我们最后还是需要整个网站文件的目录结构的,也就说插件目录什么的还是要放在wp-content文件夹里,这个结构不能乱。

 

不过,一定要删掉的文件也是有的,比如根目录的wp-config.php:如果WordPress容器在启动过程中发现了这个文件,就会认为容器中已经安装了WordPress,并跳过安装过程。

 

二、使用Docker部署WordPress国际版

是的,在Docker的官方Docker Hub里,只有WordPress国际版镜像,如果您没有什么特殊的要求,完全可以使用这个国际版镜像,像系统语言这种东西,可以部署完了之后去后台设置。

如果在虚拟机上安装Docker,请参阅这篇全是废话的博客《C# Docker开发(一) Docker的安装》(虽然题目里写着C#,但和C#基本无关哦~)

 

由于Docker Hub中的wordpress镜像只自带了Apache和PHP环境,所以MySQL需要单独再部署。

首先从官方Docker Hub上pull下MySQL镜像和WordPress国际版镜像:

docker pull mysql

docker pull wordpress

 

全部下载完成后,打开上一步里准备好的数据库SQL文件,在最开始的注释后面加上两行命令:

create database [数据库名称];

use [数据库名称];

 

就是创建数据库和使用数据库的命令,当然你也可以像笔者一样增加一点自定义的设置,比如编码等等。至于为什么还要加这些,一会儿再说。

 

注意:请在下面的操作开始前注意本机的SELinux状态,如果启用了SELinux,可能会导致命令出错或容器出错,建议操作时禁用SELinux

 

(一)启动MySQL容器

接下来我们启动MySQL容器:

docker run -d \

--name wp_mysql \

--restart always \

-v database.sql:/docker-entrypoint-initdb.d/wordpress.sql \

-v /data/wordpress/mysql:/var/lib/mysql \

-e MYSQL_ROOT_PASSWORD=[数据库ROOT用户密码] \

-p 3306 \

mysql --character-set-server=utf8 --collation-server=utf8_general_ci

 

命令非常长,我解释一下各个参数的作用:

-d:这个参数是简写,全称是--detach:表示让容器以后台状态运行;

--name wp_mysql:表示此容器的名字叫做“wp_mysql”,这项可以自定义,后面要用到;

--restart always:表示如果要求容器自动重启。当容器发生错误或者Docker Server被重启时,Docker Server会尝试重新启动此容器;

-v database.sql:/docker-entrypoint-initdb.d/wordpress.sql:-v参数是简写,全称是--volume,这个参数的要求将宿主机的/database.sql文件挂载到容器内的/docker-entrypoint-initdb.d/wordpress.sql上。至于为什么要这个挂载的原因下面说。

-v /data/wordpress/mysql:/var/lib/mysql:这个参数和上面的参数差不多,只不过这里是要求将宿主机的/data/wordpress/mysql目录挂载到容器的/var/lib/mysql目录上,这样做的原因是要让MySQL的数据能写在宿主机的磁盘中,否则当容器被销毁时,之前存在容器里的所有数据都将被销毁。引号之前的路径可以随您的意愿自定义,如果文件夹不存在,Docker会自动创建。

-e MYSQL_ROOT_PASSWORD=[数据库ROOT用户密码]:这个参数也是简写,全称是--env,这个参数负责设置容器内MySQL数据库的root用户密码的,红色部分可以随意修改。

-p 3306:表示对外暴露容器的3306端口(MySQL服务端口),这里不指定需要映射的宿主机端口,因为没什么必要。

mysql:表示容器以mysql[:latest]镜像作为模版启动。

--character-set-server=utf8 --collation-server=utf8_general_ci:这个参数主要是传给容器内的启动脚本的,告诉它使用utf-8作为文本编码,utf8_general_ci作为排序规则。可以不加,不加的话会默认使用瑞典语还是哪个语言作为编码,建议还是设置一下。

 

接下来解释一下为什么要在SQL文件前加上创建和使用数据库的命令,以及要将数据库文件挂载到容器内的/docker-entrypoint-initdb.d/文件夹下。

是这样的,Docker官方的MySQL镜像在容器启动时,会自动检查容器内的/docker-entrypoint-initdb.d/文件夹下是否存在SQL文件,如果有,则尝试执行。我们用mysqldump命令导出的数据库没有创建和使用数据库的命令,直接执行并没有效果,需要加上这两个命令才能在容器创建时同时创建数据库。另外,如果用过一次上面的命令已经成功启动过容器,且将容器内的MySQL数据目录挂载到了宿主机中,那么以后启动MySQL容器的时候不需要再带上刚刚命令中绿色的那个参数,这将导致数据重复导入

上面的命令执行后,稍等一会键入命令:

docker ps

 

如果看到刚刚创建mysql容器状态已经是 UP 了,则代表MySQL容器启动成功。

 

使用下面的命令进入MySQL容器:

docker exec -it wp_mysql /bin/bash

 

然后进入MySQL控制台

mysql -uroot -p

回车后键入root用户密码

 

进入MySQL控制台后输入以下命令展示当前所有的数据库:

show databases;

 

在当前输出的数据库列表中如果有刚刚通过SQL文件创建的数据库,则说明初始导入成功:

 

如果没有,说明初始导入没有成功,可以“cd docker-entrypoint-initdb.d”检查一下挂载进来的SQL文件是否正确,如果可以正确打开并显示内容,可以选择手动导入数据库:

进入MySQL控制台,

create database [数据库名称]

use [数据库名称]

source /docker-entrypoint-initdb.d/[SQL文件名]

 

导入SQL文件成功之后,下次启动MySQL容器时只需要将MySQL数据库库文件挂载到地址位置,不需要再次挂载SQL文件导入,这很重要,所以再啰嗦一遍。

 

(二)启动WordPress容器

因为我们的WordPress容器需要MySQL的支持才能运行,所以一定要在MySQL容器已经启动之后才能启动WordPress。

启动WordPress容器的方式和启动MySQL容器的方式差不多,都是将参数设置为容器的环境变量传进去,只不过这次我们还需要加一个link参数。

启动WordPress容器的命令如下:

 

docker run -d \

--name wordpress \

--restart always \

-v /var/www/html:/var/www/html \

-e WORDPRESS_DB_HOST=mysql \

-e WORDPRESS_DB_USER=root \

-e WORDPRESS_DB_PASSWORD=[数据库ROOT用户密码] \

-e WORDPRESS_DB_NAME=wordpress \

-e WORDPRESS_TABLE_PREFIX=wp_ \

-p 80:80 \

--link wp_mysql:mysql \

wordpress

 

老样子,我解释一下各个参数的作用:

-d:这个参数是简写,全称是--detach:表示让容器以后台状态运行;

--name wordpress:表示此容器的名字叫做“wordpress”,这项可以自定义;

--restart always:表示如果要求容器自动重启。当容器发生错误或者Docker Server被重启时,Docker Server会尝试重新启动此容器;

-v /var/www/html:/var/www/html:-v参数是简写,全称是--volume,这个参数的要求将宿主机的/var/www/html文件夹挂载到容器内的/var/www/html上,本机的目录可以随意,这里笔者为了方便就选择了和容器内的路径一样,而容器中的wordpress是会被安装到/var/www/html目录中的所以一定要是/var/www/html。刚刚一开始准备工作里的“wp-content”目录需要提前拷贝到挂载目录中。

-e WORDPRESS_DB_HOST=mysql:为容器设置环境变量,WORDPRESS_DB_HOST这个环境变量可以告诉容器内的Wordpress数据库主机名称,这个环境变量的具体值可以自定义,但受到--link参数的限制。

-e WORDPRESS_DB_USER=root:为容器设置环境变量,WORDPRESS_DB_USER这个环境变量可以告诉容器内的Wordpress数据库登陆的用户名。

-e WORDPRESS_DB_PASSWORD=[数据库ROOT用户密码]:为容器设置环境变量,WORDPRESS_DB_PASSWORD这个环境变量可以告诉容器内的Wordpress数据库登陆用户的密码。

-e WORDPRESS_DB_NAME=wordpress:为容器设置环境变量,WORDPRESS_DB_NAME这个环境变量可以告诉容器内的Wordpress使用的数据库名。

-e WORDPRESS_TABLE_PREFIX=wp_:为容器设置环境变量,WORDPRESS_TABLE_PREFIX这个环境变量可以告诉容器内的Wordpress数据库表名前缀。

-p 80:80:将宿主机的80端口映射到容器的80端口,宿主机的端口号可以自由更改。

--link wp_mysql:mysql:--link参数表示将其他容器与本容器建立起链接,这里我们将名为“wp_mysql”容器链接到本容器中,冒号后面的是链接过来的容器在本容器中的名称。这个名称必须和之前的“WORDPRESS_DB_HOST”环境变量一致。

wordpress:表示容器以wordpress[:latest]镜像作为模版启动。

 

回车执行命令,然后等待容器启动完成后,在浏览器中访问,不出意外的话就可以成功访问了。

 

(三)使用Docker Compose简化启动

Docker Compose是一个用来定义和运行复杂应用的Docker工具。使用Compose,你可以在一个文件中定义一个多容器应用,然后使用一条命令来启动你的应用,完成一切准备工作。

先安装Docker Compose,安装的方法非常简单,Linux主机只要执行下面的命令就好了:

 

 

上面的命令完成之后尝试输出Docker Compose版本号,如果能够正常输出则表示Docker Compose已成功安装

docker-compose --version

 

安装好之后,根据刚刚的启动命令制作docker-compose.yaml,新建一个名为“docker-compose.yaml”的文件,将下面的内容复制到文件中并保存(注:在这里我们不展开docker-compose.yaml的具体语法及其作用)。

 

注意几点:

1.使用Docker Compose启动wordpress之前,先记得手动关闭和删除之前用命令创建的容器,否则会造成端口冲突和容器名冲突造成无法启动;

2.和之前在上面说的一样,如果已经导入了数据库,就不需要再挂载SQL文件了,直接挂载MySQL数据目录即可;

3.两个需要关联的容器,必须使用同一个网络。

 

确保命令行已在docker-compose.yaml同目录下,使用以下命令启动wordpress:

docker-compose up -d

 

上面的命令中,up表示启动,-d表示后台运行。

如果一切正常,等命令执行结束之后,就可以用docker ps看到刚刚用docker-compose命令创建的两个容器已经启动了。

 

浏览器访问一下,可以正常浏览:

 

 

三、创建一个支持HTTPS的简体中文版WordPress on Docker

如果只是想要简单部署一个WordPress的话,Docker官方仓库里的WordPress国际版镜像就可以满足你的需求了。但如果你有以下两个需求之一,就需要和我一样去手动创建一个WordPress简体中文镜像:

1.您需要WordPress简体中文版的后台ICP备案号设置功能;

2.您需要镜像提供原生HTTPS功能。

 

第一个需求估计需要的人比较少,但第二个需求就有很多人需要了。

官方的WordPress镜像没有HTTPS的功能,即就算是挂载了写有启用SSLEngine的config文件进去都没有用,因为官方镜像中的Apache压根就没有启用SSL模块。如果需要启用SSL模块,就需要修改官方Dockerfile重新构建镜像。

官方WordPress的Docker文件下载地址在这里:https://github.com/docker-library/wordpress

在这里我以WordPress 4.9.1 + Apache + PHP 7.1的Dockerfile做讲解:

 

上面的图片就是Dockerfile的内容,我用红色框框住了三处,这三处就是我们要修改的地方。

第一处要修改的地方:(第28行)RUN a2enmod rewrite expires

这条指令就是要启用容器中Apache的rewrite和expires模块,我们还需要启用一个ssl模块,所以改为:

 

第二处要修改的地方:(第33行)ENV WORDPRESS_SHA1 892d2c23b9d458ec3d44de59b753adb41012e903

这条指令是设置了环境变量:WORDPRESS_SHA1,这个环境变量是为了接下来的校验下载下来的WordPress压缩包安装文件的校验和准备的,所以我们要替换成对应的WordPress简体中文版4.9.1的SHA-1校验和,即整行改为:

 

第三处要修改的地方:(第36行)"https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"

这里是WordPress国际版的下载地址,其中的版本号被替换为环境变量:${WORDPRESS_VERSION},我们直接修改网址为简体中文版的地址:

 

修改完成的Dockerfile内容如下:

 

之后将此Dockerfile和docker-entrypoint.sh文件放在一起,在目录下使用下面的命令构建镜像:

 

注意:和Dockerfile文件放在一起的docker-entrypoint.sh文件权限必须设置为可执行!否则之后启动时会报:“executable file not found”错误。

因为需要从网上下WordPress的简体中文安装包,而WordPress简体中文安装包下载服务器在国外,所以下起来需要好一阵子。

 

构建好之后我们可以用docker images命令看一下,在列表中应该会有一个wordpress_cn:4.9.1的镜像了:

 

之后我们修改之前的docker-compose.yaml,主要修改wordpress的几个地方:

1.使用镜像从之前的wordpress改为使用wordpress_cn:4.9.1;

2.启动容器时挂载000-default.conf(Apache的配置文件)到容器内的/etc/apache2/sites-enabled/000-default.conf;

3.启动容器时将证书目录挂载到容器内的/var/www/cert;

4.将宿主机的443端口映射到容器的443端口(当然,如果您在宿主机上使用Nginx,可以更换其他的宿主机端口)。

 

修改后的docker-compose.yaml如下:

 

附:000-default.conf文件内容:

 

配置完成后,使用Docker Compose启动项目:

 

如果配置一切正常,则可以在浏览器中浏览到效果了:

 

四、权限啊权限

我们在上面的步骤中,将之前的主题等文件挂载到了容器之中,然后我们就会发现一件非常杯具的事情:在升级WordPress或者更改插件时,会弹出这个窗口:

连接信息

 

要执行请求的操作,WordPress需要访问您网页服务器的权限。 请输入您的FTP登录凭据以继续。 如果您忘记了您的登录凭据(如用户名、密码),请联系您的网站托管商。

 

或者删除插件时提示:

未能完整移除插件XXXXX

 

这都是因为WordPress没有办法得到网站特定目录的写权限导致的。

默认情况下,WordPress容器在启动时会检查网站目录下是否存在wp-config.php文件,如果不存在则会进行WordPress安装并设置网站目录的所有者为www-data,但如果网站目录中放入了原生WordPress未自带的文件或目录,WordPress容器是不会去修改其所有者的,从而导致在更新WordPress本体或插件时发生上面的问题。

 

解决这个问题的方法也挺简单,只要下面四步即可:

1.进入WordPress容器:

 

2.修改网站目录所有者为www-data:

 

3.退出容器回到宿主机:

 

4.重启WordPress容器:

 

五、写在最后

Docker是一个非常有用的项目,它大大降低了部署的难度和多环境间的相互影响,有点类似于Python环境下的virtualenv。

在本篇文章里,笔者想告诉大家,虽然Docker官方仓库中有非常多的镜像供大家选择,但并不是所有的镜像都适合您。如果遇到官方镜像不适合自己的情况,完全可以自己动手去改写Dockerfile。

以上即为本篇全部内容,如有疑问,欢迎评论提出。谢谢

 

 

 

 

小柊

2017年12月24日 22:23:38

相关文章

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注