Docker安装及配置多个WordPress站点

之前搭建Wodpress站点一直使用的是lnmp工具,lnmp简单易用,只不过耗不过我这喜新厌旧的毛病。Docker是目前非常流行的环境部署集成工具,而且管理方便。Docker直译为甲板,下边是Docker在维基百科中的介绍:

Docker is a set of platform as a service (PaaS) products that use OS-level virtualization to deliver software in packages called containers. The service has both free and premium tiers. The software that hosts the containers is called Docker Engine. It was first started in 2013 and is developed by Docker, Inc.

在使用Docker之前,需要了解Docker中的一些基本概念,诸如image,container,network等。Docker的重要功能之一就是快速建立本地镜像image,如同Github一样,Docker可以通过版本号从镜像源仓库中Pull取需要的代码或程序,例如wordpress:latest就表示最新的wordpress程序。container就是容器,每个程序都运行在一个container中,以wordpress为例,运行wordpress需要php,mysql的支持,这三个程序都将运行在三个不同的容器中,既然在不同的容器中,就需要相互通信,这个时候就需要使用到网关network.

##查看系统中的容器
docker ps 
docker ps -a
docker ps -aq
##查看系统中的网关
docker network ls
docker network ls -q
##查看系统中的镜像
docker images 
docker images -q
##停止、运行、删除容器或者网关的指令是stop,start,rm,如果想要删除镜像image,则可有用rmi

为了便利化Docker Engine的使用,Docker开发了Docker Compose组件。Docker Compose在一个定义好的文件夹中运行,并将此文件夹视作一个大容器。这个大容器中需要存在一个docker-compose.yml文件,这个文件按照既定格式编写好了需要用到的服务services(小容器),存储volumes,以及通信网关networks. 编辑好了这个yml文件,那么就可以通过运行docker compose up -d来将Services建立并运行起来。

Docker Engine以及Docker Compose的安装

Docker Engine的安装并非难事,通常Docker的官方文档非常详尽。需要注意的一个情况是,使用国内的服务器需要进行源的更换,如果服务器在国内,比如腾讯云我们可以尝试将apt源更换成腾讯的镜像。下边就是Debian 11更换成腾讯源或者阿里源的相关代码,找到文件/etc/apt/sources.list,用下方代码替换官方源即可。

##腾讯云
deb http://mirrors.tencentyun.com/debian/ bullseye main contrib non-free
deb-src http://mirrors.tencentyun.com/debian/ bullseye main contrib non-free
deb http://mirrors.tencentyun.com/debian/ bullseye-updates main contrib non-free
deb-src http://mirrors.tencentyun.com/debian/ bullseye-updates main contrib non-free
deb http://mirrors.tencentyun.com/debian/ bullseye-backports main contrib non-free
deb-src http://mirrors.tencentyun.com/debian/ bullseye-backports main contrib non-free
deb http://mirrors.tencentyun.com/debian-security/ bullseye-security main contrib non-free
deb-src http://mirrors.tencentyun.com/debian-security/ bullseye-security main contrib non-free
##阿里云
deb http://mirrors.cloud.aliyuncs.com/debian/ bullseye main contrib non-free
deb-src http://mirrors.cloud.aliyuncs.com/debian/ bullseye main contrib non-free
deb http://mirrors.cloud.aliyuncs.com/debian/ bullseye-updates main contrib non-free
deb-src http://mirrors.cloud.aliyuncs.com/debian/ bullseye-updates main contrib non-free
deb http://mirrors.cloud.aliyuncs.com/debian/ bullseye-backports main contrib non-free
deb-src http://mirrors.cloud.aliyuncs.com/debian/ bullseye-backports main contrib non-free
deb http://mirrors.cloud.aliyuncs.com/debian-security/ bullseye-security main contrib non-free
deb-src http://mirrors.cloud.aliyuncs.com/debian-security/ bullseye-security main contrib non-free

完成了换源的操作之后,我们就可以开始安装Docker Engine了,安装的首要步骤是更新和剔除旧版本,接着就是通过几行代码完成安装。以Debian为例,官方文档传送门

