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”。它不是一句空泛的教程口号,而是我过去三年里在运维一线反复验证过的真实工作流起点。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/ (默认变量)。例如 mysql Role的 tasks/main.yml 只负责安装、启动、安全加固三件事,绝不掺杂Apache配置。这种解耦让代码可复用:下次部署WordPress,只需在 lamp-app Role里增加 wp-cli 安装和数据库导入任务, apache mysql Role原封不动复用。

  • Playbook层 :顶层 lamp-deploy.yml 像一个导演,按顺序调用四个Role,并传入环境特定变量。它不写具体命令,只声明“我要Ubuntu 18.04上的LAMP”,所有实现细节下沉到Role中。这种设计让新人能快速理解整体流程(看Playbook就知道执行顺序),而资深工程师能深入某个Role优化细节(比如在 php Role里增加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健康检查,`

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值