# Linux实战笔记:WordPress文创项目部署全流程记录

本项目是一个Wordpress站点上线实例,后续相关内容:
Linux实战笔记:WordPress文创项目五项优化结合Ansible ROLE
Linux实战笔记:WordPress文创项目运维使用说明手册

一.互联网网站架构完整演进路线

一个完整的项目并不是一蹴而就的,就像盖房子一样,要先打地基再砌砖。因此我们的项目也是从单机项目开始,然后再一步步进行功能解耦和升级。因此对于本项目的演进,我们可以进行以下规划:

1.1 单机LNMP架构(初创小型站点)

适用场景:用户量极小、低成本快速上线;
架构:单台服务器集成Nginx+PHP+MySQL;
优缺点:部署简单、成本低;存在单点故障,流量上涨后资源争抢严重。
流量模型:客户端→DNS→单机Web服务器(Web+DB同机)
请添加图片描述

1.2 Web与数据库分离架构(数据库解耦)

核心原理:PHP/Java应用消耗CPU,数据库读写消耗大量内存,两类服务资源需求冲突,因此我们需要对数据库进行解耦,拆分数据库独立服务器,隔离硬件资源。
架构:独立Web服务器 + 独立数据库服务器;
流量模型:客户端→DNS→Web服务器→独立DB服务器。

  • 数据库解耦,拆分数据库独立服务器
    请添加图片描述

1.3 Web负载均衡集群(多Web节点分担并发)

核心组件:Nginx/Haproxy/LVS作为流量调度器;Keepalived保障调度器高可用;
解决痛点:单台Web服务器并发上限低,高峰期CPU/带宽打满。
架构:调度器集群 + Web服务器集群 + 独立数据库。

  • 通过Nginx/Haproxy代理或LVS调度实现web负载均衡
  • 增加Keepalived保持代理服务器的高效可用
    请添加图片描述

1.4 动静分离架构

静态资源(图片、css、js、视频)单独Nginx静态节点部署;动态PHP/Tomcat应用单独节点;静态资源可接入CDN就近缓存,降低应用服务器压力。

  • 动态网站与静态网站分离,让服务器专注一件事(动态与静态web资源也进行分离,使用nfs分别挂载)
    请添加图片描述

1.5 数据库集群架构

优化方案:主从复制、读写分离、分库分表、共享存储;
解决单机数据库查询瓶颈、数据丢失风险,支撑海量数据读写。

  • 主从数据库、分库分表、读写分离
  • 共享存储
    请添加图片描述

1.6 缓存与CDN架构

静态数据可以通过varnish、squid或者nginx进行缓存,将数据缓存到距离用户更近的位置,构建CDN(内容分发网络)架构。

CDN:静态资源缓存至全国边缘节点,缩短用户访问延迟,减轻源站压力;

1.7 监控与安全架构

监控平台:Zabbix、Prometheus;
作用:全链路服务器资源、服务状态监控,故障实时告警;

请添加图片描述

实验环境规划

  1. 基础模板机批量创建9台Linux虚拟机;
  2. 代理服务器采用双网卡:VMnet1仅主机模式配置网段:192.168.4.0/24、VMnet8 NAT模式配置网段: 192.168.8.0/24;
  3. Windows宿主机使用WindTerm通过SSH远程管理所有虚拟机;
  4. 主机IP规划:
    请添加图片描述

二.项目整体需求背景

项目名称:云途文创官网建设与架构迭代项目
核心载体:WordPress开源CMS建站系统,分两期迭代升级架构,贴合企业真实业务流量增长场景;
前期参考资料:《云途文创官网建设与架构迭代项目甲方需求文档.pdf》,包含业务背景、流量指标、生产环境规范。

三.ansible部署

由于本次项目体量较大,需要控制的主机较多,我们可以选择在项目开启之前先部署ansible,为后面批量操作进行铺垫,可以简化部分操作,减少工作量。本次我们选择在zop主机(即监控主机。实际可根据需要选择)部署ansible,用作控制节点

3.1hosts文件修改

配置hosts文件内容,方便后续控制:

[root@zop ansible]# 
[root@zop ansible]# vim /etc/hosts
#增加配置:
192.168.8.5 haproxy1
192.168.8.6 haproxy2
192.168.8.11 web1
192.168.8.12 web2
192.168.8.13 web3
192.168.8.30 database
192.168.4.41 nfs1
192.168.8.42 nfs2
3.2ansible主机免密配置

配置 SSH 密钥免密登录:

[root@zop ~]# ssh-keygen -f /root/.ssh/id_rsa -N ''
[root@zop ~]# for i in haproxy1 haproxy2 web1 web2 web3 database nfs1 nfs2               #for循环分发密钥
> do
> ssh-copy-id root@$i
> done
3.3ansible安装

本次采用离线 RPM 包安装,需提前将 ansible-6.3.0-1.el8.noarch.rpmansible-core-2.13.3-1.el8.x86_64.rpm 上传至 control 节点(zop主机) /root 目录,执行安装命令

[root@zop ~]# dnf -y install ansible-6.3.0-1.el8.noarch.rpm ansible-core-2.13.3-1.el8.x86_64.rpm cowsay-3.04-16.el8.noarch.rpm
3.4核心配置文件修改

创建~/ansible目录,创建ansible.cfg文件,指定inventory主机清单文件

配置ansible.cfg文件:

# 1. 创建自定义配置目录并切入
# 1. 创建自定义配置目录
[root@control ~]# mkdir ~/ansible

# 2. 编辑主配置文件,指定主机清单路径
[root@control ~]# vim ~/ansible/ansible.cfg
# 写入以下内容
[defaults]
# 全局默认配置
inventory = /root/ansible/hosts  # 指定主机清单文件路径
forks = 8                   # 可选:SSH 并发连接数量,默认5,我们要控制8台就写8

配置主机清单文件:

主机清单文件用于定义 Ansible 管理的所有主机及主机组,是 Ansible 识别被管理节点的核心文件,路径与 ansible.cfg 中 inventory 配置一致(~/ansible/hosts):

[root@zop ansible]#  vim hosts

[haserver]
haproxy[1:2]

[webserver]
web[1:3]

[dataserver]
database

[nfsserver]
nfs[1:2]

(注意组名不要和成员名一样)

3.5测试 Ansible 环境连通性
[root@zop ansible]# ansible all -m ping

项目一期:单机架构 + 数据库解耦架构

阶段一:单机LNMP部署WordPress(初创基础期)

  • 项目一期拓扑图
  • 业务拆分,缓解单个服务器的压力
  • DNS服务可以选做
    请添加图片描述

WordPress简介

  • WordPress是一款开源免费 PHP+MySQL架构的内容管理系统(CMS,Content Management System),2003 年正式发布,基于 GPLv2 开源协议,任何人都可免费使用、修改、二次开发、商用,无需授权费。
  • 核心定位:快速搭建各类网站,无需大量代码基础,是全球占有率最高的建站程序,全球超 43% 网站基于 WordPress 搭建。
  • WordPress可演变成为:博客、企业官网、商城、资讯门户、课程网站、作品集、下载站等,需要程序员二次开发。

需求背景

  • 阶段一:初创稳定上线阶段(基础期)
  • 业务场景:企业刚完成品牌注册,仅需搭建基础官网,完成企业信息展示、基础资讯发布,无大规模推广动作。
  • 流量指标:日均独立访问300人,瞬时并发访问≤50,每日文章、图片上传量≤20条
  • 核心痛点:零架构需求,仅需低成本快速上线、服务稳定可用,满足企业基础展示需求
  • 架构要求:单机架构(Nginx/Apache+PHP+MySQL同机部署),快速完成WordPress站点搭建、基础配置、主题美化、功能插件部署。

1.部署LNMP架构

由易到难,自动化程度递增,我们提供三种快速部署LNMP的方法:

  • 方法一:使用纯shell脚本
    • 优点:逻辑直白、编写简单、执行速度快
    • 缺点:不够灵活,重复执行易报错
  • 方法二:ansible剧本结合脚本
    • 优点:兼顾了剧本幂等性,又保留了脚本的便捷性
    • 缺点:语法混用会提升后续维护与排障的复杂度
  • 方法三:使用ansible角色
    • 优点:自动化程度极高,可复用程度极高
    • 缺点:编写麻烦,语法较难
方法一:使用脚本快速部署
  • web1主机操作,部署LNMP架构
    因为之前部署了ansible,这里直接使用ansible进行操作
#切入ansible目录
[root@zop ~]# cd /root/ansible/
#将nginx软件包上传到zop主机的/root目录下,使用copy模块拷贝到web1主机
[root@zop ansible]# ansible web1 -m copy -a "src=/root/nginx-1.22.1.tar.gz dest=/root/"
#编写部署nginx的脚本
[root@zop ansible]# vim nginx.sh
#########脚本内容:##########
#!/bin/bash
dnf -y install gcc make pcre-devel openssl-devel
useradd nginx
tar -xf /root/nginx-1.22.1.tar.gz
cd nginx-1.22.1
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module
#指定安装目录,运行用户,运行组,开启加密功能
make && make install
ls /usr/local/nginx

#远程运行脚本
[root@zop ansible]# ansible web1 -m script -a "./nginx.sh"
#运行完毕,使用ansible远程查看安装目录进行验证:
[root@zop ansible]# ansible web1 -m shell -a "ls /usr/local/nginx"
web1 | CHANGED | rc=0 >>
conf
html
logs
sbin

接下来使用第二个脚本快速部署mariadb和php,以及配置使nginx支持动态页面,实现动静分离:

[root@zop ansible]# vim php.sh
########脚本内容:#########
#!/bin/bash
dnf -y install php php-fpm php-mysqlnd php-json mariadb-server mariadb
systemctl  enable  mariadb   --now
sed -i '38c listen = 127.0.0.1:9000' /etc/php-fpm.d/www.conf #开启php-fpm监听9000端口
systemctl enable php-fpm --now
sed -i '45c\            index index.php  index.html index.htm;' /usr/local/nginx/conf/nginx.conf #设置index.php为默认首页
sed -i '65,71s/#//' /usr/local/nginx/conf/nginx.conf #去掉65到71行的注释
sed -i '70s/_params/.conf/' /usr/local/nginx/conf/nginx.conf
sed -i '69s/^./#/' /usr/local/nginx/conf/nginx.conf #注释掉第69行
/usr/local/nginx/sbin/nginx #启动nginx
echo "/usr/local/nginx/sbin/nginx"  >> /etc/rc.d/rc.local #设置nginx开机自启动
chmod +x /etc/rc.d/rc.local

[root@zop ansible]# ansible web1 -m script -a "./php.sh"

注意!我们的脚本本质上是简单命令的集合,没有相关的逻辑检测,一旦运行时某处出现报错,千万不要重复运行脚本

注意!脚本中sed修改配置文件的命令都是基于百分百确定对应配置准确位置的情况下,实际配置过程中,需要自行去查看自己的对应配置的位置,避免因软件版本不同等原因导致修改出现问题

方法二:使用剧本结合脚本部署

创建角色(其实本项目无需角色直接写剧本就行)


[root@zop ansible]# mkdir roles
#创建角色
[root@zop ansible]# ansible-galaxy init roles/lnmp

#编写任务文件
[root@zop ansible]# vim roles/lnmp/tasks/main.yml 

任务文件内容:

---
# tasks file for roles/lnmp
- name: 安装软件包
  yum: 
    name:
      - gcc
      - make 
      - pcre-devel
      - openssl-devel
      - php
      - php-fpm
      - php-mysqlnd
      - php-json
      - mariadb
      - mariadb-server
      - mariadb-devel
    state: present 