// 删除旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc

// 更新和安装依赖
sudo apt-get update
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

// Add Docker’s official GPG key:
 sudo mkdir -p /etc/apt/keyrings
 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

// 设置库 Use the following command to set up the repository:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

// 安装,使用以下代码docker compose会同步安装
 sudo apt-get update
 sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

在上边设置库的环节需要注意,如果使用的是国内的服务器访问速度会很慢,因此有必要更换成国内的库,因为我用的国外服务器暂时还不需要,等以后有需求再行记录。需要注意的是,在旧的版本中,Docker Compose的命令是 docker-compose up -d,相较新版本多了短横线。

使用Docker Compose完成Wordpress+nginx+Mariadb+phpmyadmin的安装

新建一个文件夹叫做wp_site1,文件夹内的结构如下图所示:

首先需要有一个docker-compose.yml文件,在这个文件中设定好各个服务容器的参数。docker-compose.yml文件的编写规则另行参考,此处不一赘述。

version: '3'
services:

   nginx:
      image: nginx:latest
      depends_on:
         - testService
      expose:
         - 80
      volumes:
         - ./nginx:/etc/nginx/conf.d
         - ./data/html:/var/www/html
      environment:
         VIRTUAL_HOST: test.com
         LETSENCRYPT_HOST: test.com,www.test.com
         LETSENCRYPT_EMAIL: user@test.com

   testService:
      container_name: testService_container
      depends_on:
         - testService_db
      image: wordpress:6.0.2-php7.4-fpm #禁止使用wordpress:latest,否则无法访问
      expose:
         - 9000
      restart: always   
      volumes:
         - ./data/html:/var/www/html
         # - ./complete_install.sh:/tmp/complete_install.sh
         # - ./package.json:/var/www/html/package.json
         - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
      env_file:
         - .env
  
   testService_db:
      image: mariadb:latest
      container_name: testService_db
      volumes:
        - ./mysql:/var/lib/mysql
      restart: always
      env_file:
         - .env

   testService_PMA:
      image: phpmyadmin/phpmyadmin:latest
      container_name: testService_phpmyadmin
      env_file:
         - .env
      depends_on:
         - testService_db
      restart: always
      ports:
         - 8082:80     
      volumes:
         - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
     
networks:
  default:
    external:
      name: nginx-proxy

上边注意8082这样不常用的端口,需要在防火墙单独开启。关于不能使用wordpress:lates最新版本,我觉得挺奇怪的,用了就无法正常运行,目前没有搞明白。关于LETSENCRYPT_HOSTLETSENCRYPT_EMAIL,如果你没有设置ssl,只是普通的http访问,那么一定要将这两行注释掉,否则会影响正常访问。

还有需要注意的就是最开头的version,这个并不是指称docker-compose.yml文件的更新版本,而是指代docker编译器的版本,如果你写成“1.0”,“2.0”之类的,执行可能会出错但一般会给出修改提示。

然后是.env文件,里边规定了各种需要设定的环境变量。每种服务可以设置哪些环境变量,以Wordpress为例,可以访问https://hub.docker.com/_/wordpress,一般文档中会有相应介绍。下边是对应的env文件示例:

# wordpress
WORDPRESS_DB_HOST=testService_db
WORDPRESS_DB_PASSWORD=YOURPASSWORD
WORDPRESS_DB_USER=USERNAME
WORDPRESS_DB_NAME=DBNAME
WORDPRESS_TABLE_PREFIX=prefix_ 
WORDPRESS_SITE_URL=
WORDPRESS_SITE_DESCRIPTION= 
WORDPRESS_ADMIN_USER=
WORDPRESS_ADMIN_PASSWORD=
WORDPRESS_ADMIN_EMAIL=
WORDPRESS_DEBUG=0

# mariadb
MYSQL_ROOT_PASSWORD=YOURPASSWORD2
MYSQL_USER=USERNAME
MYSQL_PASSWORD=YOURPASSWORD
MYSQL_DATABASE=wordpress
PMA_HOST=testService_db

