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

一、项目概述

二、环境准备
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
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: rootchildren: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角色)
- name: 安装基础软件ansible.builtin.package:name: [vim, tree, net-tools, tmux]state: presentupdate_cache: yes- name: 统一时区community.general.timezone:name: Asia/Shanghai- name: 关闭SELinuxansible.posix.selinux:state: disabled
- name: ProjectXhosts: allbecome: truegather_facts: yesroles: [common]
ansible-playbook site.yml -i hosts.yml

四、MySQL主从部署
4.1 手动安装MySQL(本地RPM包)
下载官方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 数据库初始化
firewall-cmd --add-port=3306/tcp --permanentfirewall-cmd --reload
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 主从复制配置
[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;
[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配置
all:vars:mysql_bind_address: 0.0.0.0children:db:hosts:mysql_master: { mysql_id: 1, mysql_role: master }mysql_slave: { mysql_id: 2, mysql_role: slave }
[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 %}
roles/mysql/tasks/main.yml):- name: 更新MySQL配置ansible.builtin.template:src: my.cnf.j2dest: /etc/my.cnfnotify: 重启MySQL- name: 确保MySQL运行ansible.builtin.service:name: mysqldstate: startedenabled: yes
ansible-playbook site.yml -i hosts.yml


五、K3s集群部署(离线模式)
5.1 准备离线资源
curl -sfL https://get.k3s.io > install.sh
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

kubectl get nodes


5.3 Agent节点加入(192.168.111.180/181)
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
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

六、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
docker load -i wordpress-php8.5-apache.tardocker load -i nginx-alpine.tar
6.2 NFS存储配置(Ansible-Node)
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
dnf -y install nfs-utils

6.3 PV/PVC配置
apiVersion: v1kind: PersistentVolumemetadata:name: wordpress-pvspec:capacity: { storage: 5Gi }volumeMode: FilesystemaccessModes: [ReadWriteMany]persistentVolumeReclaimPolicy: RetainstorageClassName: nfs-manualnfs:server: 192.168.111.179path: /data/k3s/wordpress---apiVersion: v1kind: PersistentVolumeClaimmetadata:name: wordpress-pvcspec:accessModes: [ReadWriteMany]storageClassName: nfs-manualresources: { requests: { storage: 5Gi } }
6.4 WordPress部署(Deployment+Service)
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!"
wordpress-deploy.yaml):apiVersion: apps/v1kind: Deploymentmetadata:name: wordpress-deployspec:replicas: 3selector: { matchLabels: { app: wordpress-deploy } }template:metadata: { labels: { app: wordpress-deploy } }spec:volumes: [{ name: wordpress-data, persistentVolumeClaim: { claimName: wordpress-pvc } }]containers:- name: wordpressimage: wordpress:php8.5-apacheports: [{ 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: NodePortselector: { 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反向代理配置
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;}}
7.2 Keepalived高可用配置
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
global_defs { router_id Master }vrrp_script check_nginx { script "killall -0 nginx"; interval 2; weight -20 }vrrp_instance VI_1 {state MASTERinterface ens224virtual_router_id 51priority 100advert_int 1authentication { 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 }
检查配置 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压力测试


8.2 Apache Bench测试
ab -n 1000 -c 100 http://192.168.183.100/
8.3 HA故障切换测试

九、总结

夜雨聆风