1. 项目背景与核心价值
在当今的互联网运维领域,自动化部署已经成为提升效率的标配方案。我最近刚完成一个企业级论坛系统的自动化部署改造,将原本需要2小时的手动部署流程缩短到了15分钟以内。这个方案的核心就是通过Jenkins调用Ansible来部署LNMP环境并搭建Discuz论坛。
为什么这种组合特别适合中小型Web应用的部署?首先,Jenkins提供了稳定的任务调度和流水线管理能力;其次,Ansible作为无代理的配置管理工具,可以轻松实现批量服务器配置;最后,LNMP(Linux+Nginx+MySQL+PHP)作为经典的Web服务栈,与Discuz这类PHP论坛系统是天作之合。
这个方案特别适合以下场景:
- 需要频繁部署测试环境的开发团队
- 缺乏专职运维人员的技术小组
- 希望实现部署标准化的中小企业
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与工具选型
2.1 基础环境配置
在开始之前,我们需要准备至少两台服务器:
- 控制节点(Jenkins+Ansible):建议4核8G配置,安装RHEL 7.3或CentOS 7
- 目标节点(LNMP+Discuz):建议4核16G配置,同样使用RHEL/CentOS系统
注意:虽然最新版的Ansible支持OpenEuler等新系统,但考虑到稳定性,建议使用RHEL/CentOS 7系列。我在实际项目中曾遇到OpenEuler 20.03的软件源兼容性问题,导致部分依赖包安装失败。
2.2 关键工具版本选择
经过多次测试验证,我推荐以下版本组合:
- Jenkins:2.346.3 LTS版本(长期支持版更稳定)
- Ansible:2.9.27(兼容性最好的一个版本)
- Nginx:1.20.1(支持HTTP/2)
- MySQL:5.7.38(Discuz官方推荐的版本)
- PHP:7.4.30(Discuz X3.5支持的最高版本)
版本选择背后的考量:
- Discuz X3.5明确要求PHP版本在7.2-7.4之间
- MySQL 5.7比8.0更节省资源且兼容性更好
- Ansible 2.9的模块稳定性已被广泛验证
3. Jenkins与Ansible的集成配置
3.1 Jenkins的安装与初始化
在控制节点上执行以下命令安装Jenkins:
bash复制# 添加Jenkins源
sudo wget -O /etc/yum.repos.d/jenkins.repo \
https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
# 安装Jenkins
sudo yum install -y jenkins java-11-openjdk-devel
# 修改默认端口(避免与Nginx冲突)
sed -i 's/JENKINS_PORT="8080"/JENKINS_PORT="9080"/' \
/etc/sysconfig/jenkins
# 启动服务
sudo systemctl enable --now jenkins
安装完成后,访问http://<服务器IP>:9080 完成初始配置。有几个关键配置点需要注意:
- 安装"Ansible"和"Pipeline"插件
- 在系统设置中添加Ansible的路径(通常为/usr/bin/ansible)
- 配置SSH密钥对用于连接目标服务器
3.2 Ansible的配置优化
创建Ansible的hosts文件(/etc/ansible/hosts):
ini复制[web_servers]
web1 ansible_host=192.168.1.101 ansible_user=root
web2 ansible_host=192.168.1.102 ansible_user=root
[db_servers]
db1 ansible_host=192.168.1.103 ansible_user=root
[discuz:children]
web_servers
db_servers
配置ansible.cfg优化连接参数:
ini复制[defaults]
host_key_checking = False
forks = 10
timeout = 30
log_path = /var/log/ansible.log
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
scp_if_ssh = True
4. LNMP环境的自动化部署
4.1 编写Ansible Playbook
创建lnmp.yml playbook文件:
yaml复制---
- name: Deploy LNMP for Discuz
hosts: discuz
become: yes
vars:
mysql_root_password: "{{ vault_mysql_root_password }}"
discuz_db_password: "{{ vault_discuz_db_password }}"
tasks:
- name: Install EPEL repo
yum:
name: epel-release
state: present
- name: Install common packages
yum:
name: ['vim', 'wget', 'git', 'unzip']
state: present
- name: Configure Web Servers
hosts: web_servers
become: yes
tasks:
- name: Install Nginx
yum:
name: nginx
state: present
- name: Install PHP 7.4
yum:
name: ['php74', 'php74-php-fpm', 'php74-php-mysqlnd',
'php74-php-gd', 'php74-php-mbstring']
enablerepo: remi-php74
state: present
- name: Start Nginx and PHP-FPM
service:
name: "{{ item }}"
state: started
enabled: yes
loop:
- nginx
- php74-php-fpm
- name: Configure Database Server
hosts: db_servers
become: yes
tasks:
- name: Install MySQL 5.7
yum:
name: ['mysql-community-server', 'mysql-community-client']
state: present
- name: Start MySQL service
service:
name: mysqld
state: started
enabled: yes
- name: Change MySQL root password
mysql_user:
name: root
password: "{{ mysql_root_password }}"
host: localhost
login_unix_socket: /var/lib/mysql/mysql.sock
4.2 安全加固措施
在实际部署中,我们需要特别注意以下几点安全配置:
- MySQL安全初始化:
bash复制mysql_secure_installation
- Nginx配置禁用敏感信息:
nginx复制server {
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
}
- PHP安全配置调整:
ini复制expose_php = Off
display_errors = Off
log_errors = On
5. Discuz论坛的自动化部署
5.1 数据库准备
创建专门的Ansible任务来处理Discuz的数据库初始化:
yaml复制- name: Prepare Discuz Database
hosts: db_servers
become: yes
tasks:
- name: Create Discuz database
mysql_db:
name: discuz
state: present
login_user: root
login_password: "{{ mysql_root_password }}"
- name: Create Discuz user
mysql_user:
name: discuz
password: "{{ discuz_db_password }}"
priv: "discuz.*:ALL"
host: "%"
login_user: root
login_password: "{{ mysql_root_password }}"
5.2 Discuz代码部署
编写部署任务:
yaml复制- name: Deploy Discuz Code
hosts: web_servers
become: yes
tasks:
- name: Download Discuz package
get_url:
url: https://download.comsenz.com/DiscuzX/3.5/Discuz_X3.5_SC_UTF8.zip
dest: /tmp/Discuz_X3.5.zip
- name: Unzip package
unarchive:
src: /tmp/Discuz_X3.5.zip
dest: /var/www/
remote_src: yes
- name: Set proper permissions
file:
path: /var/www/discuz
owner: nginx
group: nginx
recurse: yes
- name: Configure Nginx
template:
src: templates/discuz.conf.j2
dest: /etc/nginx/conf.d/discuz.conf
notify: Restart Nginx
对应的Nginx模板(templates/discuz.conf.j2):
nginx复制server {
listen 80;
server_name forum.example.com;
root /var/www/discuz/upload;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php74-php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
6. Jenkins流水线整合
6.1 创建Pipeline项目
在Jenkins中新建一个Pipeline项目,使用以下Jenkinsfile:
groovy复制pipeline {
agent any
environment {
ANSIBLE_CONFIG = '${WORKSPACE}/ansible.cfg'
VAULT_PASSWORD_FILE = '${WORKSPACE}/.vault_pass'
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: 'https://github.com/your-repo/discuz-deploy.git'
}
}
stage('Deploy LNMP') {
steps {
ansiblePlaybook(
playbook: 'lnmp.yml',
inventory: 'hosts',
extras: '--vault-password-file ${VAULT_PASSWORD_FILE}'
)
}
}
stage('Deploy Discuz') {
steps {
ansiblePlaybook(
playbook: 'discuz.yml',
inventory: 'hosts',
extras: '--vault-password-file ${VAULT_PASSWORD_FILE}'
)
}
}
}
post {
always {
cleanWs()
}
}
}
6.2 安全凭证管理
对于MySQL密码等敏感信息,建议使用Ansible Vault加密:
bash复制# 创建加密文件
ansible-vault create vars/vault.yml
# 内容示例:
vault_mysql_root_password: "YourSecurePassword123!"
vault_discuz_db_password: "DiscuzUserPass456!"
然后在playbook中引用:
yaml复制- hosts: all
vars_files:
- vars/vault.yml
tasks:
...
7. 常见问题与解决方案
7.1 部署过程中的典型错误
-
PHP版本不兼容:
- 现象:Discuz安装页面报错"PHP版本必须为7.2-7.4"
- 解决方案:确认使用了正确的remi-php74仓库,并安装所有必需的PHP扩展
-
Nginx 403错误:
- 检查点:
- /var/www/discuz目录权限是否为nginx:nginx
- SELinux上下文是否正确(chcon -R -t httpd_sys_content_t /var/www/discuz)
- PHP-FPM进程是否正常运行
- 检查点:
-
MySQL连接失败:
- 排查步骤:
- 确认MySQL服务已启动
- 检查防火墙规则(firewall-cmd --add-service=mysql)
- 验证用户权限(SHOW GRANTS FOR 'discuz'@'%')
- 排查步骤:
7.2 性能优化建议
- PHP-FPM调优:
ini复制pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
- MySQL优化配置:
ini复制innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
query_cache_size = 64M
- Nginx缓存配置:
nginx复制location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public";
}
8. 扩展与进阶方案
8.1 多环境部署策略
对于需要区分开发、测试、生产环境的情况,可以采用以下方案:
- 目录结构组织:
code复制inventories/
production/
hosts
group_vars/
staging/
hosts
group_vars/
development/
hosts
group_vars/
- Jenkins多分支Pipeline:
groovy复制pipeline {
agent any
parameters {
choice(
name: 'ENVIRONMENT',
choices: ['development', 'staging', 'production'],
description: 'Select deployment environment'
)
}
stages {
stage('Deploy') {
steps {
ansiblePlaybook(
playbook: 'site.yml',
inventory: "inventories/${params.ENVIRONMENT}/hosts",
extras: '--vault-password-file ${VAULT_PASSWORD_FILE}'
)
}
}
}
}
8.2 容器化部署方案
对于更现代的部署方式,可以考虑Docker化改造:
- 编写docker-compose.yml:
yaml复制version: '3'
services:
web:
image: nginx:1.20
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./discuz:/var/www/html
depends_on:
- php
php:
image: php:7.4-fpm
volumes:
- ./discuz:/var/www/html
environment:
- DB_HOST=db
- DB_USER=discuz
- DB_PASSWORD=${DISCUZ_DB_PASSWORD}
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=discuz
- MYSQL_USER=discuz
- MYSQL_PASSWORD=${DISCUZ_DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
- 对应的Jenkins Pipeline调整:
groovy复制stage('Docker Deploy') {
steps {
sh '''
docker-compose down
docker-compose up -d --build
'''
}
}
在实际项目中,我发现这种组合方案特别适合需要频繁更新论坛插件或主题的团队。通过将部署过程标准化,新成员可以在第一天就完成环境搭建,而不是花几天时间折腾环境配置。