接下来就是nginx的设置,在nginx文件夹里面,编辑nginx.conf这个文件,内容如下:

server {
  listen 80;
  listen [::]:80;
  access_log off;
  root /var/www/html;
  index index.php;
  server_name www.test.com;
  client_max_body_size 20M;
  # 因为有内外两个nginx,所以要设置两处"client_max_body_size",此处为内层的nginx
  server_tokens off;
  location / {
    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ /index.php?$args;
  }
  # pass the PHP scripts to FastCGI server listening on wordpress:9000
  location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass testService:9000;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param SCRIPT_NAME $fastcgi_script_name;
  }
}

上边代码中设置了client_max_body_size,这是一个很重要的设定,如果不进行修改那么wordpress的默认上传可能不超过1MB。当然看注释也明白,单单修改这里还不够,还有几个地方需要同步修改,其中一个地方就是uploads.ini文件,这个文件是用来对位设置php.ini相关参数的,我们可以将uploads.ini编辑成如下内容:

file_uploads = On
memory_limit = 20M
upload_max_filesize = 20M
post_max_size = 20M
max_execution_time = 600

完成了以上四个文件的编辑,我们就可以通过ssh命令进入wp_site1文件运行 docker compose up -d进行各项服务的安装了。安装完后我们还不能直接访问到站点,外层还需要一个nginx作为访问的入口,命名为nginx-proxy,其内部结构是这样的:

首先也必须有一个docker-compose.yml文件,其内容如下:

version: '3'
services:
  nginx-proxy:
    image: nginx:alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - conf:/etc/nginx/conf.d
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - certs:/etc/nginx/certs:ro
      - ./certs:/etc/nginx/certs
  docker-gen:
    image: jwilder/docker-gen
    container_name: nginx-proxy-gen
    command: -notify-sighup nginx-proxy -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
    volumes_from:
      - nginx-proxy
    volumes:
      - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.docker_gen"
  acme-companion:
    image: nginxproxy/acme-companion
    container_name: nginx-proxy-acme
    volumes_from:
      - nginx-proxy
    volumes:
      - certs:/etc/nginx/certs:rw
      - acme:/etc/acme.sh
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment: 
       NGINX_DOCKER_GEN_CONTAINER: nginx-proxy-gen
   
volumes:
  conf:
  vhost:
  html:
  certs:
  acme:
networks:
  default:
    external:
      name: nginx-proxy

关于nginxproxy/acme-companion,可以访问其github页面,阅读其wiki案例可以大致知晓其运作要求。上边- ./certs:/etc/nginx/certs会在目录中创建一个certs文件夹,这个文件夹就是存放ssl证书的地方,该niginx-proxy所代理的所有域名的ssl文件都存放于此,每个域名有两个必要的文件.crt和.key,例如test.com.crt和test.com.key。在不同服务商处申请得到的ssl证书文件名略有不同,但是都需要改成上述的形式,这是由nginx.tmpl这个模板文件所决定的。nginx.tmpl文件可以可以查阅此处,这是个模板文件,这里是我们上边提到的需要进行client_max_body_size设置的第三个地方。需要在普通http server 处和ssl server处各添加一个client_max_body_size 20m;,应对不同的访问方式。

如上设置好之后在nginx-proxy文件夹内运行 docker compose up -d建立服务。按照上述操作应该就可以完成设置并正常访问了。一个完整的多站点其文件目录结构应当如下:

启动服务

docker network create nginx-proxy

cd nginx-proxy
docker-compose up -d

cd ../wp_site1
docker-compose up -d

cd ../wp_site2
docker-compose up -d

记住一定要先建立nginx-proxy网关。不过有时会出现一些问题导致无法正常访问,我们需要同时关闭出问题的服务(文件夹)以及niginx-proxy服务,关闭服务的方式是在对应文件夹中运行docker compose down 或者 docker compose down --volumes 关闭服务。关闭后需要重新启动docker compose up -d,注意启动顺序,先启动出问题的文件夹,再启动niginx-proxy文件夹,如此,可以将出现问题的几率降至最小。