docker 最省资源运行WordPress

@eyasliu 2017-08-05 09:25:45发表于 eyasliu/blog

背景

我想要运行WordPress程序,启动一个展示类的简单网站,但是我不想在我机器上安装php运行环境,也不想装mysql,因为在我看来他们的安装过程都是很繁琐,配置多,升级困难,不好维护。如果用docker 容器则不会有这些问题。

需求分析

那问题来了,既然WordPress依赖php和mysql,那么运行在docker里面和运行在主机不是一样的占用资源吗?对于这个问题,我的回答是,php是必须的,但是mysql并不是必须的,我可以使用sqlite替代mysql。sqlite是一种非常轻量级关系型数据库,他的资源占用非常的低,而且目前Linux所有发行版都默认附带sqlite,所以是不需要安装的。所以结果就是 只需要php,不需要mysql。

镜像选择

既然需要php运行环境,那就需要php镜像。但是在 dockerhub 能搜到 WordPress 镜像和 php 镜像,怎么选呢?

  • php 镜像只提供了最基本的运行环境,和最基本的php扩展
  • WordPress 镜像是基于 php 镜像,启用了WordPress 运行所需的所有扩展

所以很明显,当然是选择 WordPress 镜像。

最简操作

我想到了这个方法,肯定别人也早就想到了,早在几年前就有人做好了,如果觉得下面的方法太麻烦太难懂,想速成,就这样:

docker run -d -p 80:80 dorwardv/wordpress-sqlite-nginx-docker

这样就启动了一个基于 nginx 的 wordpress ,使用的 sqlite 插件。

这个项目的地址: https://github.com/dorwardv/wordpress-sqlite-nginx-docker

如果你要用这个方法,那下文的那么多内容其实不用看了。如果你想学到更多的东西,请继续看下文。

启动 WordPress 容器

默认镜像

在 WordPress 的默认镜像(latest)中,是使用php的默认镜像,php的默认镜像,是使用的debian系统,加上apache,暴露出 80 端口。所以在docker运行WordPress最快的方式就是

docker run -p 80:80 wordpress

命令运行完,就可以使用浏览器打开 http://localhost 应该就能看到WordPress安装界面了。
注:运行前请确定80端口没有被占用,如果被占用,可以使用另外的端口,在-p参数指定即可,如 -p 8080:80

alpine 镜像

上面是可以正常的运行,但是资源占用可能比在主机中运行更耗资源,要使php占用资源尽可能的小,首选alpine镜像。alpine镜像只提供了最小化系统运行所需。WordPress的alpine镜像tag为 4.8.1-fpm-alpine,没错,php的 alpine 镜像只有fpm版本。

php的 alpine 镜像使用

php:alpine镜像只启动了php-fpm,fpm监听9000端口(php服务都是监听9000端口),但是这个端口并不是web端口,而是 unix 端口,具体怎么用,我们要先从php的运行流程说起。

先看一段nginx 的 php 配置

server { 
  // 其他配置
  // ......
  // ......
  location ~ [^/]\.php(/|$) { 
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
      return 404;
    }

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO       $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php; 
  } 
}

当浏览器访问一个url时,访问的是nginx或者apache的web服务器,web服务器根据url匹配到这个请求应该给 fastcgi 处理,这个时候fastcgi 会把匹配到的php文件给 127.0.0.1:9000 处理,这个9000端口就是php启动的cgi服务,php服务接收到fastcgi 的请求后执行php文件,然后把执行的结果返回给fastcgi,fastcgi在给回 web服务器,web服务器再响应给用户,用户就能看到php代码执行的结果了。

写了那么长,其实可以简单地概括成:web服务器接收到请求后,让php服务执行,然后把执行结果返回。

再回到php:alpine镜像,其实这个镜像启动的9000端口就是php服务,WordPress的alpine镜像是基于php:alpine,只是在原本镜像基础上增加了php扩展和把wp源码放在了镜像中。所以说启动WordPress镜像的结果就只是启动了一个php服务罢了,这个php服务本身不接收不处理任何web请求。所以,我们还是需要一个apache或者nginx。

