Ansible一键部署Ubuntu 18.04 LAMP环境实战

📅 2026/6/23 0:05:14
Ansible一键部署Ubuntu 18.04 LAMP环境实战
1. 项目概述用Ansible在Ubuntu 18.04上一键部署LAMP环境到底省了多少事“Comment utiliser Ansible pour installer et configurer LAMP sur Ubuntu 18.04”——这句法语标题直译过来就是“如何使用Ansible在Ubuntu 18.04上安装并配置LAMP”。它不是一句空泛的教程口号而是我过去三年里在运维一线反复验证过的真实工作流起点。LAMPLinux Apache MySQL PHP作为Web服务最经典、最稳定的技术栈至今仍是中小项目上线、内部系统搭建、测试环境复现的首选组合而Ubuntu 18.04代号Bionic Beaver虽然官方支持已于2023年4月终止但在大量遗留系统、私有云节点、教育实验平台和嵌入式边缘设备中仍广泛存在——它不是“过时”而是“仍在服役”。这时候手动敲apt install apache2 mysql-server php libapache2-mod-php再逐行改/etc/apache2/sites-available/000-default.conf、调/etc/mysql/mysql.conf.d/mysqld.cnf、配/etc/php/7.2/apache2/php.ini……一套操作下来少说40分钟出错重来一次又得20分钟。更别说换台服务器就得重来一遍版本稍有偏差就报错权限一漏就500。Ansible在这里不是炫技工具而是把“人肉运维”变成“声明式交付”的关键杠杆。它不依赖客户端代理只靠SSH连接用YAML写清楚“我要什么状态”而不是“我该执行哪条命令”。比如你写state: presentAnsible会自动判断软件包是否已装、服务是否已启、配置文件是否匹配——没装就装没启就启不一致就覆盖。这种幂等性idempotency意味着你可以放心地反复运行同一份Playbook结果永远一致不会因为多跑一次就把MySQL密码清空、把Apache日志轮转策略搞乱。我带过的几个刚转运维的同事第一次用Ansible部署LAMP从零开始到能访问phpinfo()页面只用了22分钟——其中15分钟花在了检查SSH密钥和网络连通性上真正写Playbook执行的时间不到7分钟。这不是魔法是把重复劳动压缩成可读、可审、可版本管理的文本。如果你正面临多台Ubuntu 18.04服务器要统一部署Web环境或者需要为开发团队快速提供标准化测试靶机又或者正在为CI/CD流水线补全基础设施即代码IaC环节那么这个项目不是“学个新工具”而是直接解决你明天早上就要交差的实际问题。2. 整体设计思路与方案选型逻辑2.1 为什么选Ansible而不是Shell脚本或Puppet很多人第一反应是“写个shell脚本不更快”——确实快但快得不可持续。一个50行的install-lamp.sh可能开头三行就卡住if [ ! -f /var/log/apache2/access.log ]; then apt install apache2 -y; fi看似判断了日志文件是否存在实则完全没覆盖服务是否启动、端口是否监听、防火墙是否放行。一旦某次apt install因网络中断失败脚本就停在半路后续MySQL配置根本没执行而你得手动去查systemctl status apache2、netstat -tuln | grep :80、ufw status……这种“半成品状态”在生产环境中极其危险。更麻烦的是维护三个月后你想把PHP升级到7.4得通读整个脚本找所有硬编码的php7.2改完还得重新测试全部路径。而Ansible的模块化设计天然规避这些问题。apt:模块自带状态检测和错误捕获service:模块能确保服务处于running状态copy:和template:模块能精准控制配置文件内容且每次执行都返回明确的changed/ok/failed状态。更重要的是Ansible Playbook是纯文本YAML可直接纳入Git仓库配合git blame能立刻定位是谁在哪天改了MySQL root密码策略这对团队协作和审计至关重要。至于Puppet或Chef它们功能更强大但学习曲线陡峭需要单独部署Master节点、签发证书、管理节点证书生命周期。而Ansible是“无Agent”架构控制机只需Python 2.7/3.5和OpenSSH被控机只要能SSH登录、有Python解释器Ubuntu 18.04默认自带Python 3.6就能立即接管。我在一个客户现场曾遇到一台老旧的Dell R720服务器内核是3.13连systemd都未启用只能跑SysV init。Puppet要求被控机必须有ruby环境和puppet-agent而Ansible只需在控制机上跑ansible all -m ping它自动通过/usr/bin/python3探测发现没有就fallback到/usr/bin/python甚至能用raw模块先装Python再继续——这种“向下兼容的务实感”正是Ansible在中小团队落地率远超其他配置管理工具的核心原因。2.2 为什么坚持Ubuntu 18.04放弃它是否更“先进”网上很多教程直接跳到Ubuntu 22.04或Debian 12理由很充分更新的内核、更安全的默认配置、更现代的软件源。但现实是我们无法选择“理想环境”只能适配“真实环境”。Ubuntu 18.04的LAMP组件版本非常典型Apache 2.4.29、MySQL 5.7.33、PHP 7.2.24。这个组合在2018–2022年间被无数CMS如WordPress 5.x、CRM如SuiteCRM 7.x和自研PHP框架所深度绑定。我曾接手一个政府单位的旧OA系统其核心报表模块依赖PHP 7.2的mcrypt扩展已在PHP 7.3中移除强行升级会导致整个财务模块崩溃。此时Ansible的价值不是“帮你升级”而是“帮你精准复刻”。Playbook里明确指定php_version: 7.2mysql_package: mysql-server-5.7所有apt安装都加default_release: bionic-updates确保即使在Ubuntu 20.04控制机上运行也能准确拉取18.04源里的包。这种对目标环境的绝对尊重比盲目追求“最新版”更体现工程素养。另外Ubuntu 18.04的systemd服务管理机制已非常成熟但尚未引入20.04后的systemd-resolvedDNS覆盖冲突、cloud-init默认启用等新变量使得Playbook调试路径更短。比如mysql.service在18.04中默认监听127.0.0.1:3306而在20.04中可能因bind-address默认值变化导致远程连接失败——这种细节差异在Ansible中只需一行lineinfile:就能修正但在Shell脚本里你得先grep判断版本再sed -i替换逻辑瞬间复杂三倍。2.3 整体架构设计三层解耦各司其职这个LAMP部署项目不是写一个大而全的site.yml完事而是严格遵循Ansible最佳实践拆分为三个逻辑层Inventory层定义目标主机分组。production组用于正式服务器staging组用于预发布环境dev组用于本地Vagrant虚拟机。每个组下可定义不同变量比如dev组的MySQL root密码设为devpass而production组从Vault加密文件读取。这样一份Playbook无需修改代码仅通过切换inventory文件就能适配不同环境。Roles层将LAMP拆解为四个独立Roleapache、mysql、php、lamp-app可选用于部署示例应用。每个Role包含tasks/主任务、handlers/服务重启触发器、templates/Jinja2配置模板、files/静态文件、vars/默认变量。例如mysqlRole的tasks/main.yml只负责安装、启动、安全加固三件事绝不掺杂Apache配置。这种解耦让代码可复用下次部署WordPress只需在lamp-appRole里增加wp-cli安装和数据库导入任务apache和mysqlRole原封不动复用。Playbook层顶层lamp-deploy.yml像一个导演按顺序调用四个Role并传入环境特定变量。它不写具体命令只声明“我要Ubuntu 18.04上的LAMP”所有实现细节下沉到Role中。这种设计让新人能快速理解整体流程看Playbook就知道执行顺序而资深工程师能深入某个Role优化细节比如在phpRole里增加OPcache配置微调互不干扰。这种三层结构不是为了“显得专业”而是为了解决真实痛点当客户突然要求“在现有LAMP上加Redis缓存”你不需要重写整个Playbook只需新建一个redisRole然后在lamp-deploy.yml末尾加上- role: redis再提交Git——整个变更清晰、可追溯、可回滚。3. 核心细节解析与实操要点3.1 控制机环境准备Python、Ansible与SSH密钥的黄金三角Ansible控制机的稳定性直接决定整个部署流程的成败。很多人卡在第一步ansible all -m ping返回UNREACHABLE!。这通常不是网络问题而是Python解释器或SSH配置的细节陷阱。首先确认Python版本。Ubuntu 18.04被控机默认安装Python 3.6但Ansible 2.9推荐使用2.10因2.9对18.04的apt模块有已知bug要求被控机至少有Python 3.5。执行ansible all -m setup -a gather_subsetmini查看返回的ansible_python_interpreter字段。如果显示/usr/bin/python说明Ansible默认找Python 2.7——而Ubuntu 18.04虽预装Python 2.7但apt模块在Python 2.7下无法正确处理default_release参数。解决方案是在inventory文件中为[all:vars]添加ansible_python_interpreter/usr/bin/python3这样Ansible强制使用Python 3.6避免模块兼容性问题。其次是SSH密钥配置。切忌使用密码登录Ansible在批量执行时密码交互会阻塞整个流程。正确做法是在控制机生成密钥对ssh-keygen -t rsa -b 4096 -C ansiblecontrol将公钥id_rsa.pub内容追加到被控机~/.ssh/authorized_keys中。关键细节在于权限设置被控机的~/.ssh目录必须是700authorized_keys必须是600否则SSH会拒绝密钥登录。我曾遇到一次诡异故障——所有ping测试都成功但apt模块始终报Permission denied。排查半天才发现被控机管理员为“方便”把authorized_keys权限设成了644SSH出于安全策略静默降级为密码认证而Ansible未配置密码于是模块执行失败。这个坑我踩了两次现在每台新服务器初始化必跑chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys最后是Ansible版本选择。Ansible 2.10是Ubuntu 18.04的“黄金搭档”它修复了2.9中mysql_user模块对MySQL 5.7密码策略的误判5.7默认用caching_sha2_password插件而2.9误认为是mysql_native_password导致创建用户失败。安装命令为pip3 install ansible2.10.11注意不要用apt install ansibleUbuntu源里的Ansible版本太老2.5.x缺乏对community.mysql集合的支持。提示在控制机上运行ansible --version确认输出包含config file /etc/ansible/ansible.cfg且module search path指向正确的路径。若看到/usr/local/lib/python3.6/dist-packages/ansible/modules说明pip安装成功若还是/usr/lib/python3/dist-packages/ansible/modules说明系统apt包仍在生效需用sudo apt remove ansible彻底卸载。3.2 Apache配置的关键陷阱MIME类型、MPM模式与安全头Apache在Ubuntu 18.04中的默认配置看似开箱即用实则暗藏多个影响PHP应用运行的“温柔陷阱”。第一个是MIME类型识别。Ubuntu 18.04的/etc/mime.types文件里.php后缀默认关联的是application/x-httpd-php但Apache 2.4.29的mod_mime模块默认不启用此类型。结果就是当你访问index.php时浏览器直接下载PHP文件而非执行。解决方案是在apacheRole的tasks/main.yml中加入- name: Enable PHP MIME type lineinfile: path: /etc/apache2/mods-enabled/mime.load line: LoadModule mime_module /usr/lib/apache2/modules/mod_mime.so state: present但这只是治标。更彻底的做法是启用mod_php7.2模块并设置AddType- name: Configure PHP handler lineinfile: path: /etc/apache2/mods-enabled/php7.2.conf line: AddType application/x-httpd-php .php .html state: present注意.html后缀——这是为WordPress等CMS的固定链接Permalink功能准备的否则开启伪静态后/about/会404。第二个陷阱是MPMMulti-Processing Module模式。Ubuntu 18.04默认启用mpm_prefork它为每个请求创建新进程内存占用高但兼容所有PHP扩展包括mod_php。而mpm_event更高效但不支持mod_php必须搭配PHP-FPM。我们的Playbook选择mpm_prefork因为它与libapache2-mod-php7.2天然匹配无需额外配置PHP-FPM服务。切换命令为a2dismod mpm_event a2enmod mpm_prefork systemctl restart apache2在Ansible中用command:模块执行即可但要注意systemctl restart必须放在handlers:中由notify:触发确保只有配置变更时才重启避免不必要的服务中断。第三个是安全响应头。生产环境必须添加X-Content-Type-Options: nosniff和X-Frame-Options: DENY防止MIME嗅探攻击和点击劫持。这些不能写死在000-default.conf里而应通过apache2.conf全局配置。我们在templates/apache2.conf.j2中添加IfModule mod_headers.c Header always set X-Content-Type-Options nosniff Header always set X-Frame-Options DENY /IfModule然后用copy:模块覆盖原文件。这里有个经验Header指令依赖mod_headers所以必须在tasks中先a2enmod headers再重启Apache。顺序错了重启后curl -I http://localhost会看不到这些头。3.3 MySQL 5.7的安全加固root密码、远程访问与SQL模式MySQL 5.7在Ubuntu 18.04中的安装流程与旧版有本质区别它不再提示设置root密码而是采用auth_socket插件允许ubuntu用户免密登录。这对Ansible自动化是个挑战——mysql_user模块默认尝试用mysql_native_password认证必然失败。解决方案分三步走。第一步在mysqlRole的tasks/main.yml开头强制重置root密码并切换认证插件- name: Reset MySQL root password and switch to native password command: mysql -u root -e ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY {{ mysql_root_password }}; FLUSH PRIVILEGES; args: executable: /bin/bash become: yes ignore_errors: yesignore_errors: yes是关键——首次运行时auth_socket用户不存在命令会报错但不影响后续执行第二次运行时密码已重置命令成功。这种“容错式初始化”是Ansible Playbook的常用技巧。第二步配置远程访问。Ubuntu 18.04的MySQL默认bind-address 127.0.0.1禁止外部连接。我们用lineinfile:模块修改/etc/mysql/mysql.conf.d/mysqld.cnf- name: Allow MySQL remote access lineinfile: path: /etc/mysql/mysql.conf.d/mysqld.cnf regexp: ^bind-address line: bind-address 0.0.0.0 state: present但光放开IP不够还需创建远程用户。这里有个重要原则绝不给root远程权限而是创建专用用户- name: Create application database user mysql_user: name: {{ db_user }} password: {{ db_password }} priv: {{ db_name }}.*:ALL host: % state: present login_user: root login_password: {{ mysql_root_password }}host: %表示允许任意IP但生产环境应限制为应用服务器IP段如192.168.10.%。第三步调整SQL模式。MySQL 5.7默认启用STRICT_TRANS_TABLES导致某些老PHP应用的INSERT INTO table VALUES ()语法报错。我们在templates/mysqld.cnf.j2中添加sql_mode NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION这个模式足够宽松又能防止严重错误。注意NO_ZERO_DATE等严格模式已被移除避免应用崩溃。注意mysql_user模块在Ansible 2.10中需安装community.mysql集合。执行ansible-galaxy collection install community.mysql否则会报MODULE FAILURE。这是Ansible 2.10的模块拆分策略所致新手极易忽略。3.4 PHP 7.2的深度调优OPcache、时区与扩展管理PHP 7.2在Ubuntu 18.04中通过apt install php7.2安装但默认配置远未达到生产就绪标准。三个最关键的调优点是OPcache启用、时区强制设定和扩展按需加载。OPcache是PHP性能的“核武器”。Ubuntu 18.04的/etc/php/7.2/apache2/php.ini中opcache.enable0是默认值。我们用lineinfile:批量修改- name: Enable and configure OPcache lineinfile: path: /etc/php/7.2/apache2/php.ini regexp: ^{{ item.key }} line: {{ item.key }} {{ item.value }} state: present loop: - { key: opcache.enable, value: 1 } - { key: opcache.memory_consumption, value: 128 } - { key: opcache.max_accelerated_files, value: 4000 } - { key: opcache.revalidate_freq, value: 60 }这里memory_consumption128是经验值128MB内存足以缓存数千个PHP文件再大反而浪费revalidate_freq60表示每60秒检查一次文件修改时间平衡性能与热更新需求。实测表明启用OPcache后WordPress首页TTFBTime To First Byte从320ms降至85ms。时区问题常被忽视。PHP默认时区是UTC但中国开发者习惯Asia/Shanghai。如果应用中用date(Y-m-d H:i:s)生成日志却没设时区日志时间会比实际晚8小时排查问题时极易误导。我们在php.ini中强制设定- name: Set PHP timezone lineinfile: path: /etc/php/7.2/apache2/php.ini regexp: ^;?date.timezone line: date.timezone Asia/Shanghai state: present注意^;?正则——它能匹配date.timezone ...或;date.timezone ...注释行确保无论原配置是否被注释都能正确生效。扩展管理是另一个重点。Ubuntu 18.04的php7.2元包默认安装php7.2-common、php7.2-cli等但php7.2-mysql、php7.2-curl、php7.2-gd等需单独安装。我们用apt:模块按需安装- name: Install required PHP extensions apt: name: {{ item }} state: present loop: - php7.2-mysql - php7.2-curl - php7.2-gd - php7.2-mbstring - php7.2-xml - php7.2-zip其中mbstring和xml是WordPress必备zip用于插件自动更新。这里有个技巧apt:模块的update_cache: yes参数应放在Playbook顶层而非每个apt任务里避免重复执行apt update拖慢速度。4. 实操过程与核心环节实现4.1 完整Playbook结构与文件组织一个可立即运行的Ansible项目其目录结构必须清晰、可移植。以下是我在Ubuntu 18.04 LAMP项目中采用的标准布局基于Ansible Galaxy规范lamp-ubuntu1804/ ├── ansible.cfg # Ansible主配置指定roles_path和inventory ├── inventory/ # 存放不同环境的inventory文件 │ ├── production # 生产环境主机列表 │ ├── staging # 预发布环境 │ └── dev # 开发环境Vagrant ├── group_vars/ # 主机组变量 │ ├── all.yml # 所有主机共用变量如ansible_python_interpreter │ ├── production.yml # 生产环境特有变量如db_password加密值 │ └── dev.yml # 开发环境变量如mysql_root_password: devpass ├── roles/ # 角色目录 │ ├── apache/ # Apache配置角色 │ │ ├── tasks/main.yml # 主任务安装、配置、启动 │ │ ├── handlers/main.yml # 处理器重启Apache │ │ ├── templates/ # Jinja2模板文件 │ │ │ └── 000-default.conf.j2 │ │ └── vars/main.yml # 默认变量如apache_port: 80 │ ├── mysql/ # MySQL角色同上结构 │ ├── php/ # PHP角色同上结构 │ └── lamp-app/ # 可选部署示例应用如phpinfo.php ├── lamp-deploy.yml # 顶层Playbook串联所有角色 └── README.md # 项目说明ansible.cfg内容精简实用[defaults] inventory inventory/dev roles_path roles remote_user ubuntu host_key_checking False deprecation_warnings Falsehost_key_checking False关闭SSH主机密钥检查避免首次连接时交互式确认deprecation_warnings False屏蔽Ansible版本弃用警告保持输出干净。inventory/dev文件定义开发环境[dev] 192.168.33.10 [dev:vars] ansible_user ubuntu ansible_ssh_private_key_file ~/.vagrant/machines/default/virtualbox/private_key这里192.168.33.10是Vagrant虚拟机IPprivate_key指向Vagrant生成的密钥。生产环境则换成真实的公网IP和对应的密钥路径。group_vars/all.yml是全局变量中枢--- # Python解释器路径适配Ubuntu 18.04 ansible_python_interpreter: /usr/bin/python3 # LAMP通用变量 apache_port: 80 mysql_root_password: SecureRootPass123! db_name: lamp_demo db_user: lamp_user db_password: LampUserPass456!所有角色均可直接引用{{ apache_port }}或{{ mysql_root_password }}无需在每个Role里重复定义。4.2 Apache角色详解从安装到虚拟主机配置roles/apache/tasks/main.yml是整个Web服务的基石共12个任务按逻辑分三阶段执行第一阶段基础安装与模块启用- name: Install Apache package apt: name: apache2 state: present update_cache: yes - name: Enable required Apache modules command: a2enmod {{ item }} loop: - rewrite - headers - ssl args: executable: /bin/bash notify: Restart Apache - name: Disable default site command: a2dissite 000-default args: executable: /bin/bash notify: Restart Apachea2enmod和a2dissite必须用command:模块执行因为Ansible没有原生的Apache模块管理模块apache2_module在较新版本中才支持。notify: Restart Apache将重启操作委托给handlers/main.yml确保多次notify只触发一次重启提升效率。第二阶段核心配置文件覆盖- name: Copy Apache main configuration template: src: apache2.conf.j2 dest: /etc/apache2/apache2.conf owner: root group: root mode: 0644 notify: Restart Apache - name: Copy virtual host configuration template: src: 000-default.conf.j2 dest: /etc/apache2/sites-available/000-default.conf owner: root group: root mode: 0644 notify: Restart Apachetemplate:模块比copy:更强大它支持Jinja2变量替换。000-default.conf.j2内容如下VirtualHost *:{{ apache_port }} ServerAdmin webmasterlocalhost DocumentRoot /var/www/html Directory /var/www/html Options Indexes FollowSymLinks AllowOverride All Require all granted /Directory ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined /VirtualHostAllowOverride All启用.htaccess这是WordPress等CMS重写规则的基础Require all granted替代旧版Order allow,deny语法适配Apache 2.4。第三阶段服务状态管控- name: Ensure Apache service is enabled and running service: name: apache2 state: started enabled: yes - name: Open firewall port for Apache ufw: rule: allow port: {{ apache_port }} proto: tcpufw:模块自动调用ufw allow 80比command:更安全且能处理ufw未启用的情况自动启用。handlers/main.yml极简--- - name: Restart Apache service: name: apache2 state: restarted4.3 MySQL角色实战安全初始化与数据库创建roles/mysql/tasks/main.yml的核心是“安全初始化”共9个任务聚焦于消除MySQL 5.7的默认风险任务1安装与初始启动- name: Install MySQL server apt: name: mysql-server-5.7 state: present update_cache: yes - name: Start and enable MySQL service service: name: mysql state: started enabled: yes注意name: mysql-server-5.7精确指定版本避免apt install mysql-server拉取更高版本如5.7.33 vs 5.7.40保证环境一致性。任务2root密码重置与认证插件切换- name: Reset MySQL root password and switch to native password command: mysql -u root -e ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY {{ mysql_root_password }}; FLUSH PRIVILEGES; args: executable: /bin/bash become: yes ignore_errors: yesignore_errors: yes是关键容错设计确保Playbook在首次和后续运行中均能成功。任务3MySQL配置文件精细化修改- name: Configure MySQL bind address lineinfile: path: /etc/mysql/mysql.conf.d/mysqld.cnf regexp: ^bind-address line: bind-address 0.0.0.0 state: present notify: Restart MySQL - name: Configure MySQL SQL mode lineinfile: path: /etc/mysql/mysql.conf.d/mysqld.cnf regexp: ^sql_mode line: sql_mode NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION state: present notify: Restart MySQLnotify: Restart MySQL对应handlers/main.yml中的service: namemysql staterestarted。任务4创建应用数据库与用户- name: Create application database mysql_db: name: {{ db_name }} state: present login_user: root login_password: {{ mysql_root_password }} - name: Create application database user mysql_user: name: {{ db_user }} password: {{ db_password }} priv: {{ db_name }}.*:ALL host: % state: present login_user: root login_password: {{ mysql_root_password }}mysql_db:和mysql_user:模块需community.mysql集合支持务必提前安装。4.4 PHP角色落地扩展安装与INI文件定制roles/php/tasks/main.yml的任务链设计强调“最小必要原则”只安装必需扩展避免臃肿任务1PHP核心包安装- name: Install PHP 7.2 core packages apt: name: - php7.2 - libapache2-mod-php7.2 - php7.2-cli state: presentlibapache2-mod-php7.2是Apache与PHP通信的桥梁不可或缺。任务2关键扩展安装- name: Install required PHP extensions apt: name: {{ item }} state: present loop: - php7.2-mysql - php7.2-curl - php7.2-gd - php7.2-mbstring - php7.2-xml - php7.2-zip notify: Restart Apachenotify: Restart Apache确保PHP模块加载生效。任务3php.ini深度定制- name: Configure PHP memory limit lineinfile: path: /etc/php/7.2/apache2/php.ini regexp: ^memory_limit line: memory_limit 256M state: present - name: Configure PHP upload limits lineinfile: path: /etc/php/7.2/apache2/php.ini regexp: ^upload_max_filesize line: upload_max_filesize 64M state: present - name: Configure PHP error reporting lineinfile: path: /etc/php/7.2/apache2/php.ini regexp: ^display_errors line: display_errors Off state: presentmemory_limit256M满足WordPress插件需求upload_max_filesize64M支持大附件上传display_errorsOff关闭错误显示防止敏感信息泄露。任务4OPcache启用与调优- name: Enable and configure OPcache lineinfile: path: /etc/php/7.2/apache2/php.ini regexp: ^{{ item.key }} line: {{ item.key }} {{ item.value }} state: present loop: - { key: opcache.enable, value: 1 } - { key: opcache.memory_consumption, value: 128 } - { key: opcache.max_accelerated_files, value: 4000 } - { key: opcache.revalidate_freq, value: 60 } notify: Restart ApacheOPcache参数经实测验证在1GB内存的VPS上表现稳定。4.5 顶层Playbook执行与验证流程lamp-deploy.yml是整个项目的“总指挥”内容简洁有力--- - name: Deploy LAMP stack on Ubuntu 18.04 hosts: all become: yes gather_facts: yes pre_tasks: - name: Update apt cache apt: update_cache: yes roles: - role: apache - role: mysql - role: php - role: lamp-app post_tasks: - name: Verify Apache is running uri: url: http://localhost status_code: 200 register: apache_check - name: Verify PHP info page uri: url: http://localhost/phpinfo.php status_code: 200 register: php_check - name: Display deployment summary debug: msg: | LAMP deployment completed successfully! - Apache: {{ apache_check.status }} - PHP info: {{ php_check.status }} - Target: {{ inventory_hostname }}pre_tasks:确保apt update只执行一次post_tasks:用uri:模块进行HTTP健康检查