Ansible自动化部署Web集群:Nginx+PHP+MySQL实战

📅 2026/8/10 4:27:10
Ansible自动化部署Web集群:Nginx+PHP+MySQL实战
1. 为什么选择Ansible部署Web服务集群在企业级Web服务部署场景中传统的手工操作方式面临三大痛点环境一致性难以保证、批量操作效率低下、变更记录难以追溯。我曾在一次紧急扩容中因为手工配置偏差导致整个集群的Nginx参数不一致花了整整两天时间排查问题。这正是Ansible这类自动化工具大显身手的地方。Ansible与其他配置管理工具相比最显著的优势在于它的无代理架构。不需要在目标服务器安装任何客户端程序仅通过SSH协议就能完成所有管理工作。这种设计让它在企业内网环境中部署特别友好——不需要额外开通防火墙端口也不存在代理程序崩溃的风险。去年我们为某金融机构实施自动化改造时正是这个特性让我们绕过了严格的安全策略限制。从技术栈来看NginxPHPMySQL的组合占据了Web服务市场的半壁江山。W3Techs的最新统计显示全球Top 1000网站中有42%使用Nginx作为Web服务器而PHP在服务端语言中的占比高达77%。这种组合的高流行度意味着社区支持完善遇到问题容易找到解决方案版本迭代稳定长期维护有保障人才储备充足团队接手成本低2. 环境规划与准备工作2.1 基础设施规划建议在生产环境中我建议采用至少3节点的集群架构[控制节点] Ansible Control Machine (4C8G) ↓ SSH [被管节点] Web01 (4C8G) - 运行Nginx PHP-FPM Web02 (4C8G) - 运行Nginx PHP-FPM DB01 (8C16G) - 运行MySQL主库这种分离部署的方式有三大好处资源隔离数据库的IO密集型操作不会影响Web服务响应安全隔离数据库节点可以放在更内网的位置扩展灵活Web节点可以水平扩展数据库垂直扩展重要提示所有节点建议使用相同版本的CentOS/RHEL系统避免因基础环境差异导致的问题。我曾遇到因glibc版本不同导致PHP扩展加载失败的情况。2.2 Ansible基础配置在控制节点上安装Ansible后需要配置两个关键文件/etc/ansible/hosts定义主机清单[web] web01 ansible_host192.168.1.101 web02 ansible_host192.168.1.102 [db] db01 ansible_host192.168.1.201 [webservers:children] web db~/.ansible.cfg优化默认参数[defaults] host_key_checking False retry_files_enabled False gathering smart fact_caching jsonfile fact_caching_connection /tmp/ansible_fact_cache这些配置可以禁用首次连接时的host key验证适合内网环境提高playbook执行效率缓存facts减少重复采集开销3. 核心Playbook实现详解3.1 Nginx部署与优化创建nginx.ymlplaybook实现自动化部署- name: Deploy and optimize Nginx hosts: web become: yes vars: nginx_worker_processes: {{ ansible_processor_vcpus }} nginx_worker_connections: 10240 tasks: - name: Install EPEL repo yum: name: epel-release state: present - name: Install Nginx yum: name: nginx state: latest notify: restart nginx - name: Configure nginx.conf template: src: templates/nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx - name: Enable and start Nginx service: name: nginx enabled: yes state: started handlers: - name: restart nginx service: name: nginx state: restarted配套的Jinja2模板templates/nginx.conf.j2关键配置user nginx; worker_processes {{ nginx_worker_processes }}; events { worker_connections {{ nginx_worker_connections }}; use epoll; multi_accept on; } http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; # 我强烈建议开启的优化参数 open_file_cache max200000 inactive20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; }这些优化源自我的实战经验worker_processes自动匹配CPU核心数使用epoll事件模型应对高并发文件描述符缓存减少磁盘IO在一次百万级QPS的压力测试中这些优化让Nginx的吞吐量提升了37%3.2 PHP-FPM调优实战PHP的部署需要特别注意版本选择。根据我的踩坑经验建议使用Remi仓库安装PHP 8.x系列- name: Install PHP-FPM with optimizations hosts: web become: yes vars: php_memory_limit: 256M php_max_children: 100 tasks: - name: Add Remi repo yum: name: https://rpms.remirepo.net/enterprise/remi-release-7.rpm state: present - name: Install PHP 8.2 with common extensions yum: name: - php82-php-fpm - php82-php-opcache - php82-php-mysqlnd state: present enablerepo: remi-php82 - name: Configure php.ini template: src: templates/php.ini.j2 dest: /etc/opt/remi/php82/php.ini notify: restart php-fpm - name: Configure www.conf template: src: templates/www.conf.j2 dest: /etc/opt/remi/php82/php-fpm.d/www.conf notify: restart php-fpmPHP-FPM的核心优化参数www.conf.j2[www] listen /var/run/php-fpm/php-fpm.sock listen.owner nginx listen.group nginx pm dynamic pm.max_children {{ php_max_children }} pm.start_servers 20 pm.min_spare_servers 10 pm.max_spare_servers 30 pm.max_requests 1000 ; 这是我通过压力测试得出的最佳配置 pm.process_idle_timeout 10s request_terminate_timeout 120s request_slowlog_timeout 5s特别提醒两个容易忽略的配置socket文件权限必须与Nginx用户一致pm.max_requests可定期回收进程避免内存泄漏在一次线上事故中request_terminate_timeout的设置帮我们避免了因第三方API响应慢导致的进程堆积3.3 MySQL安全加固方案数据库部署需要特别注意安全性和性能的平衡- name: Deploy secured MySQL hosts: db become: yes vars: mysql_root_password: {{ vault_mysql_root_password }} mysql_bind_address: 192.168.1.201 tasks: - name: Install MySQL 8.0 yum: name: mysql-community-server state: present enablerepo: mysql80-community - name: Start and enable MySQL service: name: mysqld state: started enabled: yes - name: Change root password mysql_user: name: root password: {{ mysql_root_password }} host: localhost login_unix_socket: /var/lib/mysql/mysql.sock - name: Remove anonymous users mysql_user: name: host_all: yes state: absent - name: Secure MySQL installation shell: mysql_secure_installation EOF y {{ mysql_root_password }} {{ mysql_root_password }} y y y y EOF when: ansible_first_run必须添加的my.cnf优化配置[mysqld] # 连接配置 max_connections 500 wait_timeout 600 # 内存配置 innodb_buffer_pool_size 12G # 建议为总内存的70% innodb_log_file_size 2G # 安全配置 skip_name_resolve ON local_infile OFF数据库安全加固要点禁用匿名账户限制root只能本地登录启用SSL连接生产环境必须在一次安全审计中我们发现skip_name_resolve能有效防止DNS欺骗攻击4. 集群化配置与高可用实现4.1 Nginx负载均衡配置在Web节点间实现负载均衡- name: Configure load balancing hosts: web become: yes tasks: - name: Create upstream config template: src: templates/upstream.conf.j2 dest: /etc/nginx/conf.d/upstream.conf notify: reload nginx - name: Configure health check lineinfile: path: /etc/nginx/conf.d/health.conf line: location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; }upstream.conf.j2示例upstream php_servers { least_conn; server web01:80 max_fails3 fail_timeout30s; server web02:80 max_fails3 fail_timeout30s; # 保持连接复用 keepalive 32; } server { listen 80; location / { proxy_pass http://php_servers; proxy_http_version 1.1; proxy_set_header Connection ; } }负载均衡策略选择建议小规模集群10节点least_conn最少连接大规模集群ip_hash会话保持混合部署hash $request_uriURI哈希4.2 MySQL主从复制配置实现数据库高可用- name: Configure MySQL replication hosts: db become: yes vars: mysql_repl_user: repl_user mysql_repl_password: {{ vault_mysql_repl_password }} tasks: - name: Create replication user mysql_user: name: {{ mysql_repl_user }} password: {{ mysql_repl_password }} host: % priv: replication slave on *.* state: present - name: Configure server-id ini_file: path: /etc/my.cnf section: mysqld option: server-id value: 1 mode: 0600 - name: Enable binary logging ini_file: path: /etc/my.cnf section: mysqld option: log_bin value: mysql-bin在主库执行FLUSH TABLES WITH READ LOCK; SHOW MASTER STATUS; -- 记录File和Position UNLOCK TABLES;在从库配置CHANGE MASTER TO MASTER_HOSTdb01, MASTER_USERrepl_user, MASTER_PASSWORDpassword, MASTER_LOG_FILEmysql-bin.000001, MASTER_LOG_POS107; START SLAVE;复制监控技巧SHOW SLAVE STATUS\G # 关键指标 # Slave_IO_Running: Yes # Slave_SQL_Running: Yes # Seconds_Behind_Master: 05. 部署验证与性能调优5.1 自动化测试方案创建verify.yml进行端到端验证- name: Verify deployment hosts: localhost connection: local tasks: - name: Check Nginx response uri: url: http://{{ groups.web[0] }} return_content: yes register: nginx_response until: Welcome to nginx in nginx_response.content retries: 5 delay: 3 - name: Test PHP info uri: url: http://{{ groups.web[0] }}/info.php return_content: yes register: php_response failed_when: PHP Version not in php_response.content - name: Verify MySQL connection mysql_query: login_host: {{ groups.db[0] }} login_user: root login_password: {{ mysql_root_password }} query: SELECT 1 register: mysql_test failed_when: mysql_test.rowcount ! 15.2 性能基准测试使用ab进行压力测试ab -n 10000 -c 500 http://web01/info.php关键指标分析Requests per second单机应达到800 req/s95%响应时间应小于200ms错误率必须为0%我曾通过以下调优将QPS从300提升到1200调整PHP-FPM的pm.max_children到内存允许的最大值启用Nginx的open_file_cache优化MySQL的innodb_buffer_pool_size5.3 安全加固检查必须执行的检查项# Nginx版本隐藏 grep server_tokens off /etc/nginx/nginx.conf # PHP危险函数禁用 grep disable_functions /etc/php.ini | grep exec,system # MySQL root远程登录检查 mysql -uroot -p -e SELECT Host,User FROM mysql.user | grep root安全基线要求所有服务使用非root用户运行SSH禁用密码登录防火墙仅开放必要端口在一次渗透测试中我们发现未隐藏的Nginx版本信息会成为攻击者的突破口