0%

实战详解 - 使用 Nginx 负载均衡 Docker 中的 WordPress 和 PhpMyAdmin

关于 Nginx 系列其他文章的传送门

  1. 《 老司机都在用的 Nginx 实用配置 》

  2. 《 干货分享 Nginx 反向代理的参数详解 》

  3. 《 8 分钟轻松学会 Nginx 负载均衡和参数调优 》

  4. 《 实战详解 - 使用 Nginx 负载均衡 Docker 中的 WordPress 和 PhpMyAdmin 》     您当前所在位置



logo

一、实验介绍

使用物理机作为 Nginx,全权代理后端运行着 WordPress 的两台 httpd 容器,并对请求进行负载均衡。

为了保证数据的一致性,两台 httpd 连接同一台 mysql 数据库,并且容器的生产数据通过 Docker 存储卷映射到物理机。

为了提高性能,最后会在 Nginx 中启动缓存。

this

拓扑图如下
tuopu

下面开始演示部署过程

二、环境准备

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 账户dbadmin_1

4、为 WordPress 创建账户并创建同名数据库,授予权限。
dbadmin_2
dbadmin_3

到此为止数据库就准备好了

四、部署 WordPress

container

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

1
systemctl restart nginx

六、配置 WordPress

访问 http://192.168.50.11 填写站点信息后,点击安装。
WordPress 配置就完成了,非常简单!
wordpress_1.png

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

默认情况下 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
httpd_11.png
httpd_12.png

到此,Nginx 负载均衡 Docker 容器内的 WordPress 就完成了!

七、启动 Nginx 缓存

为了提高性能,可以打开 Nginx 缓存。

先用 AB 做压力测试,看看不打开缓存时的性能。

1
ab -n 1000 -c 100 http://192.168.50.11/index.php

ab_1.png

可以看到无比异常特别的差!平均每秒只能打开页面 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 测试压力。
ab_2.png

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