关于 Nginx 系列其他文章的传送门
-
《 老司机都在用的 Nginx 实用配置 》
-
《 干货分享 Nginx 反向代理的参数详解 》
-
《 8 分钟轻松学会 Nginx 负载均衡和参数调优 》
-
《 实战详解 - 使用 Nginx 负载均衡 Docker 中的 WordPress 和 PhpMyAdmin 》 您当前所在位置

一、实验介绍
使用物理机作为 Nginx,全权代理后端运行着 WordPress 的两台 httpd 容器,并对请求进行负载均衡。
为了保证数据的一致性,两台 httpd 连接同一台 mysql 数据库,并且容器的生产数据通过 Docker 存储卷映射到物理机。
为了提高性能,最后会在 Nginx 中启动缓存。

拓扑图如下:

下面开始演示部署过程:
二、环境准备
1、在物理机创建生产数据的 Docker 存储卷目录。
1
| mkdir -p /data/{wordpress,mysql.httpd}
|
2、因为 Docker 默认的 bridge 网络无法为容器指定 IP,容器重启后 IP 会变动,这很尴尬,所以这里我们自己创建一个 Docker 网络 wordpress。
1 2 3 4 5
| docker network create \ -d bridge \ --subnet 10.0.0.0/24 \ --gateway 10.0.0.1 \ wordpress
|
三、准备数据库
1、创建并启动 mariadb 的容器。
1 2 3 4 5 6
| docker run -d --name blog_db \ -e MYSQL_ROOT_PASSWORD=monster0303 \ # 指定数据库 ROOT 密码 --network wordpress --ip 10.0.0.2 \ # 指定容器的 IP -v /data/mysql:/var/lib/mysql \ # 指定共享存储的映射目录 mariadb:10.4.7
|
2、创建并启动 phpmyadmin 的容器,为了前期部署方便,发布到宿主机的 8080 端口。
1 2 3 4
| docker run --name dbadmin -d \ -e PMA_HOST=10.10.0.2 \ # 这里指向 mysql 的 IP --network wordpress --ip 10.0.0.3 -p 8080:80 \ # 指定容器的 IP,并发布 80 到宿主机的 8080 phpmyadmin/phpmyadmin
|
3、客户端浏览器打开 192.168.50.11:8080,使用 phpmyadmin 来创建 WordPress 的数据库。
用户名密码使用 mysql 的 ROOT 账户。 
4、为 WordPress 创建账户并创建同名数据库,授予权限。


到此为止数据库就准备好了
四、部署 WordPress

