使用docker部署wordpress, 及搭建本地开发环境

最近似乎与网络相克, 先是4月份的时候由于之前博客的主机空间洛杉矶机房到期, 空间服务商没有及时把博客进行转移, 结果丢失了2018年的一些文章, 当时空间商还说可以为我免费补偿一年的空间使用权, 于是开开心心地进行了香港机房迁移.

没想到两个月不到, 坏消息继续传来, 空间商表示现在入不敷出, 于是要在6月30号停止服务.

于是又开始了一轮的可用vps大搜寻的游戏, 原则是:
大陆可以直接访问.
速度快.
免备案.
稳定, 不会在某些特殊事件中意外的down掉.

找一圈也没有发现符合以上特征的服务商. 正好前段时间六四三十周年网络封锁加剧, 大家纷纷表示cloudfare在表现良好. 作为一个cdn提供商, 我突然意识到, 之前的四个条件, 我其实并不需要同时满足, 相反, 我只需要一个好用的vps, 配合vps就可以使用了.

另外之前的博客一直搭建在wordpress的专用主机空间上, 这样好处是博客并不需要过多的精力来进行服务器方面的管理, 但是却缺少了很多自主权, 想了想我这种控制狂还是把一切都控制在自己手里会比较放心.

因此这此便一鼓作气, 把博客和vps等等这些事情一起解决掉.

使用docker部署wordpress.

其实简要来说, 一个wordpress需要这么三个东西, 其一是所依赖的mysql数据库, 其二是php运行环境, 其三就是一个网页服务器了. nginx或者apache.
在我有限的网页服务开发经验, 虽然大家都说nginx如何好如何好, 我却一直更偏好apache, nginx的脚本语法实在是诡异的可以, 我一直觉得天下的语言其实分为两种, 一种是一个完全没有学过该种语言的人可以根据stackoverflow很快的解决问题的语言. 一个是完全没有学过该种语言的连搜索关键词都无法准确定义的语言. 对比nginx和apache的conf文件, 你知道我在说什么.

但是即使apache这种配置文件, 我也是能不用就不用, 没办法, 我是一个懒人, 除了算法等等真正体现人类的思维的奥义, 而且能够泛化到生活的其他方面, 能够改变一个人看待世界的视角的这种学问, 对于怎么写配置文件这种学问, 我实在是懒得学.

好在我们有docker. 更妙的是我们还有docker-compose.
docker的介绍, 安装配置在此就略过不提了. 比较简单.

对于一个wordpress来说, 既然我们依赖上述的三条依赖, 那么我们把这些依赖配齐就可以了. 但是一般mysql和逻辑关系和wordpress弱一些, 所以一般是mysql一个docker镜像, 而wordpress, apache或nginx, php一个镜像.

我们所要做的事情, 就是使用docker下载这两个镜像, 然后使得其能够相互访问, wordpress需要能够访问mysql数据库进行读写. 并进行端口暴露, 最后启动镜像就可以了.

这些事情都可以通过docker-compose来完成, 重点是docker-compose的写法:

    version: '2'
    services:
    mysql:
        image: mysql:5.7
        restart: always
        volumes:
        - ./readventurer_database.sql:/docker-entrypoint-initdb.d/import.sql
        environment:
        MYSQL_USER: readventurer_db_user
        MYSQL_ROOT_PASSWORD: readventurer_db_root_passwd
        MYSQL_DATABASE: readventurer_db
        MYSQL_PASSWORD: readventurer_password

    wordpress:
        depends_on:
        - mysql
        image: wordpress:5.0.2-php5.6-apache
        ports:
          - 80:80
        restart: always
        volumes:
        - ./domains/readventurer.com/public_html:/var/www/html
        environment:
        WORDPRESS_DB_HOST: mysql:3306
        WORDPRESS_DB_USER: readventurer_db_user
        WORDPRESS_DB_NAME: readventurer_db
        WORDPRESS_DB_PASSWORD: readventurer_password

在以上的docker-compose.yaml文件中, 我们定义了两个容器, 在mysql容器中, 使用mysql5.7作为博客数据库, 并定义数据库所使用的用户名, 密码和数据库名, 值得注意的是我们将之前博客dump出来的sql文件外挂在/docker-entrypoint-inidb.d文件夹下, 根据mysql容器的描述, 将一个sql文件外挂在此, 那么在创建容器后就会自动执行文件中的sql语句, 通过这种方法, 我们就可以将之前备份的数据库直接导入到容器中.

在wordpress容器中, 首先是通过depends_on来确保wordpress能够访问mysql中对应的数据库, 其次需要将整个网站的站点文件夹加载到/var/www/html文件夹中. 将打开其80端口, 使得外部网络能够访问博客的站点网页.

最后使用docker-compose -f docker-compose.yaml up -d 启动这两个容器就可以了.

在mac上部署本地开发环境

