1. 项目概述:用Ansible在Ubuntu 18.04上一键部署LAMP环境,到底省了多少事?
“Comment utiliser Ansible pour installer et configurer LAMP sur Ubuntu 18.04”——这句法语标题直译过来就是“如何使用Ansible在Ubuntu 18.04上安装并配置LAMP”。它不是一句空泛的教程口号,而是我过去三年里在运维一线反复验证过的真实工作流起点。LAMP(Linux + 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: present
,Ansible会自动判断软件包是否已装、服务是否已启、配置文件是否匹配——没装就装,没启就启,不一致就覆盖。这种幂等性(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.2"
,
mysql_package: "mysql-server-5.7"
,所有
apt
安装都加
default_release: bionic-updates
,确保即使在Ubuntu 20.04控制机上运行,也能准确拉取18.04源里的包。这种对目标环境的绝对尊重,比盲目追求“最新版”更体现工程素养。
另外,Ubuntu 18.04的
systemd
服务管理机制已非常成熟,但尚未引入20.04后的
systemd-resolved
DNS覆盖冲突、
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拆解为四个独立Role:
apache、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,只需新建一个
redis
Role,然后在
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_subset=mini"
,查看返回的
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 "ansible@control"
,将公钥
id_rsa.pub
内容追加到被控机
~/.ssh/authorized_keys
中。关键细节在于权限设置:被控机的
~/.ssh
目录必须是700,
authorized_keys
必须是600,否则SSH会拒绝密钥登录。我曾遇到一次诡异故障——所有
ping
测试都成功,但
apt
模块始终报
Permission denied
。排查半天才发现,被控机管理员为“方便”,把
authorized_keys
权限设成了644,SSH出于安全策略静默降级为密码认证,而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 ansible==2.10.11
注意不要用
apt install ansible
,Ubuntu源里的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文件,而非执行。解决方案是在
apache
Role的
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。
第二个陷阱是MPM(Multi-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
认证,必然失败。
解决方案分三步走。第一步,在
mysql
Role的
tasks/main.yml
开头,强制重置root密码并切换认证插件:
- name: Reset MySQL root password and switch to native password
command: mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{{ mysql_root_password }}'; FLUSH PRIVILEGES;"
args:
executable: /bin/bash
become: yes
ignore_errors: yes
ignore_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.enable=0
是默认值。我们用
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_consumption=128
是经验值:128MB内存足以缓存数千个PHP文件,再大反而浪费;
revalidate_freq=60
表示每60秒检查一次文件修改时间,平衡性能与热更新需求。实测表明,启用OPcache后,WordPress首页TTFB(Time 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 = False
host_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虚拟机IP,
private_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 Apache
a2enmod
和
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 Apache
template:
模块比
copy:
更强大,它支持Jinja2变量替换。
000-default.conf.j2
内容如下:
<VirtualHost *:{{ apache_port }}>
ServerAdmin webmaster@localhost
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
</VirtualHost>
AllowOverride 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: tcp
ufw:
模块自动调用
ufw allow 80
,比
command:
更安全,且能处理
ufw
未启用的情况(自动启用)。
handlers/main.yml
极简:
---
- name: Restart Apache
service:
name: apache2
state: restarted
4.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),保证环境一致性。
任务2:root密码重置与认证插件切换
- name: Reset MySQL root password and switch to native password
command: mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{{ mysql_root_password }}'; FLUSH PRIVILEGES;"
args:
executable: /bin/bash
become: yes
ignore_errors: yes
ignore_errors: yes
是关键容错设计,确保Playbook在首次和后续运行中均能成功。
任务3:MySQL配置文件精细化修改
- 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 MySQL
notify: Restart MySQL
对应
handlers/main.yml
中的
service: name=mysql state=restarted
。
任务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
的任务链设计强调“最小必要原则”,只安装必需扩展,避免臃肿:
任务1:PHP核心包安装
- name: Install PHP 7.2 core packages
apt:
name:
- php7.2
- libapache2-mod-php7.2
- php7.2-cli
state: present
libapache2-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 Apache
notify: Restart Apache
确保PHP模块加载生效。
任务3:php.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: present
memory_limit=256M
满足WordPress插件需求;
upload_max_filesize=64M
支持大附件上传;
display_errors=Off
关闭错误显示,防止敏感信息泄露。
任务4:OPcache启用与调优
- 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 Apache
OPcache参数经实测验证,在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健康检查,`

280

被折叠的 条评论
为什么被折叠?