1、从官网下载站点文件,并解压缩到 物理机的存储卷目录。
1 2
| wget https://cn.wordpress.org/latest-zh_CN.tar.gz tar -xvf latest-zh_CN.tar.gz -C /data/
|
2、从模板创建 WordPress 的配置文件。
1 2 3
| cd /data/wordpress cp wp-config-sample.php wp-config.php vim wp-config.php
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| ... # 其他默认不动,省略 // ** MySQL 设置 - 具体信息来自您正在使用的主机 ** // /** WordPress数据库的名称 */ define( 'DB_NAME', 'wordpress' );
/** MySQL数据库用户名 */ define( 'DB_USER', 'wordpress' );
/** MySQL数据库密码 */ define( 'DB_PASSWORD', 'monster0303' );
/** MySQL主机 */ define( 'DB_HOST', '10.0.0.2' );
/** 创建数据表时默认的文字编码 */ define( 'DB_CHARSET', 'utf8' );
/** 数据库整理类型。如不确定请勿更改 */ define( 'DB_COLLATE', '' );
/**#@+ * 身份认证密钥与盐。 * * 修改为任意独一无二的字串! * 或者直接访问{@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org密钥生成服务} * 任何修改都会导致所有cookies失效,所有用户将必须重新登录。 * * @since 2.6.0 */ define( 'AUTH_KEY', 'Txq/R51G9Esetigbt14mHEH9Sxo=' ); # 使用 openssl rand -base64 20 生成 define( 'SECURE_AUTH_KEY', 'Txq/R51G9Esetigbt14mHEH9Sxo=' ); define( 'LOGGED_IN_KEY', 'Txq/R51G9Esetigbt14mHEH9Sxo=' ); define( 'NONCE_KEY', 'Txq/R51G9Esetigbt14mHEH9Sxo=' ); define( 'AUTH_SALT', 'Txq/R51G9Esetigbt14mHEH9Sxo=' ); define( 'SECURE_AUTH_SALT', 'Txq/R51G9Esetigbt14mHEH9Sxo=' ); define( 'LOGGED_IN_SALT', 'Txq/R51G9Esetigbt14mHEH9Sxo=' ); define( 'NONCE_SALT', 'Txq/R51G9Esetigbt14mHEH9Sxo=' );
/**#@-*/
|
3、使用 Dockerfile 创建 httpd 镜像。
注意:centos 自带 php 版本太老,需要使用 REMI 源来安装 php7.3 版,并安装连接数据库的组件 php73-php-mysqlnd。
Dockerfile 内容:vim /data/httpd/Dockerfile
1 2 3 4 5 6 7 8 9 10
| FROM centos:7
LABEL maintainer="monster httpd for centos7 <admin@monster.com>"
RUN yum install -y httpd epel-release https://rpms.remirepo.net/enterprise/remi-release-7.rpm \ && yum install -y php73-php php73-php-mysqlnd
CMD /usr/sbin/httpd -DFOREGROUND
EXPOSE 80/tcp
|
4、构建镜像。
1
| docker build /data/httpd -t httpd:php
|
5、启动 2 个 httpd。
1 2 3
| # ↓ 指定固定 IP # ↓ 指定共享存储目录 docker run --name httpd_1 -d --network wordpress --ip 10.0.0.4 -v /data/wordpress:/var/www/html httpd:php docker run --name httpd_2 -d --network wordpress --ip 10.0.0.5 -v /data/wordpress:/var/www/html httpd:php
|
五、部署 Nginx 代理
1、安装 Nginx
1 2
| yum install epel-release yum install nginx -y
|
2、注释掉 /etc/nginx/nginx.conf 中默认的 server {} 配置段,避免冲突。
3、编辑代理配置文件 vim /etc/nginx/conf.d/wordpress.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| upstream wordpress { server 10.0.0.4:80 weight=1; # httpd_1 的 IP server 10.0.0.5:80 weight=1; # httpd_2 的 IP ip_hash; # 为了配置 wordpress 时不会在两个 httpd 之间漂移,暂时设置为 ip_hash }
server { listen 80; index index.php;
# 顺便把 phpmyadmin 给代理上 location ^~ /dbadmin/ { proxy_pass http://10.0.0.3/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 代理 wordpress 端配置 location ~* .*$ { proxy_pass http://wordpress; # 必须设置把真实客户端的报文首部传给后端,不然 CSS 样式无法显示。 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
|
注意:
- 必须通过设置
proxy_set_header 把真实客户端的报文首部信息传给后端 httpd,不然 CSS 样式无法显示。
nginx.conf 默认配置下,会把 /etc/nginx/conf.d 目录下的所以配置文件 include 进 http {},所以 upstream 前不应该再加 http {}。
4、启动 Nginx
六、配置 WordPress
访问 http://192.168.50.11 填写站点信息后,点击安装。
WordPress 配置就完成了,非常简单!

可以登录博客管理后台,我改了个主题,再次访问 http://192.168.50.11,就看到了。

默认情况下 httpd 的 access.log 日志里,客户端的 IP 是代理服务器的。
不过我们之前在 Nginx 中设置了把真实客户端的 IP 通过 X-Real-IP 传给 httpd_1 和 httpd_2,那么在 httpd 中修改一下 httpd 的日志格式就能看到真实客户端 IP 了。
1 2 3 4 5 6 7 8
| docker exec -it httpd_1 bash [root@18e0a2560632 /]# vi /etc/httpd/conf/httpd.conf ... ... # 把这行修改为这样,开头的 h 替换为 X-Real-IP LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined ... ...
|
最后别忘了把 Nginx 负载均衡配置中的 ip_hash 去掉,就变成默认的轮询负载了。
1 2
| vim /etc/nginx/conf/wordpress.conf ip_hash; # 这行直接删掉
|
刷新 8 次页面,查看两个 httpd 的 access.log 日志,可以从访问时间看出,是轮询负载的。
并且能看到客户端的真实 IP 为 192.168.50.3。


到此,Nginx 负载均衡 Docker 容器内的 WordPress 就完成了!
七、启动 Nginx 缓存
为了提高性能,可以打开 Nginx 缓存。
先用 AB 做压力测试,看看不打开缓存时的性能。
1
| ab -n 1000 -c 100 http://192.168.50.11/index.php
|

可以看到无比异常特别的差!平均每秒只能打开页面 20 个左右。
配置打开 Nginx 缓存
在之前的基础上,添加缓存的配置。
vim /etc/nginx/conf/wordpress.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| upstream wordpress { hash $request_uri consistent; ## 使用“一致性 HASH”算法。 server 10.0.0.4:80 weight=1; server 10.0.0.5:80 weight=1; }
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:1:2 keys_zone=pxycache:20m max_size=1g; # 定义缓存 pxycache
server { listen 80; index index.php;
location ^~ /dbadmin/ { proxy_pass http://10.0.0.3/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
location ~* .* { proxy_pass http://wordpress; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache pxycache; # 使用缓存 pxycache proxy_cache_key $request_uri; # uri 作为键 proxy_cache_valid 200 302 301 1h; # 定义特定响应码的响应内容的缓存时长 proxy_cache_valid any 1m; # 定义特定响应码的响应内容的缓存时长 } }
|
再次使用 AB 测试压力。

可以看到平均每秒打开的页面提高到了 7000 多个,性能提升非常好!是不是感觉心情也变好了呢?