如果你的系统是linux, 那么在本地部署开发环境其实与上面所述的内容是相似的. 但是如果你使用mac或者win, 那么就麻烦了.

因为docker事实上, 是需要一个linux微环境的, 对于linux系统来讲, 可以在宿主系统直接使用这个微环境, 但是对于mac和win系统, 就必须先有一个linux内核环境, 然后才能实现docker, 所以事实上, 是先使用virtualbox下载了一个虚拟机, 然后在虚拟机中部署的docker.

先来看linux的情况, 在这种情况下, 假如以上的docker-compose.yaml完全不变的话, 那会本地开发环境和网络生产环境相比, 有一个最大的不同就是, 链接解析的问题.

在博客系统的网页链接中, 假设需要访问一张图片, 出于简便和可移植性的原因, 一般图片的地址为域名加上相对地址两部分组成,对于相对地址而言,这一部分没有变化,这很好,但是在生产环境中的域名www.readventurer.com会通过dns被解析成ip, 这如果在本地完全不做变化进行部署的话, 导致的结果就是, 除了首页等等直接访问的有限资源外, 本地环境事实上都会去访问www.readventure.com+图片相对地址, 然后由dns解析出站点的网络ip, 也就是说, 自以为的本地环境, 事实上去访问了远程站点.

所以对于本地开发, 我们首先要做的事情, 就是将数据库中的域名更改了为本地开发域名localhost. 这其实就是在数据库的有关表中, 查找域名, 并将域名替换为本地ip.

我们来建一个update_sitename.sql文件, 并放入以下语句:

    UPDATE wp_options SET option_value = replace(option_value, 'http://www.readventurer.com', 'http://dev.readventurer.com') WHERE option_name = 'home' OR option_name = 'siteurl';
    UPDATE wp_posts SET guid = replace(guid, 'http://www.readventurer.com','http://dev.readventurer.com');
    UPDATE wp_posts SET post_content = replace(post_content, 'http://www.readventurer.com', 'http://dev.readventurer.com');
    UPDATE wp_postmeta SET meta_value = replace(meta_value,'http://www.readventurer.com','http://dev.readventurer.com');

将这个update_sitename.sql同样放置在前文介绍的docker-entrypoint-initdb.d文件夹, 使得mysql容器在导入备份数据库下, 就立即进行本地域名更新. 注意这是的dev.readventurer.com是我的自定义域名, 我会在/etc/hosts中同时将其指向到localhost, 这样就实现了本地开发环境.

通过这种操作, 系统就可以通过http://dev.readventure.com, 或者http://localhost 来访问本地开发网页.

但是对于mac和win来说, 事情就又复杂了一层, 由于docker实际上是使用虚拟机来实现的, 那么localhost只能指向到宿主机, 但是其实我们是要找宿主机内的虚拟机内的docker容器. 这么说吧, 网页浏览器向localhost的80端口发了一个请求, 但是使用上述的方法启动完之后, 由于虚拟机和宿主机的网络是通过一块虚拟网上连接, 从网络的视角来看, 等于是宿主机插了两块网卡, 一块网卡的另一端连着的虚拟机上, 才实际运行着docker, 宿主机的80端口本质上没有程序在监听. 最后的访问一定是失败的.

在mac上运行

    docker-machine env default

来查看虚拟机的详细环境, 可以看到

    export DOCKER_HOST="tcp://192.168.99.100:2376"

类似这样的结果, 这就是虚拟机与宿主机在虚拟网络中的子网络.

因此, 不能使用localhost来访问站点, 而是需要使用http://192.168.99.100 也就是虚拟机的虚拟网络地址来访问站点才行.

由此我们得到了在mac上部署的三个步骤.

  1. docker-compose.yaml
    version: '2'
    services:
    mysql:
        image: mysql:5.7
        restart: always
        volumes:
        - ./readventurer_database.sql:/docker-entrypoint-initdb.d/import.sql
        - ./updata_sitename.sql:/docker-entrypoint-initdb.d/update.sql
        environment:
        MYSQL_USER: readventurer_db_user
        MYSQL_ROOT_PASSWORD: readventurer_db_root_passwd
        MYSQL_DATABASE: readventurer_db
        MYSQL_PASSWORD: readventurer_password
    
    wordpress:
        depends_on:
        - mysql
        image: wordpress:5.0.2-php5.6-apache
        ports:
          - 80:80
        restart: always
        volumes:
        - ./domains/readventurer.com/public_html:/var/www/html
        environment:
        WORDPRESS_DB_HOST: mysql:3306
        WORDPRESS_DB_USER: readventurer_db_user
        WORDPRESS_DB_NAME: readventurer_db
        WORDPRESS_DB_PASSWORD: readventurer_password
    
  2. 修改hosts, 添加
    192.168.99.100    dev.readventurer.com
    
  3. 访问http://dev.readventurer.com 进行本地开发.