- name: 拷贝nginx源码包
  copy: 
    src: /root/nginx-1.22.1.tar.gz
    dest: /root/

- name: 解压缩nginx
  unarchive: 
    src: /root/nginx-1.22.1.tar.gz
    dest: /root/

- name: 执行脚本,编译安装nginx并修改配置文件
  script: /root/nginx.sh

- name: 启动mariadb服务
  service: 
    name: mariadb
    state: started
    enabled: yes

- name: 重启php服务
  service: 
    name: php-fpm
    state: restarted
    
- name: 启动nginx服务
  shell: /usr/local/nginx/sbin/nginx
  ignore_errors: true

编写脚本:

[root@zop ansible]# vim /root/nginx.sh
#####脚本内容:########
#!/bin/bash
sed -i '38c listen = 127.0.0.1:9000' /etc/php-fpm.d/www.conf #开启php-fpm监听9000端口
useradd nginx
cd /root/nginx-1.22.1
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module
make && make install
sed -i '45c\            index index.php  index.html index.htm;' /usr/local/nginx/conf/nginx.conf #设置index.php为默认首页
sed -i '65,71s/#//' /usr/local/nginx/conf/nginx.conf #去掉65到71行的注释
sed -i '70s/_params/.conf/' /usr/local/nginx/conf/nginx.conf
sed -i '69s/^./#/' /usr/local/nginx/conf/nginx.conf #注释掉第69行
echo "/usr/local/nginx/sbin/nginx"  >> /etc/rc.d/rc.local #设置nginx开机自启动
chmod +x /etc/rc.d/rc.local

编写剧本:

[root@zop ansible]# vim ansible_nginx.yml

---
- hosts: web2
  roles:
    - lnmp

运行剧本:

[root@zop ansible]# ansible-playbook ansible_nginx.yml 
方法三:ansible角色(ROLE)

本方法适用于长期的批量部署工作。

Role目录结构
roles/lnmp/
├── tasks/          # 任务执行(主逻辑,软件包安装,模板渲染,角色调用等)
├── templates/      # 配置模板(用来渲染配置文件,避免精细化文本替换的繁琐操作)
├── handlers/       # 触发器(重载/重启服务)
├── vars/           # 全局变量(统一版本、路径等参数,后续任务变更统一修改)
└── playbook.yml    # 调用Role的剧本
1)初始化lnmp角色目录:
[root@zop ~]# cd ansible/
[root@zop ansible]# ansible-galaxy init roles/lnmp
#切入角色目录:
[root@zop ansible]# cd roles/lnmp/
2) 编写部署主任务 tasks/main.yml

按执行顺序拆分任务,自动判断是否已安装,避免重复编译 / 重复操作,全程幂等。

---
# 1. 安装系统依赖(Nginx编译依赖 + PHP/MariaDB 运行依赖)
- name: 安装 LNMP 全量依赖包
  yum:
    name:
      - gcc
      - make
      - pcre-devel
      - openssl-devel
      - php
      - php-fpm
      - php-mysqlnd
      - php-json
      - mariadb
      - mariadb-server
      - mariadb-devel
    state: present

# 2. 创建 Nginx 运行用户
- name: 创建 Nginx 系统用户
  user:
    name: "{{ nginx_user }}"
    shell: /sbin/nologin
    create_home: no
    state: present

# 3. 拷贝 Nginx 源码包到被管理节点
- name: 拷贝 Nginx 源码包
  copy:
    src: "{{ nginx_src_package }}"
    dest: "/root/"
    mode: 0644

# 4. 解压源码包
- name: 解压 Nginx 源码包
  unarchive:
    src: "/root/nginx-{{ nginx_version }}.tar.gz"
    dest: "/root/"
    remote_src: yes
    creates: "/root/nginx-{{ nginx_version }}"  # 已解压则跳过

# 5. 编译安装 Nginx(已安装则跳过,实现幂等)
- name: 编译安装 Nginx
  shell: |
    ./configure --prefix={{ nginx_install_path }} \
    --user={{ nginx_user }} --group={{ nginx_user }} \
    --with-http_ssl_module --with-http_stub_status_module && make && make install
  args:
    chdir: "/root/nginx-{{ nginx_version }}"
    creates: "{{ nginx_install_path }}/sbin/nginx"  # 已存在则不执行编译

# 6. 渲染 Nginx 主配置文件(模板方式,替代 sed 改行号)
- name: 生成 Nginx 主配置文件
  template:
    src: nginx.conf.j2
    dest: "{{ nginx_install_path }}/conf/nginx.conf"
    mode: 0644
  notify: 重载 Nginx  # 配置变更才触发重载

# 7. 渲染 PHP-FPM 配置文件
- name: 配置 PHP-FPM 监听端口
  template:
    src: www.conf.j2
    dest: /etc/php-fpm.d/www.conf
    mode: 0644
  notify: 重启 PHP-FPM

# 8. 启动 MariaDB 服务并设置开机自启
- name: 启动 MariaDB 服务
  service:
    name: "{{ mariadb_service }}"
    state: started
    enabled: yes

# 9. 启动 PHP-FPM 服务并设置开机自启
- name: 启动 PHP-FPM 服务
  service:
    name: php-fpm
    state: started
    enabled: yes

# 10. 设置 Nginx 开机自启(写入 rc.local,兼容原有习惯)
- name: 设置 Nginx 开机自启
  lineinfile:
    path: /etc/rc.d/rc.local
    line: "{{ nginx_install_path }}/sbin/nginx"
    state: present
- name: 赋予 rc.local 执行权限
  file:
    path: /etc/rc.d/rc.local
    mode: 0755

# 11. 启动 Nginx 服务(幂等:已启动则不重复操作)
- name: 启动 Nginx 服务
  shell: "{{ nginx_install_path }}/sbin/nginx"
  args:
    creates: /var/run/nginx.pid
3.)配置模板:

本身模板(templates)作用就是直接替换掉被配置的主机的对应文件的。从思路上来说,完全可以直接拷贝已经配置好的主机上的对应配置文件,然后使用copy模块直接覆盖(但是需要考虑没有对应主机专门的配置)。
但实际上,我们使用template模块无法直接简单粗暴的拷贝文件当作模板,因为template会解析特殊字符,template ≠ 复制文件,它是渲染 + 写入二合一。所以要么使用copy模块简单粗暴的拷贝已配置完毕文件/覆盖掉未配置文件,要么使用template模块仅插入有效的核心配置。

  1. templates/nginx.conf.j2

本模板目的是为了配置nginx的配置文件nginx.conf ,作用是直接替换掉原配置文件中的内容。

worker_processes  auto;
events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    server_tokens off;#关闭版本号显示
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;
        root         {{ web_root }};
        index        index.php index.html index.htm;

        location / {
            root   html;
            index index.php  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location ~ \.php$ {
        root           html;
        fastcgi_pass   {{ php_fpm_listen }};
        fastcgi_index  index.php;
        include        fastcgi.conf;
        }
    }
}
  1. templates/www.conf.j2
[www]
; 仅保留核心配置,其余默认配置保留
listen = {{ php_fpm_listen }}
listen.allowed_clients = 127.0.0.1
listen.acl_users = apache,nginx
user = apache
group = apache
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[soap.wsdl_cache_dir]  = /var/lib/php/wsdlcache
4)编写触发器 handlers/main.yml
---
# handlers file for roles/lnmp
- name: 重载 Nginx
  shell: "{{ nginx_install_path }}/sbin/nginx -s reload"

- name: 重启 PHP-FPM
  service:
    name: php-fpm
    state: restarted

- name: 重启 MariaDB
  service:
    name: "{{ mariadb_service }}"
    state: restarted
5)定义全局变量 vars/main.yml

统一定义所有路径、版本参数,后续修改无需改任务代码:

# 路径与版本变量
nginx_version: "1.22.1"
nginx_install_path: "/usr/local/nginx"
nginx_src_package: "/root/nginx-{{ nginx_version }}.tar.gz"
nginx_user: "nginx"
web_root: "{{ nginx_install_path }}/html"

# PHP 配置
php_fpm_listen: "127.0.0.1:9000"

# MariaDB 配置
mariadb_service: "mariadb"
6) 编写调用 Role 的 Playbook
[root@zop lnmp]# vim /root/ansible/deploy_lnmp.yml

---
- name: 批量部署 LNMP 架构
  hosts: webserver  # 对应主机清单中的 webserver 组
  become: yes       # 以 root 权限执行
  roles:
    - lnmp          # 调用我们编写的 lnmp role

2.数据库配置

  • 创建wordpress业务库
  • 授权数据库业务用户
    • 用户名:wpuser01@localhost(授权仅本机登录)
    • 密码:wordpress
[root@web1 ~]# mysql
#创建数据库wordpress,指定该数据库默认字符集为 utf8mb4
MariaDB [(none)]> CREATE DATABASE wordpress character set utf8mb4;
#创建wpuser01用户并仅授予 wordpress 数据库的全部权限(对其他数据库无权限),设置该数据库用户密码为 wordpress
MariaDB [(none)]> GRANT ALL ON wordpress.* TO wpuser01@localhost IDENTIFIED BY  'wordpress';
MariaDB [(none)]> FLUSH PRIVILEGES;        #刷新授权表

3.上线WordPress

  • wordpress-6.1.1-zh_CN.tar.gz上传至虚拟机web1的/root
  • 将代码上线至Nginx的网页根目录**/usr/local/nginx/html**
  • 注意:
    • php动态页面是由php-fpm程序处理的,它的进程所有者为apache
    • 所以上线的页面需要让apache用户有权限
[root@web1 ~]# tar -xf wordpress-6.1.1-zh_CN.tar.gz wordpress/
[root@web1 ~]# cp -r wordpress/* /usr/local/nginx/html/
[root@web1 ~]# chown -R apache:apache /usr/local/nginx/html/ #修改归属,让php-fpm服务有权限

4.WordPress初始化

  • Windows客户端使用浏览器访问:http://192.168.8.11
  • 根据提示完成初始化

请添加图片描述

填写数据库信息,指定数据库位置及连接用户

  • 一定要与之前创建的库、授权的用户保持一致
    请添加图片描述

请添加图片描述
根据提示完成初始化,创建登录用户名admin,密码123456

请添加图片描述
安装完成
请添加图片描述
登录站点:

请添加图片描述
进入网站页面
请添加图片描述
可以进行以下基础业务操作:

  1. admin发布文章;
  2. 创建普通用户zhangsan,密码1234.com;
  3. zhangsan登录评论文章;
  4. admin后台审核评论。
  5. 管理后台,可以修改主题风格等

阶段二:数据库解耦分离架构(性能瓶颈期)

2.1业务场景说明

线下推广曝光暴涨,日均访客5000,瞬时并发300~500,数据库日查询10万+;
单机Web与DB资源抢占,出现页面加载慢、数据库查询超时;
需求:Web、数据库进行解耦,实现资源隔离,拆分独立服务器。

2.2整体迁移流程

  1. web1单机备份wordpress数据库(mysqldump);
  2. 将备份数据库文件远程传输至database数据库主机;
  3. 在新的数据库主机(即database主机)创建同名库、授权远程访问账号;
  4. database主机导入备份的数据库数据;
  5. web1修改WordPress配置,指向远程数据库;
  6. 关闭web1本机mariadb服务。
