乐于分享
好东西不私藏

企业级WordpPress服务集群部署文档(基于K3s、MySQL、NFS、Keepalived+Nginx)

企业级WordpPress服务集群部署文档(基于K3s、MySQL、NFS、Keepalived+Nginx)

一、项目概述

本项目构建高可用Web服务集群,整合K3s容器编排、MySQL主从、NFS存储、Keepalived+Nginx负载均衡,实现从流量接入到数据持久化的全链路冗余与自动化管理。架构分层如下:
接入层:Keepalived+Nginx(VIP漂移,双机热备)
应用层:K3s集群(1 Master+2 Agent,部署WordPress)
数据层:MySQL主从(数据持久化)
管理层:Ansible(自动化配置管理)

二、环境准备

2.1 主机规划(IP与角色)

角色分区

主机名

管理/内网IP (eth0)

业务/外网IP (eth1)

关键软件/功能

接入层(VIP)

Cluster VIP

192.168.183.100

虚拟入口,高可用漂移

接入层(LB)

LB-01(Master)

192.168.111.173

192.168.183.133

Nginx, Keepalived(主)

接入层(LB)

LB-02(Backup)

192.168.111.175

192.168.183.134

Nginx, Keepalived(备)

应用层(Web)

K3s-Server

192.168.111.176

K3s Master, Pods, NodePort

应用层(Web)

K3s-Agent1

192.168.111.180

K3s Agent

应用层(Web)

K3s-Agent2

192.168.111.181

K3s Agent

数据层(DB)

MySQL-Master

192.168.111.177

MySQL(主)

数据层(DB)

MySQL-Slave

192.168.111.178

MySQL(从)

管理层(Mgmt)

Ansible-Node

192.168.111.179

Ansible, SSH控制端

三、Ansible初始化与环境配置

3.1 安装Ansible

在Ansible-Node节点执行:
pip install pipxpipx install --include-deps ansible
验证版本:
ansible --version

输出示例:ansible [core 2.20.1],Python 3.12.12,Jinja 3.1.6

3.2 配置SSH免密登录

生成密钥并分发至所有节点:
ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsafor ip in 173 175 176 177 178 180 181; dossh-copy-id root@192.168.111.$ipdone

3.3 创建Ansible项目结构

mkdir -p my-project/{roles,group_vars}cd my-projectmkdir -p roles/{common,keepalived_nginx,mysql,web}/{tasks,handlers,templates}

3.4 主机清单(hosts.yml)

all:  vars:    ansible_user: root  children:    lb:      hosts:        lb01: { ansible_host: 192.168.111.173 }        lb02: { ansible_host: 192.168.111.175 }    web:      hosts:        k3s_server: { ansible_host: 192.168.111.176 }        k3s_agent1: { ansible_host: 192.168.111.180 }        k3s_agent2: { ansible_host: 192.168.111.181 }    db:      hosts:        mysql_master: { ansible_host: 192.168.111.177 }        mysql_slave: { ansible_host: 192.168.111.178 }

3.5 主机连通性测试

ansible all -i hosts.yml -a 'whoami'

预期输出:所有节点返回root

3.6 基础初始化(common角色)

编辑roles/common/tasks/main.yml:
- name: 安装基础软件  ansible.builtin.package:    name: [vim, tree, net-tools, tmux]    state: present    update_cache: yes- name: 统一时区  community.general.timezone:    name: Asia/Shanghai- name: 关闭SELinux  ansible.posix.selinux:    state: disabled
执行初始化Playbook(site.yml):
- name: ProjectX  hosts: all  become: true  gather_facts: yes  roles: [common]
运行:
ansible-playbook site.yml -i hosts.yml

四、MySQL主从部署

4.1 手动安装MySQL(本地RPM包)

在MySQL节点下载并安装MySQL 8.4.7:https://dev.mysql.com/downloads/mysql/

下载官方bundle包并解压