由于nginx比apache更轻量级,所以我选择了nginx,当然,是docker的nginx:alpine镜像。

另一个问题,WordPress源码是在WordPress镜像的/usr/src/wordpress里面,运行的时候会把 /usr/src/wordpress复制到 /var/www/html,然后定义了/var/www/html为挂载目录。这个过程可以在这里看到。这里就需要用到docker的volumes-from参数了,用这个参数指定一个容器启动一个新容器,会让新容器直接使用被指定的容器挂载目录。所以使用这个特性就可以让nginx使用到WordPress镜像的源码了。

先启动wordpress镜像,并暴露出端口

docker run -p 9000:9000 --name wordpress-fpm wordpress:4-fpm-alpine

第二部,新建一个nginx配置文件vhost.conf,内容如下

server { 
  listen 80; 
  server_name localhost; 
  root /var/www/html; 

  index index.php; 

  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  rewrite /wp-admin$ $scheme://$host$uri/ permanent;

  location ~ [^/]\.php(/|$) { 
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
      return 404;
    }

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO       $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php; 
  } 
}

第三部,启动nginx容器

docker run -p 80:80 -v `pwd`/vhost.conf:/etc/nginx/conf.d/default.conf --volumes-from wordpress-fpm nginx:alpine

就这样,访问http://localhost 就能到吗wordpress安装界面了

数据库

wordpress总算是开始安装了,不过说好的不用mysql而转用sqlite呢。

官方镜像中,在docker-entrypoint.sh 有mysql数据库的检查代码,我们要先去掉它,先把文件提取出来,删除 TERM=dumb php -- <<'EOPHP' ........ $mysql->close(); EOPHP 的这大段php代码即可,改好后留着备用,待会定制镜像时会放进新镜像中

wordpress 使用sqlite 需要用到一个插件: SQLite Integration

插件的使用方法是,把插件解压放到plugins目录,然后把该插件目录的 db.php 放到 wp-content 目录下,在执行安装过程,就能发现跳过了输入数据库信息的过程。

定制镜像

把插件也放在镜像里面,每次启动就不用重新复制插件了。这样需要使用 Dockerfile 定制镜像。我们基于wordpress:4-fpm-alpine 镜像去定制

FROM wordpress:4-fpm-alpine
MAINTAINER eyasliu@163.com

COPY docker-entrypoint.sh /usr/local/bin/

RUN curl -o sqlite-plugin.zip https://downloads.wordpress.org/plugin/sqlite-integration.1.8.1.zip && \
    unzip sqlite-plugin.zip -d /usr/src/wordpress/wp-content/plugins/ && \
    cp /usr/src/wordpress/wp-content/plugins/sqlite-integration/db.php /usr/src/wordpress/wp-content && \
    chmod +x /usr/local/bin/docker-entrypoint.sh && \
    rm -rf sqlite-plugin.zip

Dockerfile 有了,构建一下新的镜像

docker build -t fpm-sqlite-wp:latest .

构建好后就可以启动了

docker run -d -p 9000:9000 --name fpm-wp fpm-sqlite-wp
docker run -d -p 80:80 --name nginx --volumes-from fpm-wp nginx:alpine

到此为止,镜像定制完成。

如果使用docker-compose,配置可以这样写

version: '2'
services:
  fpm-wp:
    image: fpm-sqlite-wp
    networks: 
      - mywp
    expose:
      - '9000'
  
  nginx:
    image: nginx:1.11.10-alpine
    depends_on:
      - fpm-wp
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    volumes_from:
      - fpm-wp
    networks:
     - mywp
    ports:
      - '80:80'

结语

整个过程是很繁琐,但是这种定制在一个稍微复杂项目中我觉得不算什么,我的项目中nginx是做了很多事情的,所以是必须的,而且结果的确达到了节省资源的目的。