2.2.1 web1备份数据库并传输
# 导出数据库备份文件
[root@web1 ~]# mysqldump -uroot wordpress > /root/wordpress.sql  
# scp远程拷贝至database主机
[root@web1 ~]# scp    /root/wordpress.sql   root@192.168.8.30:/root
2.2.2 database主机数据库环境初始化
  • 配置新的数据库服务器

    • 新数据库服务器database创建wordpress库
    • 授权用户:wpuser01@'%',密码:wordpress

    注意:database服务器上的数据库业务用户要允许在任意主机登录

# 安装数据库服务
[root@database ~]# dnf -y install mariadb-server mariadb
# 启动并开机自启
[root@database ~]# systemctl enable mariadb --now
# 验证3306端口
[root@database ~]# ss -nutlp | grep :3306
# 登录数据库执行建库、授权
[root@database ~]# mysql
#创建数据库并设置支持字符集
MariaDB [(none)]> CREATE DATABASE wordpress character set utf8mb4;
# 授权账号允许任意主机远程连接(@'%')
MariaDB [(none)]> GRANT ALL ON wordpress.* TO wpuser01@'%' IDENTIFIED BY  'wordpress';
#刷新授权表
MariaDB [(none)]> FLUSH PRIVILEGES;

2.2.3 database恢复备份数据
#还原数据
[root@database ~]# mysql -uroot wordpress < /root/wordpress.sql
2.2.4 web1测试远程数据库连通性

在web1进行连接测试:

[root@web1 ~]# mysql -h192.168.8.30 -uwpuser01 -p'wordpress'
MariaDB [(none)]>  SHOW TABLES FROM wordpress;  

请添加图片描述
可以看到WordPress库的表

2.2.5 修改WordPress数据库连接地址
  • 更新WordPress数据库连接
    • web服务器修改/usr/local/nginx/html/wp-config.php 文件
    • 更新数据库服务器地址:192.168.8.30
    • 停止web1本机的数据库服务
[root@web1 ~]# vim /usr/local/nginx/html/wp-config.php
 31 /** Database hostname */
 32 define( 'DB_HOST', '192.168.8.30' );              #指定数据库服务器地址
 
 #关闭本机数据库服务
 [root@web1 ~]# systemctl disable mariadb --now 

请添加图片描述
改成:

请添加图片描述

2.2.6 业务验证
  • 客户端访问测试
    • 数据库迁移之后,Windows客户端继续访问:http://192.168.8.11/
    • 编写文章,新产生的数据会存储在database数据库服务器

项目二期:负载均衡、共享存储、高可用集群

业务阶段说明

  • 阶段三:Web服务并发瓶颈阶段(负载均衡期)

    • 业务场景:线下春季文创展会预热活动开启,大量用户集中访问官网查看活动详情、预约展会名额。
    • 流量指标:日均独立访问1.2万人,高峰期瞬时并发访问2000,单节点Web服务QPS满载。
    • 核心痛点:单台Web服务器处理能力有限,高并发场景下CPU、带宽耗尽,出现页面打不开、请求超时、服务宕机等问题,无法承载峰值流量。
    • 架构要求:搭建Web负载均衡集群,新增多台Web应用节点,通过负载均衡设备实现流量分发,分担单节点压力,提升网站并发承载能力,解决高峰期服务瘫痪问题。
  • 阶段四:业务高可用保障阶段(集群高可用期)

    • 业务场景:全国文旅创意高峰论坛开启,官网开启线上门票售卖、直播预约、作品投稿功能,业务直接关联企业营收,故障零容忍。
    • 流量指标:高峰期瞬时并发访问8000,7×12小时持续高负载运行,全年无停机维护窗口期。
    • 核心痛点:单负载均衡节点、单数据库节点存在严重单点故障风险,一旦服务器宕机、服务异常,会直接导致全站瘫痪,造成门票订单丢失、品牌口碑受损、直接经济损失。
    • 架构要求搭建高可用代理集群+数据库主从架构,实现核心服务冗余备份,杜绝单点故障;实现服务故障自动切换,保障业务7×24小时稳定运行。
  • 通过Nginx/Haproxy代理或LVS调度实现web负载均衡

    • 增加Keepalived保持代理服务器的高效可用
    • 选择web1主机充当ansible的控制节点

请添加图片描述

阶段三:Web服务并发瓶颈阶段(负载均衡期)

3.1 Web站点扩展

  • 将web1主机的WordPress网站页面上传至服务器web2、web3
  • 使web2、web3也可以独立运行WordPress
  • 实际生产环境建议提前发布升级更新公告
3.1.1 web2web3部署LNMP

使用之前提前部署好的ansible批量部署web2和web3的lnmp架构:
ansible的tasks文件和脚本在前文已经写好,这里不再引用
只需要对剧本进行细微修改即可:

---
- hosts: web2,web3
  roles:
    - lnmp
3.1.2 打包wordpress文件内容

打包web1中的wordpress文件内容并循环分发到web2web3

#打包指定目录下的数据
[root@web1 ~]# tar -zcf wordpress.tar.gz -C /usr/local/nginx/html .
#将打包页面拷贝至web2、web3
[root@web1 ~]# for i in 192.168.8.12 192.168.8.13
> do
> scp /root/wordpress.tar.gz root@$i:/root 
> done
3.1.3 批量上线WordPress

使用之前已经部署过的ansible进行远程批量部署
回到我们的控制主机zop进行操作:

#上线WordPress
[root@zop ansible]# ansible web1,web2 -m shell -a "tar -xf /root/wordpress.tar.gz -C /usr/local/nginx/html/"
#确保php-fpm有权限
[root@zop ansible]# ansible web1,web2 -m shell -a "chown -R apache:apache /usr/local/nginx/html/"
#重启php-fpm服务
[root@zop ansible]# ansible web1,web2 -m shell -a "systemctl restart php-fpm"
  • 截至目前3台web服务器,均可以独立发布WordPress页面
  • Windows浏览器访问测试:
    • http://192.168.8.11
    • http://192.168.8.12
    • http://192.168.8.13
3.1.4 当前架构缺陷
  1. 图片、附件存储在单台Web本地,负载均衡轮询至其他节点时图片丢失;
  2. 网站代码更新需要逐台Web服务器操作,维护效率极低;
    解决方案:NFS统一共享存储,所有Web挂载同一套网站代码与上传目录。
3.1.5 小结与反思
  • 目前3台web服务器均可以独立上线WordPress
  • 但是目前如果访问http://192.168.8.11,发表含有图片的文章
  • 图片会存储在web1的**/usr/local/nginx/html/wp-content/upload/年/月/日**
  • 如果请求轮询至web1发布文章,存储图片至web1
  • 查看文章时,请求轮询至web2,有可能web2本地找不到此图片
  • 其他业务场景中,此问题必须考虑,解决方案可以考虑对象存储
  • 目前wordpress图片在数据库中存储的是一个路径,路径指向了web1,调用时还找web1
  • 但如果遇到了wordpress代码需要迭代更新,难道每一个主机都要单独更新吗?

3.2 NFS共享存储统一网站资源

  • nfs1主机搭建NFS共享服务,共享/nfs_share目录
  • 将web1主机的WordPress代码迁移至nfs1服务器的共享目录/nfs_share
  • 所有web服务器挂载nfs1服务器共享的/nfs_share
3.2.1 nfs1部署NFS服务端
#下载软件包
[root@nfs1 ~]# dnf -y install nfs-utils rpcbind
#共享/nfs_share目录
[root@nfs1 ~]# vim /etc/exports
/nfs_share  192.168.8.0/24(rw,no_root_squash,sync)
#启动服务并设置开启自启
[root@nfs1 ~]# systemctl enable rpcbind --now
[root@nfs1 ~]# systemctl enable nfs-server --now
#查看nfs共享清单
[root@nfs1 ~]# showmount -e
Export list for nfs1:
/nfs_share 192.168.8.0/24

3.2.2 web1网站代码迁移至NFS共享
# 打包站点代码。之前做过可以不做
[root@web1 ~]# tar -zcf wordpress.tar.gz -C /usr/local/nginx/html .  
# 传输至nfs1
[root@web1 ~]# scp wordpress.tar.gz  root@192.168.8.41:/root

nfs1将web文件解压至共享目录:

[root@nfs1 ~]# tar -xf wordpress.tar.gz -C /nfs_share/
3.2.3 三台Web服务器永久挂载NFS共享

下一步需要将NFS共享的目录分别挂载至三个web主机
因为三台主机操作完全一致,所以可以使用ansible批量一键部署。

回到zop主机操作:

#删除现有本地页面文件
[root@zop ansible]# ansible webserver -m shell -a "rm -rf /usr/local/nginx/html/*  "
#安装nfs文件系统
[root@zop ansible]# ansible webserver -m shell -a "dnf -y install nfs-utils"
#永久挂载共享数据
[root@zop ansible]# ansible webserver -m lineinfile -a "path=/etc/fstab line='192.168.8.41:/nfs_share   /usr/local/nginx/html   nfs    defaults,_netdev   0   0' state=present"
#刷新挂载
[root@zop ansible]# ansible webserver -m shell -a "mount -a"
#查看挂载验证
[root@zop ansible]# ansible webserver -m shell -a "df -h"

NFS架构优势:

  1. 所有Web节点共用一套网站代码,统一更新,无需逐台发布;
  2. 文章上传图片统一存放在共享存储,任意Web节点访问均可加载图片;

阶段四:业务高可用保障阶段(集群高可用期)

4.1 负载均衡选型对比

  • 可选方案:
    • Nginx
    • LVS
    • Haproxy
      本项目选用Haproxy适配7层Web业务
      配合Keepalived实现双机热备,消除负载均衡单点故障。
4.1.1 搭建负载均衡集群

两台haproxy主机的配置操作过程一模一样,因此我们可以结合ansible简化批量操作
在zop主机批量安装haproxy:

[root@zop ansible]# ansible haserver -m shell -a "dnf -y install haproxy"

编辑haproxy1的配置文件:

[root@haproxy1 ~]# vim  /etc/haproxy/haproxy.cfg 
......删除64行之后的内容,并加入以下内容......
listen websrv
   bind *:80
   balance roundrobin
   server web1 192.168.8.11:80 check inter 2000 rise 2 fall 5
   server web2 192.168.8.12:80 check inter 2000 rise 2 fall 5
   server web3 192.168.8.13:80 check inter 2000 rise 2 fall 5

编辑haproxy2的配置文件:

[root@haproxy2 ~]# vim  /etc/haproxy/haproxy.cfg 
......删除64行之后的内容,并加入以下内容......
listen websrv
   bind *:80
   balance roundrobin
   server web1 192.168.8.11:80 check inter 2000 rise 2 fall 5
   server web2 192.168.8.12:80 check inter 2000 rise 2 fall 5
   server web3 192.168.8.13:80 check inter 2000 rise 2 fall 5

在控制节点zop主机批量启动服务:

[root@zop ansible]# ansible haserver -m shell -a "systemctl enable haproxy --now  "

4.2 搭建keepalived服务

因为搭建keepalive需要进行的配置有所差异,我们需要分别进行配置

4.2.1haproxy1主机搭建keepalived服务:

设置浮动IP(VIP):192.168.4.50

[root@haproxy1 ~]# dnf -y install keepalived
[root@haproxy1 ~]# vim /etc/keepalived/keepalived.conf

修改文件内容:

! Configuration File for keepalived