tar -xvf mysql-8.4.7-1.el10.x86_64.rpm-bundle.tar

移除冲突依赖

sudo dnf remove mariadb-libs mariadb-connector-c -y

本地安装

sudo dnf localinstall mysql-community-*.rpm

启动并设置开机自启

sudo systemctl start mysqld && sudo systemctl enable mysqld

4.2 数据库初始化

放行3306端口:
firewall-cmd --add-port=3306/tcp --permanentfirewall-cmd --reload
重置root密码(获取临时密码):
grep 'temporary password' /var/log/mysqld.logmysql -u root -p

输入临时密码后执行

ALTER USER 'root'@'localhost' IDENTIFIED BY 'Admin_123!';FLUSH PRIVILEGES;允许root远程登录:USE mysql;UPDATE user SET host='%' WHERE user='root';FLUSH PRIVILEGES;修改监听地址(/etc/my.cnf):bind-address=0.0.0.0

4.3 主从复制配置

Master节点(192.168.111.177)
/etc/my.cnf配置:
[mysqld]bind-address=0.0.0.0server-id=1log_bin=mysql-binbinlog_format=ROWbinlog_expire_logs_seconds=604800gtid_mode=ONenforce_gtid_consistency=ON
创建同步用户:
CREATE USER 'repl'@'%' IDENTIFIED BY 'Admin_123!';GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';FLUSH PRIVILEGES;
Slave节点(192.168.111.178)
/etc/my.cnf配置:
[mysqld]server-id=2log_bin=mysql-binbinlog_format=ROWbinlog_expire_logs_seconds=604800gtid_mode=ONenforce_gtid_consistency=ONread_only=1
启动复制:
STOP REPLICA;CHANGE REPLICATION SOURCE TOSOURCE_HOST='192.168.111.177',SOURCE_USER='repl',SOURCE_PASSWORD='Admin_123!',SOURCE_PORT=3306,SOURCE_AUTO_POSITION=1,SOURCE_SSL=1;START REPLICA;
验证:
SHOW REPLICA STATUS\G(Replica_IO_Running=Yes)

4.4 Ansible管理MySQL配置

hosts.yml添加变量:
all:  vars:    mysql_bind_address: 0.0.0.0  children:    db:      hosts:        mysql_master: { mysql_id: 1, mysql_role: master }        mysql_slave: { mysql_id: 2, mysql_role: slave }
模板roles/mysql/templates/my.cnf.j2:
[mysqld]bind-address={{ mysql_bind_address }}server-id={{ mysql_id }}log_bin=mysql-binbinlog_format=ROWbinlog_expire_logs_seconds=604800gtid_mode=ONenforce_gtid_consistency=ON{% if mysql_role == 'slave' %}read_only=1{% endif %}
Playbook(roles/mysql/tasks/main.yml):
- name: 更新MySQL配置  ansible.builtin.template:    src: my.cnf.j2    dest: /etc/my.cnf  notify: 重启MySQL- name: 确保MySQL运行  ansible.builtin.service:    name: mysqld    state: started    enabled: yes
执行:
ansible-playbook site.yml -i hosts.yml

五、K3s集群部署(离线模式)

5.1 准备离线资源

在有网节点下载:
K3s安装脚本:
curl -sfL https://get.k3s.io > install.sh
二进制与镜像:k3s、k3s-airgap-images-amd64.tar.gz

5.2 K3s Master节点安装(192.168.111.176)

加载镜像

docker load -i k3s-airgap-images-amd64.tar.gz

放置二进制文件

cp k3s /usr/local/bin/ && chmod +x /usr/local/bin/k3s

执行安装

export INSTALL_K3S_SKIP_DOWNLOAD=trueexport INSTALL_K3S_EXEC="--docker"chmod +x install.sh && ./install.sh
验证:(Master状态Ready)
kubectl get nodes

5.3 Agent节点加入(192.168.111.180/181)

