- 文档/教程
【免费下载链接】90DaysOfDevOps
This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.
本篇文章以 90DaysOfDevOps 仓库 2022 年西班牙语版第 68 天配置管理实战中的 apache2 角色 README 为骨架,完整拆解一个 Ansible Role 的标准文件结构(Requirements、Role Variables、Dependencies、Example Playbook、License、Author Information),并结合仓库中ansible-scenario7的真实角色文件、playbook 与全局变量,说明如何把一个ansible-galaxy init生成的模板填充为一个可安装、可配置、可重启、可验证的 Apache HTTP Server 自动化角色。读完本文,你将掌握 Ansible Role 目录规范、变量分层(defaults / vars / group_vars)、任务与处理器(tasks/handlers)的协作方式,以及如何将 MySQL、Nginx 等角色组织进同一套多主机编排。
Role Name:一个角色的"身份证"
ansible-galaxy init roles/apache2生成的角色目录下,README.md 第一小节Role Name看似只是一个标题占位,但在工程实践中,它是角色在 Galaxy 生态与团队文档中的唯一身份标识。角色名应当与目录名、meta/main.yml中的描述保持一致,例如本仓库中的apache2、mysql、nginx、common四个角色,命名即职责:
apache2:安装与配置 Apache HTTP Server;mysql:安装 MySQL 并创建数据库与用户;nginx:部署反向代理配置;common:安装各主机通用的基础工具。
角色的标准目录结构(以 ansible-scenario7/roles/apache2 为例)包含:
roles/apache2/ ├── defaults/main.yml # 默认变量(优先级最低,可被覆盖) ├── handlers/main.yml # 处理器:由任务 notify 触发的动作 ├── meta/main.yml # 角色元数据:作者、许可证、依赖、平台 ├── tasks/ │ ├── main.yml # 入口指针,import 具体任务文件 │ └── apache2_install.yml ├── templates/ │ ├── index.html.j2 # Jinja2 模板 │ └── ports.conf.j2 ├── tests/ │ ├── inventory │ └── test.yml └── vars/main.yml # 角色内部变量(优先级高于 defaults)Requirements:运行角色前需要满足的前提
README 的Requirements小节提示:任何不被 Ansible 自身或角色覆盖的前置条件都应在此说明。以本仓库 MySQL 角色为典型例子——install_mysql.yml 中先通过apt安装python3-pip、mysql-client、python3-mysqldb、libmysqlclient-dev,再通过pip安装PyMySQL模块,然后才安装mysql-server。这正是Requirements要记录的内容:数据库模块依赖 Python 库与系统包,缺一不可。
第 68 天的实战笔记记录了真实教训:首次仅对database标签运行 playbook 时报错,原因是控制端缺少pip3(Python 包管理器),最终通过在 common 角色的任务中补装工具解决。对应证据在 common 角色 install_tools.yml,其中安装了neofetch、tree、figlet等通用工具。由此可见,Requirements 既是文档约定,也是任务文件里隐式执行的前置保障。
Role Variables:变量从哪里来、优先级如何
README 的Role Variables小节要求说明角色可设置的变量,包括defaults/main.yml、vars/main.yml中的变量,以及通过参数传入或从全局作用域(hostvars、group vars)读取的变量。
defaults 与 vars 的优先级
apache2 的 defaults/main.yml 和 vars/main.yml 目前都只有注释占位。在 Ansible 变量优先级体系中,vars/main.yml的优先级高于defaults/main.yml,而defaults是最低优先级,便于被 playbook、inventory、group_vars 或命令行-e覆盖。因此推荐:可变且需被外部定制的参数放 defaults,角色内部强约束的参数放 vars。
全局变量:group_vars
在本场景中,变量被集中到了全局作用域 group_vars/all/common_variables.yml:
http_port: 8000 https_port: 4443 html_welcome_msg: "Hello 90DaysOfDevOps - Welcome to Day 68!" mysql_user_name: root mysql_user_password: vagrant db_user: devops db_pass: DevOps90 db_name: 90DaysOfDevOps由于放在group_vars/all/下,所有主机组(webservers、proxy、database)都能读取这些变量。这正是 README 中"从全局作用域读取变量"的真实落点——http_port被 apache2 的ports.conf.j2模板消费,同时被 nginx 的mysite.j2动态代理配置消费;mysql_*、db_*系列变量则被 mysql 角色的用户与数据库创建任务引用。
模板中的变量与事实(facts)
ports.conf.j2 使用Listen {{ http_port }}与Listen {{ https_port }}两个变量渲染监听端口,且仅在启用ssl_module或mod_gnutls.c模块时监听 HTTPS 端口:
Listen {{ http_port }} <IfModule ssl_module> Listen {{ https_port }} </IfModule> <IfModule mod_gnutls.c> Listen {{ https_port }} </IfModule>index.html.j2 则同时使用了用户变量与 Ansible 自动收集的"事实":
<html> <h1>{{ html_welcome_msg }}! I'm webserver {{ ansible_facts['nodename'] }} </h1> </html>ansible_facts['nodename']来自每次执行 playbook 前默认触发的"收集事实(gathering facts)"阶段,无需我们显式定义。你可以用ansible <host> -m setup查看完整事实数据,本仓库将输出重定向保存为 ansible-scenario5/facts.json 供查阅——其中包含 IP 地址、架构、BIOS 版本等大量可复用信息。这就是 README 提示"变量可来自 hostvars / group vars / facts"的完整写照。
Dependencies:角色依赖的声明方式
README 的Dependencies小节要求列出托管于 Galaxy 的其他角色及其参数。对应实现位于 meta/main.yml:
galaxy_info: author: your name description: your role description company: your company (optional) license: license (GPL-2.0-or-later, MIT, etc) min_ansible_version: 2.1 galaxy_tags: [] dependencies: []dependencies: []表示当前角色没有声明对其他角色的硬依赖——依赖关系通过 playbook 的roles:列表以编排顺序表达(例如每个主机组都先跑common再跑业务角色),而不是在角色内部耦合。min_ansible_version: 2.1声明了最低 Ansible 版本门槛。值得注意的是,README 末尾声明许可证为 BSD,而meta/main.yml中 license 字段仍为占位符(SPDX 建议值如 BSD-3-Clause、MIT、GPL-2.0-or-later、Apache-2.0 等),正式发布前应统一二者。
Example Playbook:如何引用该角色
README 的Example Playbook给出了标准的角色引用语法:
- hosts: servers roles: - { role: username.rolename, x: 42 }仓库中 playbook7.yml 给出了本场景的真实多主机编排:
- hosts: webservers become: yes roles: - common - apache2 tags: web - hosts: proxy become: yes roles: - common - nginx tags: proxy - hosts: database become: yes roles: - common - mysql tags: database要点解读:
- 三个 play 分别针对
webservers(web01、web02)、proxy(loadbalancer)、database(db01)主机组,均使用become: yes提权; - 每个主机组先应用
common(通用工具),再应用各自业务角色; tags让运维可以按需定点执行:ansible-playbook playbook7.yml --tags web只跑 Web 相关任务,--tags database只配置数据库,而--tags proxy,web可组合执行;- 若某任务标记
tag: always,则无论--tags传什么都会执行。
主机组定义在控制端的/etc/ansible/hosts(inventory)中,虚拟机清单可参考仓库根部的 Vagrantfile——它定义了db01(192.168.169.130)、web01(192.168.169.131)、web02(192.168.169.132)、loadbalancer(192.168.169.134)四台基于bento/ubuntu-21.10的机器。
Tasks 与 Handlers:安装、模板渲染与重启联动
apache2 角色通过 tasks/main.yml 作为指针文件引入 apache2_install.yml,形成完整的状态闭环:
- name: ensure apache is at the latest version apt: name=apache2 state=latest - name: write the apache2 ports.conf config file template: src=templates/ports.conf.j2 dest=/etc/apache2/ports.conf notify: restart apache - name: write a basic index.html file template: src: templates/index.html.j2 dest: /var/www/html/index.html notify: - restart apache - name: ensure apache is running service: name: apache2 state: started四个任务职责清晰:
- 安装:
apt: name=apache2 state=latest确保 Apache 为最新版本(幂等); - 渲染监听端口:把
ports.conf.j2写入/etc/apache2/ports.conf,配置变更时notify: restart apache; - 渲染首页:把
index.html.j2写入/var/www/html/index.html,同样在变更时通知重启; - 保证运行:
service模块确保apache2服务处于 started 状态。
处理器(handler)定义在 handlers/main.yml:
- name: restart apache service: name: apache2 state: restarted关键机制:handler 仅在任务实际发生变更(changed)时由notify触发,且在所有任务结束后执行。这意味着只有端口配置或首页内容真正变化才重启 Apache,避免了无谓的服务中断——这是 Ansible 幂等设计在服务管理上的核心体现。
同样的模式贯穿于其他角色:mysql 的 handlers/main.yml 定义restart mysql;nginx 的 configure_nginx.yml 渲染mysite.j2到/etc/nginx/sites-enabled/mysite并notify: restart nginx,同时移除默认站点配置。
角色自测:tests 目录与 inventory
README 虽未单独列出测试小节,但角色目录规范中包含tests/。tests/test.yml 针对localhost执行角色:
- hosts: localhost remote_user: root roles: - roles/apache2配合 tests/inventory(内容为localhost),可用于在开发机上快速冒烟验证角色是否可运行。发布到 Galaxy 前,建议为tests/补全针对各变量的验证断言。
运行与验证:端到端效果
在 db01 虚拟机启动并ssh-copy-id db01完成密钥分发后,从ansible-scenario7目录执行:
ansible-playbook playbook7.yml若只想配置数据库,可只跑 database 标签:
ansible-playbook playbook7.yml --tags database执行成功后,登录 db01 验证:
ssh db01 sudo /usr/bin/mysql -u root -p # 密码:vagrant select user, host from mysql.user; # 应看到 devops 用户 SHOW DATABASES; # 应看到 90DaysOfDevOps 数据库同样可以用sudo /usr/bin/mysql -u devops -p(密码DevOps90)登录。实战笔记还记录了一个关键排错点:在 setup_mysql.yml 中创建用户时必须显式指定login_unix_socket: /var/run/mysqld/mysqld.sock,才能正确连接 db01 上的 MySQL 实例——这是本地套接字认证环境下的常见适配。
从整体链路看,common + apache2 + nginx + mysql四个角色通过 playbook7.yml 被编排到三组主机,变量统一收敛于 group_vars/all/common_variables.yml,nginx 的 mysite.j2 借助groups['webservers']与hostvars[host]['ansible_facts']['nodename']动态生成 upstream 列表,实现负载均衡配置随 Web 主机增减而自动伸缩。
小结
这份 apache2 角色的 README 虽然只是ansible-galaxy init生成的模板占位,但它精确勾勒了 Ansible Role 的"契约骨架"。对照 90DaysOfDevOps 仓库ansible-scenario7的真实实现可以看到:Requirements 对应任务中的系统包与 Python 模块安装,Role Variables 对应 defaults/vars/group_vars 的分层取值,Dependencies 对应 meta 中的声明与 playbook 的编排,Example Playbook 对应多主机组的 tags 化执行,License 与 Author Information 对应 meta/main.yml 的元数据。理解这套骨架,你就能把任意一个ansible-galaxy init生成的空角色,快速填充成可复用、可测试、可发布的生产级自动化组件。
- 文档/教程
【免费下载链接】90DaysOfDevOps
This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.
相关推荐
90DaysOfDevOps 实战:用 Ansible Role 骨架构建可复用的 Apache2 配置管理角色
90DaysOfDevOps 实战:用 Ansible Role 骨架构建可复用的 Apache2 配置管理角色 导读 本文以 90DaysOfDevOps 配
文档/教程深入 Ansible Role 结构与文档规范:以 90DaysOfDevOps 的 apache2 角色为例
深入 Ansible Role 结构与文档规范:以 90DaysOfDevOps 的 apache2 角色为例 在 90DaysOfDevOps 项目第 66
文档/教程90DaysOfDevOps 实战:用 Ansible Galaxy 与 Roles 重构 Playbook——从内联任务到可复用角色(Day 66)
90DaysOfDevOps 实战:用 Ansible Galaxy 与 Roles 重构 Playbook——从内联任务到可复用角色(Day 66) 本文是
文档/教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考