global_defs {
   notification_email {
     kisaki@gmail.com                       #设置邮箱。发生故障时会给这个邮箱发邮件
   }
   notification_email_from root@localhost   #设置发件人邮箱
   smtp_server 192.168.8.5                  #邮箱服务器的地址
   smtp_connect_timeout 30
   router_id LVS_1                          #路由ID,两台主机不能相同
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state MASTER                             #角色为:主
    interface ens160                         #VIP的绑定网卡
    virtual_router_id 51                     #集群ID,主备必须一致
    priority 100                             #优先级
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.4.50                          #VIP
    }
}
......因为我们不配置LVS,后面的内容可以全部删除......

关于keepalive配置文件本处不作过多解释,若有需要可以前往:# Linux运维Day05:Keepalived热备基础,Keepalived+LVS实现负载均衡

启动服务并验证VIP:

[root@haproxy1 ~]# systemctl enable keepalived --now
[root@haproxy1 ~]# ip a s ens160

请添加图片描述
可以看到VIP4.50已经绑定到ens160网卡上

4.2.2haproxy2主机搭建keepalived服务:

设置浮动IP(VIP):192.168.4.50

[root@haproxy2 ~]# dnf -y install keepalived
[root@haproxy2 ~]# vim /etc/keepalived/keepalived.conf

修改文件内容:

! Configuration File for keepalived

global_defs {
   notification_email {
     kisaki@gmail.com
   }
   notification_email_from root@localhost
   smtp_server 192.168.8.6
   smtp_connect_timeout 30
   router_id LVS_2
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens160
    virtual_router_id 51
    priority 80
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.4.50
    }
}

启动服务:

[root@haproxy2 ~]# systemctl enable keepalived --now
#注意,这里是看不到VIP的
[root@haproxy1 ~]# ip a s ens160

请添加图片描述
这里是看不到ens160网卡上的VIP的。因为VIP现在在nfs1主机。当nfs1宕机/出故障,VIP将会飘到nfs2主机,此时再使用ip a s才能看到vip

4.3 业务验证与故障测试

  1. 客户端访问统一入口 http://192.168.4.50(VIP);
  2. 三台Web执行 tail -f /usr/local/nginx/log/access.log,刷新页面可见流量轮询分发;
  3. 模拟haproxy1主节点宕机,VIP自动漂移至haproxy2,客户端访问无中断。

项目三期:数据库集群与Zabbix监控平台

阶段五:数据库集群(NFS实时备份,数据库主从同步)与Zabbix监控

  • NFS升级可以考虑Ceph分布式存储平台,但由于资源有限采用现有办法升级
  • 数据库从业务层面也有很多升级方案,后续学习,这里做主从同步即可

请添加图片描述

5.1 NFS实时备份

NFS数据同步我们采用:Inotifywait + rsync结合shell脚本完成
inotify-tools-3.13.tar.gz源码包上传至虚拟机nfs1的/root

#安装依赖和rsync
[root@nfs1 ~]# dnf  -y  install gcc  gcc-c++  make rsync
#释放源码包
[root@nfs1 ~]# tar    -xf    inotify-tools-3.13.tar.gz    -C    /usr/src/
#切入目录,进行初始化
[root@nfs1 ~]# cd /usr/src/inotify-tools-3.13/
[root@nfs1 inotify-tools-3.13]# ./configure 
#编译并安装
[root@nfs1 inotify-tools-3.13]# make
[root@nfs1 inotify-tools-3.13]# make install
5.1.1 编写实时备份脚本

nfs1服务器实现无密码管理nfs2服务器

#生成密钥对
[root@nfs1 ~]# ssh-keygen  -f '/root/.ssh/id_rsa'  -N '' 
#分发密钥对
[root@nfs1 ~]# ssh-copy-id root@192.168.8.42

编写同步脚本:

[root@nfs1 ~]# vim /opt/nfsrsync.sh
#!/bin/bash
while  inotifywait -rqq /nfs_share/
do
  rsync -az --delete /nfs_share/ root@192.168.8.42:/nfs_share/
  #要注意目录结尾的斜杠:/ 
done
#赋予权限
[root@nfs1 ~]# chmod +x /opt/nfsrsync.sh
#后台执行脚本
[root@nfs1 ~]# /opt/nfsrsync.sh &
5.1.2 nfs同步验证

回到nfs2主机上,也要安装rsync软件:

[root@nfs2 ~]# dnf -y install rsync

验证nfs同步:

#在nfs1主机对/nfs_share/目录进行查看操作
[root@nfs1 ~]# ls /nfs_share/
#回到nfs2主机,查看根目录,发现/nfs_share目录已经被同步
[root@nfs2 ~]# ls /
bin   dev  home  lib64  mnt    nfs_share  proc  run   srv  tmp  var
boot  etc  lib   media  mydvd  opt        root  sbin  sys  usr

5.2 数据库主从同步

  • 数据库主从同步是一项自动备份数据的技术,可实现从库实时备份主库数据
  • database主机备份数据,授权主从用户,备份数据 将nfs2 兼为从数据库服务器(性能允许的情况下也可以单独开一个新的虚拟机)
  • database主机指定开启binlog日志,指定server_id
  • 授权主从同步用户:repluer,密码:1234.com
5.2.1 database主机指定开启binlog日志,指定server_id
[root@database ~]# vim /etc/my.cnf.d/mariadb-server.cnf
#在配置文件[mysql]之下添加两行配置
16 [mysqld]
#开启二进制日志,用于主从,还能做数据恢复。开启log-bin是搭建主从同步的前提条件
17 log-bin=master
#给当前 MySQL 实例分配唯一服务 ID,是主从复制强制要求的参数
18 server_id=30 

#重启服务
[root@database ~]# systemctl restart mariadb
5.2.2 database主机创建主从同步用户
#创建主从同步的用户,仅授予读取的权限
GRANT  REPLACATION  SLAVE ON  *.*  TO  repluser@"%" IDENTIFIED BY  "1234.com";
5.2.3 备份database数据库

想要进行主从同步,从数据库数据必须先和主数据库完全一致才行,因此我们直接导出database数据,在从数据库恢复即可

#备份主数据库所有数据
[root@database ~]# mysqldump -A > /opt/all.sql
#使用scp拷贝到从数据库
[root@database ~]# scp /opt/all.sql root@192.168.8.42:/root
#在从数据库恢复数据,需要先清空本地服务器。
5.2.4 nfs2数据库服务器安装数据库服务并导入数据
#安装软件
[root@nfs2 ~]# dnf -y install mariadb-server maridb
#不要照抄行号
[root@nfs2 ~]# vim /etc/my.cnf.d/mariadb-server.cnf    
 16 [mysqld]
 18 server_id=42 
[root@nfs2 ~]# systemctl enable mariadb --now 
[root@nfs2 ~]# mysql < /root/all.sql
5.2.5 nfs2数据库进行从数据库配置

在进行nfs2的从数据库配置之前,我们先在database主机进入数据库,查看我们的binlog文件和偏移量信息:

MariaDB [(none)]> show master status;
+---------------+----------+--------------+------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| master.000006 |      339 |              |                  |
+---------------+----------+--------------+------------------+
1 row in set (0.001 sec)

可以看得到,database主机的binlog文件是master.000006,偏移量是339。这两个数据是我们配置从数据库需要的信息,每个人都不一样,需要按照个人真实情况进行填写

接下来配置从数据库:

#进入数据库
[root@nfs2 ~]# mysql                       
MariaDB [(none)]> CHANGE MASTER TO
    -> MASTER_HOST="192.168.8.30",
    -> MASTER_USER="repluser",
    -> MASTER_PASSWORD="1234.com",
    -> MASTER_LOG_FILE="master.000006",    #binlog日志文件从主服务器查看
    -> MASTER_LOG_POS=339;                 #偏移量从主服务器查看
MariaDB [(none)]> START SLAVE;             #启动SLAVE进程
MariaDB [(none)]> SHOW SLAVE STATUS \G     #查看主从状态
#在一堆信息中看到下面两个绿色的“yes”就算配置成功
   Slave_IO_Running: Yes
   Slave_SQL_Running: Yes

5.3 搭建Zabbix监控平台

搭建Zabbix监控平台具体分为两步:

  1. 配置LNMP
  2. 部署Zabbix

由于Zabbix对nginx的配置,php和mariadb的版本有特殊要求,所以无法使用之前的一键部署LNMP平台的脚本和剧本,需要进行更细化的配置,并且准备好安装包

5.3.1 部署nginx

使用之前部署nginx的脚本快速部署nginx
脚本内容:

#!/bin/bash
dnf -y install gcc make pcre-devel openssl-devel
useradd nginx
tar -xf /root/nginx-1.22.1.tar.gz
cd nginx-1.22.1
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module
make && make install
ls /usr/local/nginx

nginx-1.22.1.tar.gz提前上传至zop主机的/root目录

运行脚本:

[root@zop ~]# . /root/ansible/nginx.sh 

修改nginx.conf配置文件,支持 PHP 动态请求:

[root@zop ~]# vim /usr/local/nginx/conf/nginx.conf