放行Master端口:
firewall-cmd --permanent --add-port=6443/tcp --add-port=8472/udp --add-port=10250/tcpfirewall-cmd --permanent --zone=trusted --add-source=10.42.0.0/16firewall-cmd --reload
获取Master Token:cat /var/lib/rancher/k3s/server/node-token
Agent安装:
export INSTALL_K3S_SKIP_DOWNLOAD=trueexport K3S_URL=https://192.168.111.176:6443export K3S_TOKEN=K104123e9155e9ac199e116488262b932f291e1c18c4cf8648fb46deac6d1dc256d::server:a4ef7df6147c3aaf4f79bd070bdefa0dexport INSTALL_K3S_EXEC="--docker"./install.sh agent
验证:kubectl get nodes(Agent状态Ready)

六、WordPress部署(K3s应用)

6.1 准备Docker镜像

在有网节点拉取并导出:
docker pull wordpress:php8.5-apache && docker pull nginx:alpinedocker save -o wordpress-php8.5-apache.tar wordpress:php8.5-apachedocker save -o nginx-alpine.tar nginx:alpine
拷贝至K3s节点并加载:
docker load -i wordpress-php8.5-apache.tardocker load -i nginx-alpine.tar

6.2 NFS存储配置(Ansible-Node)

安装NFS服务:
dnf install -y nfs-utilsmkdir -p /data/k3s/wordpress && chmod 777 /data/k3s/wordpressecho "/data/k3s/wordpress 192.168.111.*(rw,sync,no_root_squash)" >> /etc/exportssystemctl enable --now nfs-server.servicefirewall-cmd --add-service={nfs,mountd,rpc-bind} --permanent && firewall-cmd --reload
K3s节点安装NFS客户端:
dnf -y install nfs-utils

6.3 PV/PVC配置

wordpress-volume.yaml:
apiVersion: v1kind: PersistentVolumemetadata:  name: wordpress-pvspec:  capacity: { storage: 5Gi }  volumeMode: Filesystem  accessModes: [ReadWriteMany]  persistentVolumeReclaimPolicy: Retain  storageClassName: nfs-manual  nfs:    server: 192.168.111.179    path: /data/k3s/wordpress---apiVersion: v1kind: PersistentVolumeClaimmetadata:  name: wordpress-pvcspec:  accessModes: [ReadWriteMany]  storageClassName: nfs-manual  resources: { requests: { storage: 5Gi } }
应用:kubectl apply -f wordpress-volume.yaml

6.4 WordPress部署(Deployment+Service)

ConfigMap与Secret(wp-config.yaml):
apiVersion: v1kind: ConfigMapmetadata:  name: wordpress-confdata:  WORDPRESS_DB_HOST: "192.168.111.177:3306"  WORDPRESS_DB_USER: "root"  WORDPRESS_DB_NAME: "wordpress_db"---apiVersion: v1kind: Secretmetadata:  name: wordpress-secrettype: OpaquestringData:  WORDPRESS_DB_PASSWORD: "Admin_123!"
Deployment(wordpress-deploy.yaml):
apiVersion: apps/v1kind: Deploymentmetadata:  name: wordpress-deployspec:  replicas: 3  selector: { matchLabels: { app: wordpress-deploy } }  template:    metadata: { labels: { app: wordpress-deploy } }    spec:      volumes: [{ name: wordpress-data, persistentVolumeClaim: { claimName: wordpress-pvc } }]      containers:      - name: wordpress        image: wordpress:php8.5-apache        ports: [{ containerPort: 80 }]        env:        - { name: WORDPRESS_DB_HOST, valueFrom: { configMapKeyRef: { name: wordpress-conf, key: WORDPRESS_DB_HOST } } }        - { name: WORDPRESS_DB_USER, valueFrom: { configMapKeyRef: { name: wordpress-conf, key: WORDPRESS_DB_USER } } }        - { name: WORDPRESS_DB_NAME, valueFrom: { configMapKeyRef: { name: wordpress-conf, key: WORDPRESS_DB_NAME } } }        - { name: WORDPRESS_DB_PASSWORD, valueFrom: { secretKeyRef: { name: wordpress-secret, key: WORDPRESS_DB_PASSWORD } } }        volumeMounts: [{ name: wordpress-data, mountPath: /var/www/html }]