[root@zop ~]# vim /usr/local/nginx/conf/nginx.conf
...略...
http{
...略...
  fastcgi_buffers 8 16k;                #缓存php生成的页面内容,8个16k
  fastcgi_buffer_size 32k;              #缓存php生产的头部信息
  fastcgi_connect_timeout 300;          #连接PHP的超时时间
  fastcgi_send_timeout 300;             #发送请求的超时时间
  fastcgi_read_timeout 300;             #读取请求的超时时间
  ...略...
  server {
  ...略...
  location ~ \.php$ {                   #配置nginx支持php动态请求
              root           html;
              fastcgi_pass   127.0.0.1:9000;
              fastcgi_index  index.php;
              #注释此行
              #fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
              #修改为fastcgi.conf
              include        fastcgi.conf;
        }
  ...略...
}


5.3.2 配置php

安装php相关软件:zabbix要求php-7.4以上版本,所以采用离线安装
将php7.4.tar.gz上传至zop主机的/root

[root@zop ~]# tar -xf php7.4.tar.gz            #解压压缩包
[root@zop ~]# cd php74/                        #切换至工作目录
[root@zop php74]# dnf -y localinstall *.rpm    #安装php相关软件
[root@zop php74]# vim /etc/php-fpm.d/www.conf  #修改php-fpm配置文件,支持9000端口
...约第38行...
#注释这一行
38 ;listen = /run/php-fpm/www.sock
#添加此行
39 listen = 127.0.0.1:9000
...略...
[root@zop php74]# php -v                        #查看php版本为7.4.19
PHP 7.4.19 (cli) (built: May  4 2021 11:06:37) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.19, Copyright (c), by Zend Technologies
5.3.3 配置mariadb

Zabbix 6.4.7 要求 MariaDB 版本 ≥ 10.6,但内置的版本不满足条件,因此同样采用离线安装。将 mariadb10.6.tar.gz 上传至zop主机的 /root 目录:

#解压软件包
[root@zop ~]# tar -xf  mariadb10.6.tar.gz 
#切入mariadb目录
[root@zop ~]# cd mariadb10.6/
#安装mariadb相关软件 
[root@zop mariadb10.6]# dnf -y localinstall *.rpm 
5.3.4 启动服务

启动LNMP相关服务,并编写测试页面

#启动mariadb
[root@zop mariadb10.6]# systemctl enable  mariadb --now  
#启动php-fpm
[root@zop mariadb10.6]# systemctl enable  php-fpm --now
#启动nginx。可以写service文件实现systemctl控制
[root@zop mariadb10.6]# /usr/local/nginx/sbin/nginx
#编写测试页面:
[root@zop mariadb10.6]# vim   /usr/local/nginx/html/test.php
<?php
$i=33;
echo $i;
?>
#访问测试:
[root@zop mariadb10.6]# curl 192.168.8.100/test.php
33[root@zop mariadb10.6]# 
5.3.5 zabbix监控端部署
#安装依赖
[root@zop ~]# dnf -y install net-snmp-devel libcurl-devel libevent-devel libxml2-devel  
#创建zabbix启动用户
[root@zop ~]# useradd -s /sbin/nologin zabbix
#解压:
[root@zop ~]# tar -xf zabbix-6.4.7.tar.gz  
#切入软件包目录
[root@zop ~]# cd zabbix-6.4.7/
#初始化编译
[root@zop zabbix-6.4.7]# ./configure \  #配置zabbix,初始化zabbix
> --enable-server \        #支持zabbix监控功能(服务端)
> --enable-agent \        #支持zabbix被监控功能(客户端)
> --with-mysql \          #让zabbix支持mysql/mariadb数据库
> --with-net-snmp \       #支持 SNMP 监控(用于网络设备、服务器硬件)
> --with-libcurl \        #支持 Web 监控、API 监控、HTTPS
> --with-libxml2          #支持 XML 数据解析(配合监控使用)

#安装zabbix
[root@zop zabbix-6.4.7]# make install
#查看配置文件验证:
[root@zop zabbix-6.4.7]# ls /usr/local/etc/
zabbix_agentd.conf    zabbix_server.conf
zabbix_agentd.conf.d  zabbix_server.conf.d
[root@zop zabbix-6.4.7]# ls /usr/local/bin/
zabbix_get  zabbix_js  zabbix_sender
[root@zop zabbix-6.4.7]# ls /usr/local/sbin/
zabbix_agentd  zabbix_server
5.3.6 Zabbix数据库配置
  • 创建zabbix服务存储监控数据的数据库:zabbix库
  • 授权php网页使用的连接用户:zabbix,密码:zabbix
#进入数据库
[root@zop ~]# mysql
#创建zabbix数据库,支持中文字符集
MariaDB [(none)]> CREATE DATABASE zabbix CHARACTER SET utf8 COLLATE utf8_bin;
#授权用户zabbix,密码为zabbix
MariaDB [(none)]> GRANT ALL  ON zabbix.*  to zabbix@"localhost" IDENTIFIED BY 'zabbix';
#刷新授权表立即生效
MariaDB [(none)]> FLUSH PRIVILEGES ;
#退出数据库
MariaDB [(none)]> exit

使用zabbix模板文件还原数据库(zabbix自带)
导入 Zabbix 数据库模板文件(注意顺序不能颠倒):

#切入存放数据库文件的目录
[root@zop ~]# cd zabbix-6.4.7/database/mysql/
#恢复数据,注意顺序
[root@zop mysql]# mysql -uzabbix -pzabbix zabbix < schema.sql
[root@zop mysql]# mysql -uzabbix -pzabbix zabbix < images.sql
[root@zop mysql]# mysql -uzabbix -pzabbix zabbix < data.sql
5.3.7 初始化zabbix

将zabbix的php监控页面发布至Nginx的网页根目录

#切入web目录
[root@zop mysql]# cd /root/zabbix-6.4.7/ui/
#将页面递归拷贝放到web根目录
[root@zop ui]# cp -r * /usr/local/nginx/html/ 
#授予权限,实验环境临时赋权方便排错,生产环境不建议使用777最大权限
[root@zop ui]# chmod  -R 777 /usr/local/nginx/html/

为满足zabbix初始化,需要修改php相关配置,否则在初始化的时候会提示异常
修改配置文件:/etc/php.ini

[root@zop ui]# vim /etc/php.ini            #修改配置文件,不要抄行号,以实际情况为主
923 date.timezone = Asia/Shanghai          #时区调整为 Asia/Shanghai
694 post_max_size = 32M                    #最大执行时间,秒
388 max_execution_time = 300               #POST(上传提交)数据最大容量
398 max_input_time = 300                   #服务器接收数据的时间限制
# 重启 PHP-FPM 使配置生效
[root@zop ui]# systemctl restart php-fpm

在 Windows 浏览器中访问 http://192.168.8.100/index.php,按照以下步骤完成初始化:

请添加图片描述

请添加图片描述
配置zabbix连接mariadb数据库,用户名:zabbix,密码zabbix(我们之前授权的数据库用户密码)

请添加图片描述
设置zabbix服务器的名字:zabbix-server

请添加图片描述

汇总信息确认,点击下一步
请添加图片描述

初始化成功

请添加图片描述

  • 登录zabbix管理页面
    • 用户名:Admin
    • 密码:zabbix

请添加图片描述
会发现全是红色,这是因为系统(Linux 系统)缺少 en_US.UTF-8 语言区域配置
请添加图片描述
点击左下角用户头像 → “User settings” → “Language” 选择 “Chinese (zh_CN)”,点击 “Update” 即可切换为中文界面。
请添加图片描述

请添加图片描述

再返回首页,已经可以正常显示
请添加图片描述

5.3.8 启动zabbix服务
  • 配置数据库:修改zabbix_server服务端配置文件,启动zabbix_server服务
[root@zop ui]# vim /usr/local/etc/zabbix_server.conf
87 DBHost=localhost                               #数据库主机(去掉注释顶格写)
99 DBName=zabbix                                  #设置数据库名称
115 DBUser=zabbix                                 #设置数据库账户
123 DBPassword=zabbix                             #设置数据库密码(去掉注释顶格写))
38 LogFile=/tmp/zabbix_server.log                 #设置日志
  • 启动zabbix相关服务
    • 启动zabbix_server服务,端口号:10051
    • 启动zabbix_agent服务,端口号:10050
#启动服务端
[root@zop ui]# zabbix_server 
[root@zop ui]# ss -nutlp | grep :10051 
#启动客户端
[root@zop ui]# zabbix_agentd 
[root@zop ui]# ss -nutlp | grep :10050

#将服务设置为开启自启
[root@zop ui]# echo zabbix_server >> /etc/rc.d/rc.local
[root@zop ui]# echo zabbix_agentd >> /etc/rc.d/rc.local
[root@zop ui]# chmod +x /etc/rc.d/rc.local
5.3.9 zabbix被监控端部署

所有的被监控主机均需要进行源码编译安装zabbix_agent。所以我们可以结合ansible使用剧本快速批量部署zabbix。
被监控端具体操作分为三步:

  1. 编写批量部署的剧本
  2. 事先将zabbix-6.4.7.tar.gz上传至虚拟机zop(即ansible控制节点)的/root目录
  3. 修改被监控端配置文件

编写剧本zabbix.yml:

- hosts: web1  #先在web1上部署
  become: yes
  tasks:
    #  拷贝文件 
    - name: 拷贝压缩包
      copy:
        src: /root/zabbix-6.4.7.tar.gz
        dest: /opt/zabbix-6.4.7.tar.gz

    #  安装依赖
    - name: 安装依赖
      dnf:
        name:
          - gcc
          - pcre-devel
          - autoconf
          - make
          - zlib-devel
        state: present

    #  解压文件
    - name: 解压
      unarchive:
        src: /opt/zabbix-6.4.7.tar.gz
        dest: /opt
        remote_src: yes

    #  编译安装
    - name: 编译安装
      shell: |
        ./configure --enable-agent
        make install
      args:
        chdir: /opt/zabbix-6.4.7

运行剧本:

[root@zop ansible]# ansible-playbook zabbix.yml

修改被监控端配置文件

  • web1主机操作
[root@web1 ~]# vim /usr/local/etc/zabbix_agentd.conf
113 Server=127.0.0.1,192.168.8.100                #允许访问服务地址列表,即允许谁监控我
167 ServerActive=192.168.8.100:10051              #监控服务器ip地址和端口
30 LogFile=/tmp/zabbix_agentd.log                 #日志文件
#创建启动用户
[root@web1 ~]# useradd -s /sbin/nologin zabbix
#启动服务:
[root@web1 ~]# zabbix_agentd  
#查看端口
[root@web1 ~]# ss -nutlp | grep :10050 
 #将服务设置为开机自启
[root@web1 ~]# echo zabbix_agentd >> /etc/rc.d/rc.local
#赋予文件执行权限
[root@web1 ~]# chmod +x /etc/rc.d/rc.local  
5.3.10 基础监控配置

登录 Zabbix Web 界面,点击左侧菜单栏 监测 → 主机 → 创建主机
请添加图片描述

填写主机信息:
主机名称:web1(尽可能与真实主机名保持一致)
可见的名称:web1
主机群组:选择 Linux servers
接口:类型选择 Agent,IP 地址填写 192.168.8.11(即被监控主机web1的IP地址),端口保持 10050
请添加图片描述

在模板框搜索并添加 Linux by Zabbix agent 模板,选择完毕点击添加
请添加图片描述
添加完毕,点击监测 → 主机 → 最新数据
请添加图片描述
在这里就可以查看当前所有的监控项了请添加图片描述

至此,本项目框架已经部署完毕。

项目优化

安全加固

安全方面的优化我们可以分为两个阶段,前期(单机阶段)和后期(项目部署完成阶段)

前期安全加固

根据前期单机部署阶段的需求,我们需要没有额外硬件 / 架构投入的,低成本、易落地、收益明确的基础安全措施。

1)隐藏 Nginx 版本信息

本优化只需加入一行代码即可,已经融入前文Ansible Role的nginx模板文件中

修改 Nginx 主配置文件:

[root@web1 ~]# vim /usr/local/nginx/conf/nginx.conf

#在 http { ... } 配置块中新增一行参数:

    # 新增一行内容,隐藏版本号
    server_tokens off;

    # ... 其余原有配置保持不变

#重载 Nginx 使配置生效
[root@web1 ~]# /usr/local/nginx/sbin/nginx -s reload

在控制主机访问验证:

[root@zop ~]# curl -I http://192.168.8.11
HTTP/1.1 200 OK
Server: nginx
#没有输出版本号,设置成功
2)修改 WordPress 默认数据库前缀

默认前缀 wp_ 是批量扫描攻击的默认目标。一期初始化阶段修改成本最低,推荐在安装 WordPress 前配置,但是我们已经安装完毕,所以这里给出两种方法:

场景 A:全新安装 WordPress 前修改
此场景适用于还没有在web站点完成初始化安装的场景

进入 WordPress 代码目录,复制配置模板:

[root@web1 ~]# cd /usr/local/nginx/html
#注意重命名的名称一定要是wp-config.php,因为安装完毕会自动生成wp-config.php文件
[root@web1 html]# cp wp-config-sample.php wp-config.php
[root@web1 html]# vim wp-config.php

接下来要找到找到 $table_prefix 行(建议直接使用cat -n | grep table_prefix 快速锁定配置位置)

#修改为自定义前缀(建议用字母 + 下划线,比如 wt_、yc_,保留结尾下划线):
$table_prefix = 'wt_';

场景 B:已完成 WordPress 安装后修改

先备份数据库,防止操作失误:

mysqldump -uroot wordpress > /root/wordpress_backup.sql

批量修改数据库表名:

-- 登录数据库执行批量修改命令(把 wt_ 替换成你的自定义前缀)

USE wordpress;
RENAME table wp_commentmeta TO wt_commentmeta;
RENAME table wp_comments TO wt_comments;
RENAME table wp_links TO wt_links;
RENAME table wp_options TO wt_options;
RENAME table wp_postmeta TO wt_postmeta;
RENAME table wp_posts TO wt_posts;
RENAME table wp_termmeta TO wt_termmeta;
RENAME table wp_terms TO wt_terms;
RENAME table wp_term_relationships TO wt_term_relationships;
RENAME table wp_term_taxonomy TO wt_term_taxonomy;
RENAME table wp_usermeta TO wt_usermeta;
RENAME table wp_users TO wt_users;

然后修改 /usr/local/nginx/html/wp-config.php 中的前缀配置(使用之前的定位方式快速锁定$table_prefix 所在位置):

$table_prefix = 'wt_';

接下来修复选项表和用户元表中的旧前缀数据:

UPDATE wt_options SET option_name = 'wt_user_roles' WHERE option_name = 'wp_user_roles';
UPDATE wt_usermeta SET meta_key = 'wt_capabilities' WHERE meta_key = 'wp_capabilities';
UPDATE wt_usermeta SET meta_key = 'wt_user_level' WHERE meta_key = 'wp_user_level';

验证方法:

--登录数据库查看表名
SHOW TABLES FROM wordpress;
3)禁用 Root 远程 SSH 登录(可选)

禁用 Root 远程 SSH 登录可能会对远程连接操作虚拟机造成影响,因此该操作可以选择在项目后期进行配置

先创建管理员普通用户(必须第一步执行):

#创建用户ops
[root@web1 html]# useradd ops
#设置密码
[root@web1 html]# echo 123456 | passwd --stdin ops
# 赋予 sudo 免密权限
[root@web1 html]# echo "ops ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

修改ssh服务配置文件:

[root@web1 html]# vim /etc/ssh/sshd_config
#不要照抄,具体行号可能会有差异
#禁用root远程登陆
43 PermitRootLogin no
#禁用密码登录,可选,搭配免密登录安全性更高
70 PasswordAuthentication no

#重启 SSH 服务生效
[root@web1 html]# systemctl restart sshd

验证:
新开一个终端使用root进行远程连接:

请添加图片描述
从安全方面考虑,可以实施防火墙对端口的精准控制。但是从务实的角度来讲,在一期项目进行防火墙控制会妨碍后续项目的开发升级,显著增加沟通 / 排障成本,影响开发效率。

基础安全加固

负载均衡层统一 SSL 卸载(https站点加密)

我们选择在负载均衡层来做https加密。此外,不只是https,后续要加访问限流、IP 黑名单、防暴力破解等安全策略,全部都在负载均衡层统一配置

前置环境要求:
  1. 已搭建负载均衡集群(以 Haproxy 为例,Nginx 反向代理逻辑一致)+ Keepalived 高可用
  2. 后端多台 Web 节点的 80 端口 HTTP 服务已正常运行
  3. 负载均衡服务器防火墙已开放 443 端口
  4. 域名已解析到负载均衡 VIP(虚拟漂移 IP)
步骤1:获取并处理 SSL 证书

Haproxy 要求证书和私钥合并为单个 .pem 文件,这是和 Nginx 配置的核心区别。

首先明确,正常生产环境我们需要购买合法正规的证书和密钥,但是前提是我们拥有一个正规合法的公网可解析的真实域名才可以操作,因此我们暂时使用自签名证书。关于如何申请使用正规证书,详见:

因为我们并没有公网可解析的域名,因此我们使用签名证书

#在主负载均衡节点(haproxy1)创建证书目录:
[root@haproxy1 ~]# mkdir -p /etc/haproxy/certs
#切入对应目录
[root@haproxy1 ~]# cd /etc/haproxy/certs
#生成密钥
[root@haproxy1 certs]# openssl genrsa 2048 > cert.key
#生成证书
[root@haproxy1 certs]# openssl req -new -x509 -key cert.key -days 3650 -out cert.pem

下面这些选项大多可直接回车跳过:

    Country Name (2 letter code) [XX]:CN   # 国家代码,填CN
    State or Province Name []:BJ            # 省份,可留空
    Locality Name []:                        # 城市,可留空
    Organization Name []:                    # 公司/组织名,可留空
    Organizational Unit Name []:             # 部门名,可留空
    Common Name []:www.yuntuwenchuang.com   # 【重点】填你的域名,没有域名填服务器IP
    Email Address []:                        # 邮箱,可留空

因为我们没有公网可用的域名,所以这里要填写VIP。证书的 Common Name(通用名称)必须和用户最终在浏览器里访问的地址完全一致,否则浏览器会判定「证书与访问地址不匹配」,报安全错误

Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:192.168.8.40 #我们的VIP
Email Address []:

处理密钥和证书

#合并证书与私钥为单个 pem 文件:
[root@haproxy1 certs]# cat cert.pem cert.key > yuntu.pem
#设置严格权限,保护私钥安全
[root@haproxy1 certs]# chmod 600 yuntu.pem
步骤2:配置 Haproxy HTTPS 负载均衡
  1. 备份原配置文件
[root@haproxy1 certs]# cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
  1. 编辑配置文件,替换原 80 端口配置
[root@haproxy1 certs]# vim /etc/haproxy/haproxy.cfg
#以下是完整配置文件的内容
# ===================== 全局配置 =====================
global
    log         127.0.0.1 local2 info    # 日志配置,输出到本地syslog
    chroot      /var/lib/haproxy           # 安全沙箱目录
    pidfile     /var/run/haproxy.pid       # 进程PID文件
    maxconn     4000                        # 全局最大并发连接数
    user        haproxy                     # 运行用户
    group       haproxy                     # 运行用户组
    daemon                                   # 后台守护进程运行
    stats socket /var/lib/haproxy/stats     # 状态监控socket

# ===================== 默认配置 =====================
defaults
    mode                    http              # 默认工作在7层HTTP模式
    log                     global            # 继承全局日志配置
    option                  httplog           # 记录详细HTTP日志
    option                  dontlognull       # 不记录空连接日志
    option                  http-server-close # 服务端主动关闭连接
    option                  forwardfor except 127.0.0.0/8  # 传递真实IP
    option                  redispatch        # 节点故障时自动重定向到健康节点
    retries                 3                 # 请求失败重试次数
    timeout http-request    10s               # HTTP请求超时时间
    timeout queue           1m                # 队列等待超时
    timeout connect         10s               # 连接后端节点超时
    timeout client          1m                # 客户端空闲超时
    timeout server          1m                # 后端服务响应超时
    timeout http-keep-alive 10s               # 长连接保持时间
    timeout check           10s               # 健康检查超时
    maxconn                 3000              # 单前端最大并发数

# ===================== 80端口:HTTP强制跳转HTTPS =====================
frontend http_front
    bind *:80                                  # 监听所有网卡的80端口
    mode http
    # 非HTTPS请求,全部301永久重定向到HTTPS地址
    redirect scheme https code 301 if !{ ssl_fc }

# ===================== 443端口:HTTPS SSL卸载 =====================
frontend https_front
    bind *:443 ssl crt /etc/haproxy/certs/yuntu.pem  # 监听443端口,加载证书
    mode http

    # 1. 传递用户真实IP给后端Web节点
    option forwardfor
    # 2. 告诉后端Web:原始请求是HTTPS协议(解决WordPress重定向循环核心)
    http-request set-header X-Forwarded-Proto https
    # 3. 传递原始Host头,避免WordPress生成错误的站点链接。注意,若为2.0之前的低版本haproxy会报错,本身对项目性能影响不大,可选择屏蔽
    #http-request set-header Host %[host]  

    # 默认转发到后端Web服务器池
    default_backend web_pool

# ===================== 后端Web节点池 =====================
backend web_pool
    mode http
    balance roundrobin                          # 轮询分发请求

    # 后端Web节点配置,开启健康检查
    # inter 2000:每2秒检查一次节点状态
    # rise 2:连续2次检查成功,判定节点为可用
    # fall 5:连续5次检查失败,判定节点为不可用,自动摘除
    server web1 192.168.8.11:80 check inter 2000 rise 2 fall 5
    server web2 192.168.8.12:80 check inter 2000 rise 2 fall 5
    server web3 192.168.8.13:80 check inter 2000 rise 2 fall 5

需注意:
1.配置里的 /etc/haproxy/certs/yuntu.pem 要改成你实际的证书文件路径,确保这个文件是合并了证书和私钥的 pem 格式,且文件权限设置为 600
2.192.168.8.11/12/13,改成你实际的内网 IP 即可,端口保持 80(后端走内网 HTTP)
3.监听所有网卡的原因:用 bind *:80 和 bind *:443 而不是写死 IP,是为了适配 Keepalived 的 VIP 漂移 ——VIP 飘到哪台 Haproxy 节点,哪台节点就能直接接管请求,不用修改配置

步骤3:校验配置并重启 Haproxy
  1. 语法校验,确认配置无误
[root@haproxy1 certs]# haproxy -c -f /etc/haproxy/haproxy.cfg

可能会出现:
请添加图片描述

该警告不影响后续功能配置

  1. 重启服务生效
[root@haproxy1 certs]# systemctl restart haproxy
  1. 验证 443 端口监听
# 同时看到80和443端口即为成功
[root@haproxy1 certs]# ss -nutlp | grep haproxy

请添加图片描述

步骤4:haproxy备主机同步配置
#同步证书目录到备节点
[root@haproxy1 certs]# scp -r /etc/haproxy/certs root@192.168.8.6:/etc/haproxy/
#同步 Haproxy 配置文件到备节点
[root@haproxy1 certs]# scp /etc/haproxy/haproxy.cfg root@192.168.8.6:/etc/haproxy/
#重启 Haproxy 服务生效
[root@haproxy2 ~]# systemctl restart haproxy
#验证 80 和 443 端口都在监听
[root@haproxy2 ~]# ss -nutlp | grep haproxy
步骤5:后端 WordPress 业务适配(必做)

这里给出两种方式:修改wordpress/修改后端nginx。修改wordpress代码,只需修改一个文件即可;修改后端nginx,配置简单但是需要每台主机都进行配置

为什么必须适配?

HTTPS 在负载均衡层解密后,转发到后端 Web 的是普通 HTTP 请求,WordPress 不知道前端是 HTTPS,会出现两个经典问题:

  1. 重定向循环:WordPress 认为是 HTTP 请求,自动跳转到 HTTPS → 跳转后还是被负载均衡转成 HTTP 到后端 → 无限循环
  2. 混合内容报错:页面里的图片、CSS、JS 链接还是 HTTP 开头,浏览器会拦截这些不安全的资源,导致页面样式错乱

注意:不是加了 HTTPS 就一定要做适配,而是「SSL 卸载架构 + 动态业务系统」的组合才需要,而这恰恰是企业生产环境的主流架构。
我们的 WordPress 属于典型的动态 CMS,是标准的需要适配的场景。

适配方式一:修改 WordPress 代码

因为 Web 节点用了 NFS 共享存储,只需修改一次 wp-config.php 即可全节点生效:

定位到我们的wordpress项目目录(nfs1主机):

#切入项目目录
[root@nfs2 ~]# cd /nfs_share 
#修改配置前先备份
[root@nfs1 nfs_share]# cp wp-config.php wp-config.php.bak
#编辑 wp-config.php,添加 HTTPS 适配代码
[root@nfs1 nfs_share]# vim /nfs_share/wp-config.php

用 vim 编辑配置文件,必须把代码添加在文件最顶部的<?php标签下方,放在原有数据库配置的前面

<?php
// ====== HTTPS 反向代理适配 - 开始 ======
// 读取负载均衡传过来的X-Forwarded-Proto头
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
    // 告诉WordPress当前是HTTPS环境,解决重定向循环
    $_SERVER['HTTPS'] = 'on';
    // 修正端口识别,避免生成带端口的错误链接
    $_SERVER['SERVER_PORT'] = 443;
}