Service(NodePort):

apiVersion: v1kind: Servicemetadata:  name: wordpress-servicespec:  type: NodePort  selector: { app: wordpress-deploy }  ports: [{ port: 80, targetPort: 80, nodePort: 30080 }]

应用并放行端口:

kubectl apply -f .&& firewall-cmd --add-port=30080/tcp --permanent && firewall-cmd --reload

6.5 初始化WordPress数据库

CREATE DATABASE wordpress_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

七、Keepalived+Nginx负载均衡(VIP配置)

7.1 Nginx反向代理配置

LB节点安装Nginx:dnf install -y nginx && systemctl enable –now nginx
/etc/nginx/conf.d/default.conf:
upstream my_backend_servers {  server 192.168.111.176:30080;  server 192.168.111.180:30080;  server 192.168.111.181:30080;}server {  listen 80;  server_name localhost;  location / {    proxy_pass http://my_backend_servers;    proxy_connect_timeout 2s;    proxy_next_upstream error timeout http_500 http_502 http_503 http_504;    proxy_set_header Host $host;    proxy_set_header X-Real-IP $remote_addr;    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  }}
重启:systemctl restart nginx

7.2 Keepalived高可用配置

放行VRRP协议:
firewall-cmd --permanent --add-protocol=vrrpfirewall-cmd --permanent --add-rich-rule='rule family="ipv4" destination address="224.0.0.18" protocol value="vrrp" accept'firewall-cmd --reload
Master节点(/etc/keepalived/keepalived.conf):
global_defs { router_id Master }vrrp_script check_nginx { script "killall -0 nginx"; interval 2; weight -20 }vrrp_instance VI_1 {  state MASTER  interface ens224  virtual_router_id 51  priority 100  advert_int 1  authentication { auth_type PASS; auth_pass Admin123 }  virtual_ipaddress { 192.168.183.100 }  track_script { check_nginx }}

Backup节点(差异项):

global_defs { router_id Backup }vrrp_instance VI_1 { state BACKUP; priority 90 }
重启:systemctl restart keepalived

检查配置 LB-01 正常称为:Master

ps:WordPress 的⼀个坑,WordPress 重定向循环(redirect loop

解决⽅法,将 siteurl 和 siteurl 设置为 VIP 就⾏了

USEwordpress_db;UPDATE wp_options SET option_value ='http://192.168.183.100'WHERE option_name ='siteurl';UPDATE wp_options SET option_value ='http://192.168.183.100'WHERE option_name ='siteurl';

八、压力测试与故障切换

8.1 JMeter压力测试

场景1:100线程,10s启动,持续运行 → 响应时间≈3s,无异常
场景2:50线程,10s启动 → 响应时间≈1.5s,轻微过载

8.2 Apache Bench测试

ab -n 1000 -c 100 http://192.168.183.100/
结果摘要:
请求成功率:100%(Failed requests=0)
平均连接时间:1ms(min=0, max=8)
吞吐量:26.09 req/s
90%请求响应时间≤8163ms

8.3 HA故障切换测试

模拟LB-01故障(关闭Keepalived/Nginx),VIP在5秒内漂移至LB-02,服务无中断。

九、总结

本集群通过Ansible实现全链路自动化配置,K3s保障应用弹性伸缩,MySQL主从确保数据安全,Keepalived+Nginx实现接入层高可用,NFS解决存储共享问题。压力测试验证了系统在100并发下的稳定性,故障切换测试证明高可用机制有效,满足企业级Web服务需求。