// 强制全站域名使用HTTPS,解决混合内容问题
// 优先级高于数据库里的配置,修改配置文件比改数据库更安全
define('WP_HOME', 'https://192.168.4.50');
define('WP_SITEURL', 'https://192.168.4.50'); 
// 如果配置了可用可解析的域名,上面配置中的ip地址改成域名即可
// ====== HTTPS 反向代理适配 - 结束 ======

// 下面是原有的数据库配置等内容,保持不变

不要照抄,代码里的https://192.168.4.50是实际的 HTTPS 访问地址(即 Keepalived VIP 地址),需注意

适配方式二:后端 Nginx配置

如果你不想修改 WordPress 代码,也可以在每台 Web 节点的 Nginx 配置里,通过 FastCGI 参数传递 HTTPS 状态,效果完全一致,更偏向服务端配置。
在 Nginx 站点配置的 PHP 处理段添加一行:

location ~ \.php$ {
    root           html;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    include        fastcgi.conf;
    # 新增这一行:根据X-Forwarded-Proto头自动设置HTTPS状态
    fastcgi_param HTTPS $http_x_forwarded_proto if_not_empty;
}

修改后重载 Nginx 生效:

/usr/local/nginx/sbin/nginx -t
/usr/local/nginx/sbin/nginx -s reload

说明:两种方案选一种即可,不需要同时配置。推荐用 wp-config.php 的方式,更贴合 WordPress 生态,且共享存储只改一次

可选:防火墙放行端口

使用 iptables 放行端口需要在两台 Haproxy 节点(主 + 备)上同步配置,保证 VIP 漂移到任意节点时,访问端口都能正常通信

需要放行的核心端口 / 协议:
TCP 80 端口:接收 HTTP 请求,用于强制跳转到 HTTPS;
TCP 443 端口:接收 HTTPS 加密请求,是 HTTPS 服务的核心端口;
VRRP 协议(协议号 112):Keepalived 主备节点的心跳通信协议,用于 VIP 漂移,高可用架构必须放行。

首先需要先关闭并禁用 firewalld,避免和 iptables 规则冲突

# 停止并禁用firewalld
systemctl stop firewalld
systemctl disable firewalld

# 安装iptables服务组件(如已安装可跳过)
yum install -y iptables-services

# 启动并设置iptables开机自启
systemctl start iptables
systemctl enable iptables

添加端口放行规则:
所有规则均添加到 INPUT 链(入站流量控制),使用 -I 参数插入到规则列表开头,避免被前面的全局拒绝规则拦截

#放行 HTTP 80 端口
iptables -I INPUT -p tcp --dport 80 -j ACCEPT
# 放行 HTTPS 443 端口
iptables -I INPUT -p tcp --dport 443 -j ACCEPT
#放行 VRRP 协议(Keepalived 高可用必需)
iptables -I INPUT -p vrrp -j ACCEPT

验证规则是否添加成功:

iptables -L INPUT -n --line-numbers
#输出以下信息即为成功
num  target     prot opt source               destination
1    ACCEPT     vrrp --  0.0.0.0/0            0.0.0.0/0
2    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:443
3    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80

需注意,iptables 的规则默认是临时生效的,服务器重启或 iptables 服务重启后规则会丢失,若想要长期有效或者开机自启用,必须手动保存到配置文件

同步配置到备节点

高可用架构要求两台 Haproxy 节点的防火墙规则完全一致,VIP 漂移后备节点才能正常提供服务。

快速同步方式:

直接把主节点的 iptables 配置文件同步到备节点:

# 把配置文件同步到备节点(替换为备节点的物理IP)
scp /etc/sysconfig/iptables root@192.168.8.6:/etc/sysconfig/
#同步完成后,在备节点上重载 iptables 规则并验证:
systemctl reload iptables
# 验证规则是否生效
iptables -L INPUT -n --line-numbers


性能优化

同样的,部分性能优化项目完全可以贯穿整个项目,而有的优化项需要项目进行到一定阶段才能进行。

基础性能优化

以下五项优化可以贯穿整个项目的全生命周期,属于 LNMP 架构下的基础盘性能优化,和上层业务架构(单机 / 数据库解耦 / 负载均衡 / 高可用集群)的解耦度极高,是典型的一次搭建框架,全周期迭代复用的优化项,完全可以加入我们的ROLE之中,方便后续进行批量部署lnmp时直接进行配置,详见:# Linux实战笔记:WordPress文创项目五项优化结合Ansible ROLE(新增web Gzip优化)

1) Nginx 进程与连接数优化

worker_processes 控制工作进程数,建议与 CPU 核心数一致;搭配 worker_connections 调整单进程并发连接数,两者共同决定 Nginx 最大并发承载能力。一期低流量场景下,优化后可减少进程调度开销,连接数预留充足余量

[root@web1 ~]# vim /usr/local/nginx/conf/nginx.conf

# 全局块:工作进程数,auto 自动匹配CPU核心数,一期虚拟机推荐直接用 auto
worker_processes  auto;

# 优化补充:绑定CPU核心,减少上下文切换(可选,2核以上生效)
# worker_cpu_affinity auto;

events {
    # 单进程最大连接数,一期设为1024完全够用,后续集群可调大到2048
    worker_connections  1024;
    # 开启高效复用连接
    use epoll;
    # 允许一次接受多个连接
    multi_accept on;
}

#重载生效
[root@web1 ~]# /usr/local/nginx/sbin/nginx -s reload

验证方法:

# 查看Nginx工作进程数,与CPU核心数一致即为生效

2) PHP-FPM 进程数优化

WordPress 是重型 PHP 程序,PHP-FPM 是动态请求的性能瓶颈。默认配置通常偏保守。按服务器内存合理调整进程数,可避免进程频繁创建销毁,同时防止内存溢出。

单 PHP-FPM 进程常驻内存约 20~40MB(WordPress 场景)
计算公式:pm.max_children = 服务器可用内存 / 单进程内存(预留 30% 内存给系统、Nginx、数据库)

; 进程管理模式,dynamic动态模式适合流量波动场景
104 pm = dynamic

; 最大进程数,2G内存建议设20,4G设40
115 pm.max_children = 20

; 启动时初始进程数
120 pm.start_servers = 5

; 空闲最小进程数
125 pm.min_spare_servers = 2

; 空闲最大进程数
135 pm.max_spare_servers = 8

; 单个进程处理多少请求后自动重启,防止内存泄漏,一期设1000足够
141 pm.max_requests = 1000
3)开启 PHP OPcache 字节码加速

OPcache简介:OPcache 是 PHP 官方内置的字节码缓存扩展,大幅减少 PHP 重复编译脚本的 CPU 开销,提升网站并发、降低响应耗时,是生产环境必开优化

将 PHP 脚本编译后的字节码缓存到共享内存中,后续相同请求无需重复解析编译,WordPress 场景下可降低PHP 的执行耗时,是 PHP 优化中投入产出比最高的一项

#下载OPcache扩展
[root@web1 ~]# dnf -y install php-opcache
#编辑 PHP 主配置文件
[root@web1 ~]# vim /etc/php.ini 
#直接在配置文件末尾添加以下配置

[opcache]
; 开启OPcache
opcache.enable = 1

; 开启CLI模式缓存(命令行脚本也生效,可选)
opcache.enable_cli = 1

; 共享内存大小,单位MB,一期设128完全够用,站点大可设256
opcache.memory_consumption = 128

; 最大缓存脚本数量,WordPress约有上千个文件,设10000足够
opcache.max_accelerated_files = 10000

; 多久检查一次脚本是否更新,单位秒
; 开发调试期设为60,上线稳定后可设为3600(1小时)
opcache.revalidate_freq = 60

; 开启快速关闭,提升释放速度
opcache.fast_shutdown = 1

; 保存注释,兼容依赖注释的WordPress插件/主题
opcache.save_comments = 1
#重启服务:
[root@web1 ~]# systemctl restart php-fpm

验证:
在站点根目录创建 opcache.php:

<?php
phpinfo();

访问 http://192.168.8.11/opcache.php,按下ctrl+f搜索Opcode Caching,为Up and running即为成功:

请添加图片描述

开发期提示:如果频繁修改 PHP 代码,可临时将 opcache.revalidate_freq 设为 0(每次请求都检查更新),调试完成后再调大数值

4)配置 Nginx 浏览器静态资源缓存

通过 Nginx 给图片、CSS、JS、字体等静态资源添加缓存响应头,让用户浏览器本地缓存这些文件,二次访问时直接从本地读取,既提升页面加载速度,又降低服务器带宽和 IO 消耗

编辑 Nginx 配置文件,在 server 配置块内添加静态资源匹配规则

[root@web1 ~]# vim /usr/local/nginx/conf/nginx.conf
#在 server 块中(PHP 动态页面规则之前)加入以下配置

    # 静态资源缓存规则
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|eot|svg)$ {
        # 缓存7天,上线稳定后可改为30d
        expires 7d;
        # 缓存状态码
        add_header Cache-Control "public, no-transform";
        # 关闭日志,减少IO
        access_log off;
    }
#重载nginx
[root@web1 ~]# /usr/local/nginx/sbin/nginx -s reload

验证:
用 curl 查看静态资源的响应头,确认出现缓存相关字段

[root@web1 ~]# curl -I http://192.168.8.11/wp-includes/css/dashicons.min.css
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 01 Jul 2026 01:56:04 GMT
Content-Type: text/css
Content-Length: 59004
Last-Modified: Tue, 23 Jun 2026 01:18:37 GMT
Connection: keep-alive
ETag: "6a39deed-e67c"
Expires: Wed, 08 Jul 2026 01:56:04 GMT
Cache-Control: max-age=604800
Cache-Control: public, no-transform
Accept-Ranges: bytes

输出中包含 Expires、Cache-Control: max-age即为生效

5)全局 Gzip 资源压缩优化

配置写在 Nginx 主配置文件的 http 块中,全局生效,所有站点都能复用:

[root@web1 ~]# /usr/local/nginx/conf/nginx.conf  
#http块内新增
http {
    # ... 原有其他配置 ...

    # 开启Gzip压缩
    gzip on;
    # 压缩级别:1-9,数字越大压缩率越高、CPU消耗越大,推荐6(性价比最高)
    gzip_comp_level 6;
    # 最小压缩文件:小于1k的文件压缩收益极低,跳过
    gzip_min_length 1k;
    # 压缩缓冲区设置
    gzip_buffers 4 16k;
    # 兼容HTTP协议版本
    gzip_http_version 1.1;
    # 添加Vary响应头,适配CDN/代理缓存
    gzip_vary on;
    # 需要压缩的MIME类型(text/html默认自动压缩,无需单独写)
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml
        application/xml+rss
        image/svg+xml;
    # 禁用IE6及以下的Gzip兼容(老IE对Gzip支持有bug)
    gzip_disable "MSIE [1-6]\.";
}

# 配置语法校验
[root@web1 ~]# /usr/local/nginx/sbin/nginx -t
# 重载服务
[root@web1 ~]# /usr/local/nginx/sbin/nginx -s reload

验证压缩生效:
在客户端执行 curl 命令,查看响应头是否包含 Content-Encoding: gzip:

[root@web1 ~]# curl -I -H "Accept-Encoding: gzip, deflate" http://192.168.8.11/wp-includes/css/dashicons.min.css
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 06 Jul 2026 03:30:34 GMT
Content-Type: text/css
Last-Modified: Tue, 23 Jun 2026 01:18:37 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: W/"6a39deed-e67c"
Expires: Mon, 13 Jul 2026 03:30:34 GMT
Cache-Control: max-age=604800
Cache-Control: public, no-transform
Content-Encoding: gzip   # 压缩生效标识

其余三台主机都需要进行相同配置,直接scp即可

[root@web1 ~]# scp /usr/local/nginx/conf/nginx.conf root@192.168.8.12:/usr/local/nginx/conf/nginx.conf
[root@web1 ~]# scp /usr/local/nginx/conf/nginx.conf root@192.168.8.13:/usr/local/nginx/conf/nginx.conf

进阶性能优化

1)数据库读写分离

结合我们的项目架构演进路径(单机→数据库解耦→负载均衡→共享存储→高可用)和流量增长场景,数据库读写分离是当前阶段最核心、最优先落地的进阶优化方向。
当前项目已完成数据库独立部署,但单库仍会面临 “读请求占比高(WordPress 场景下查询占比超 80%)、写请求锁表、高峰期查询超时” 等问题,读写分离能精准拆解数据库压力,完全适配我们的业务场景。

主机划分:

我们将采用MaxScale代理来实现数据库的读写分离,将haproxy2充当MaxScale的服务器。因为haproxy2是备主机,日常性能占用极低(但实际生产中,仍建议购置一台低性能服务器来部署MaxScale代理)
将haproxy2主机(192.168.8.6)重命名为haproxy2max用来标识

max部署

需要提前下载安装包:maxscale-24.02.1-1.rhel.8.x86_64.rpm,可点击此处前往官网下载

#提前将安装包上传到haproxy2max主机的/root目录下
[root@haproxy2max ~]# dnf -y localinstall maxscale-24.02.1-1.rhel.8.x86_64.rpm 
#备份并修改核心配置文件
[root@haproxy2max ~]# cp /etc/maxscale.cnf  /etc/maxscale.cnf.bak
[root@haproxy2max ~]# vim /etc/maxscale.cnf

配置文件分段说明:
(需要修改配置的部分都加了注释)

...
 12 [maxscale]
 13 threads=auto
...
#指定要代理的数据库服务器,[server2]部分需要自己手工定义
[server1]
type=server
address=192.168.8.30     #指定主服务器地址
port=3306
[server2]
type=server
address=192.168.8.42     #指定从服务器地址
port=3306
...
#指定监控用户maxscalemon,用于登录后端服务器,检查服务器的运行状态和主从状态
 47 [MariaDB-Monitor]
 48 type=monitor
 49 module=mariadbmon
 50 servers=server1,server2                 #上边的定义的主机
 51 user=maxscalemon                        #指定监控用户
 52 password=123qqq...A        ·             #指定监控用户的密码
 53 monitor_interval=2s
 ...
 86 #[Read-Only-Service]                    #只读服务不需要,这段全部注释
 87 #type=service
 88 #router=readconnroute
 89 #servers=server1
 90 #user=service_user
 91 #password=service_pw
 92 #router_options=slave
...
#定义读写分离服务器配置
 99 [Read-Write-Service]
100 type=service
101 router=readwritesplit
102 servers=server1,server2             #指定读写分离服务器  
103 user=maxscalerouter                  #指定路由用户
104 password=123qqq...A                 #指定路由用户密码           

...
#只读服务配置信息加上注释
118 #[Read-Only-Listener]
119 #type=listener
120 #service=Read-Only-Service
121 #protocol=mariadbprotocol
122 #port=4008
 ...
#读写分离配置信息,默认端口号为4006
124 [Read-Write-Listener]
125 type=listener
126 service=Read-Write-Service
127 protocol=mariadbprotocol
128 port=4006

这里我们配置了两个用户:
监控用户(maxscalemon):后台定时巡检所有后端数据库,检测节点是否存活、主从角色、同步是否正常,给读写路由提供状态判断依据,不处理业务 SQL
路由用户(maxscalerouter):代理业务客户端转发所有业务 SQL,将写请求路由到主库、读请求分发到从库,实际执行数据增删改查操作

数据库用户配置(database主机配置)

后端主、从库创建两类专用用户
根据/etc/maxscale.cnf配置要求,需要在master主机和slave主机授权用户

  • maxscalemon用户,密码为123qqq…A
    • 创建监控用户maxscalemon,用于登录后端服务器,检查服务器的状态
  • maxscalerouter用户,密码为123qqq…A
    • 创建路由用户maxscalerouter,检测客户端的用户名和密码在后端数据库中是否存在

REPLICATION SLAVE:该权限能够同步数据,查看从服务器上slave的状态;
REPLICATION CLIENT:该权限可以获取数据库服务的状态(数据库服务是否允许,主从是否正常,服务器是否存活)

监控用户:maxscalemon(监控账号)

权限需求:REPLICATION SLAVEREPLICATION CLIENT,用于检测主从同步状态、服务在线状态
在Master主机(即database主机)执行。(因为之前做过主从同步,从库会自动同步账号,因此无需在从库重复操作)

MariaDB [(none)]> CREATE USER 'maxscalemon'@'%' IDENTIFIED BY '123qqq...A';
MariaDB [(none)]> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'maxscalemon'@'%';

路由用户:maxscalerouter(路由校验账号)
权限需求:仅需要查询系统库,校验客户端账号密码是否存在

MariaDB [(none)]> CREATE USER 'maxscalerouter'@'%' IDENTIFIED BY '123qqq...A';
MariaDB [(none)]> GRANT SELECT ON mysql.* TO 'maxscalerouter'@'%';
--刷新授权表
MariaDB [(none)]> FLUSH PRIVILEGES;

启动MaxScale服务

[root@haproxy2max ~]# systemctl restart maxscale
[root@haproxy2max ~]# systemctl enable maxscale
[root@haproxy2max ~]# ss -ntulp | grep 4006

读写分离功能测试

在database主机先创建访问用户:

MariaDB [(none)]> CREATE USER 'sam'@'%' IDENTIFIED BY '123qqq...A';
MariaDB [(none)]> GRANT ALL ON *.* TO 'sam'@'%';

haproxy2max充当客户端访问读写分离服务器

[root@haproxy2max ~]# dnf -y install mariadb
#-h后跟本机地址
[root@haproxy2max ~]# mysql -h192.168.8.6 -P 4006 -usam -p"123qqq...A"
#写入数据
MariaDB [(none)]> create database ababccc;

回到database主机查看验证是否写入:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| aaa                |
| ababccc            |
| information_schema |
| mysql              |
| performance_schema |
| wordpress          |
+--------------------+

在nfs2(从数据库)主机查看是否写入:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| aaa                |
| ababccc            |
| information_schema |
| mysql              |
| performance_schema |
| wordpress          |
+--------------------+

可以推断出,写入数据走的肯定是database主机,只有这样才会同步到从数据库,如果在从数据库写入数据是无法同步到主数据库的。

读操作分流验证(核心读写分离效果)

接下来在从数据库写入数据来验证:

MariaDB [(none)]> create database aaaaaaaaaaa;

在主数据库是看不到从数据库添加的数据的:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| aaa                |
| ababccc            |
| information_schema |
| mysql              |
| performance_schema |
| wordpress          |
+--------------------+

回到我们的客户主机(haproxy2max主机)进行查看:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| aaa                |
| aaaaaaaaaaa        |
| ababccc            |
| information_schema |
| mysql              |
| performance_schema |
| wordpress          |
+--------------------+

客户端可以查看到从数据库添加的数据库。由此推断出,我们读取数据查看的是从数据库的数据。
自此,数据库读写分离完成

2)自定义404报错页面
  • WordPress 站点推荐采用 「动态 + 静态」双适配方案,兼顾用户体验和性能:
    • 动态页面 404:由 WordPress 主题的 404 模板处理,风格和站点统一,可加搜索框、热门推荐,提升用户留存;
    • 静态资源 404:由 Nginx 直接返回静态 404 页面,不经过 PHP 处理,减少性能消耗。

站点用了 NFS 共享存储,404 页面文件只需上传一次,所有 Web 节点自动同步

步骤一:编写报错页面的文件

/nfs_share/wp-content/themes/wr404/404.php

<?php get_header(); ?>
<div class="error-404">
    <h1>页面走丢了 | 404 Not Found</h1>
    <p>抱歉,您访问的页面不存在,可能已被删除或链接有误。</p>
    <div class="404-actions">
        <a href="<?php echo home_url(); ?>" class="btn">返回首页</a>
        <?php get_search_form(); ?> <!-- 插入搜索框 -->
    </div>
    <div class="hot-recommend">
        <h3>热门文创推荐</h3>
        <?php
        // 调用5篇热门文章
        $args = array('posts_per_page' => 5, 'orderby' => 'comment_count');
        $query = new WP_Query($args);
        while($query->have_posts()) : $query->the_post();
        ?>
            <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
        <?php endwhile; wp_reset_postdata(); ?>
    </div>
</div>
<?php get_footer(); ?>

/nfs_share/404-static.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>404 资源不存在</title>
    <style>
        body { font-family: "Microsoft Yahei", sans-serif; text-align: center; padding: 100px; }
        h1 { font-size: 48px; color: #333; }
        p { font-size: 18px; color: #666; }
        a { color: #0066cc; text-decoration: none; }
    </style>
</head>
<body>
    <h1>404</h1>
    <p>您访问的资源不存在</p>
    <a href="/">返回首页</a>
</body>
</html>
步骤二:Nginx 配置 404 规则

在 Nginx 站点配置的 server 块中新增以下规则:

server {
        listen       80;
        server_name  localhost;
        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        # 静态资源缓存规则
        location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|eot|svg|html|htm)$ {
        # 缓存7天,上线稳定后可改为30d
            expires 7d;
        # 缓存状态码
            add_header Cache-Control "public, no-transform";
        # 关闭日志,减少IO
            access_log off;
            try_files $uri =404;
        # 静态资源不存在时,返回专属静态404
            error_page 404 /404-static.html;
        }
        
# 静态404页面:仅允许内部跳转访问
location = /404-static.html {
            internal;
        }

        location / {
        #
            try_files $uri $uri/ /index.php?$args;
        }
      # redirect server error pages to the static page /50x.html
        # 服务器错误页面
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        error_page 404 /index.php;

注意,三台web主机的nginx都需要进行相同配置。可以直接使用scp进行拷贝覆盖

[root@web1 ~]# scp /usr/local/nginx/conf/nginx.conf root@192.168.8.12:/usr/local/nginx/conf/nginx.conf
[root@web1 ~]# scp /usr/local/nginx/conf/nginx.conf root@192.168.8.13:/usr/local/nginx/conf/nginx.conf
步骤三:Wordpress站点设置

WordPress 还在使用默认的「朴素」固定链接模式,没有开启路径式的伪静态。需要按下面步骤操作:

  1. 进入 WordPress 后台
    访问 https://192.168.4.50/wp-admin,登录管理员账号

  2. 修改固定链接设置

  • 左侧菜单找到 设置 → 固定链接:
    • 默认选中的是「朴素」模式(网址带 ?p=123 这种参数形式)
    • 改成 文章名(或者其他任意非朴素的模式,比如日期、数字型都可以)
    • 拉到页面底部,点击 保存更改
      请添加图片描述
步骤四:验证最终效果

访问 https://192.168.4.50/abcdefg:
请添加图片描述
页面显示 WordPress 主题自带的 404 页面(和网站风格统一,带导航、页脚,一般会有「页面未找到」「搜索」等内容)

访问 https://192.168.4.50/notexist.jpg,会显示我们自定义的简洁静态 404 页面
请添加图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值