Ansible Roles 完全指南:概念、使用与实战部署 MySQL/Nginx/Httpd 📅 2026/7/1 5:33:59 Ansible Roles 完全指南概念、使用与实战部署 MySQL/Nginx/Httpd一、什么是 Ansible Roles在自动化运维领域Ansible 凭借其简洁的 YAML 语法和强大的功能脱颖而出。随着项目规模的增长Playbook 文件会变得越来越庞大和复杂——当一个项目有成百上千个任务时仅靠简单的 includes 不停地引用最终会导致文件结构错综复杂、难以维护。Ansible Roles角色正是为了解决这一问题而诞生的。Roles 是 Ansible 自 1.2 版本引入的特性用于层次性、结构化地组织 Playbook。简单来说Roles 通过分别将变量、文件、任务、模板及处理器放置于单独的目录中并提供一种便捷的调用机制实现了类似编程中模块化的效果。更正式的定义是Roles 能够根据已知的文件结构自动加载相关的变量、文件、任务、处理器以及其他 Ansible 构件。将内容分组到 Roles 后可以轻松地在不同项目中复用并与他人共享。可以把 Roles 想象成一个“功能工具箱”——我们把安装 Nginx、MySQL、Httpd 等不同服务的功能角色放在一个仓库里需要哪个就从里面拿出来用。二、Roles 的目录结构一个标准的 Ansible Role 拥有七个主要目录每个 Role 至少需要包含其中一个目录用不到的目录可以省略。textroles/ └── role_name/ ├── tasks/ # 主要任务列表 │ └── main.yml ├── handlers/ # 通知处理器 │ └── main.yml ├── templates/ # Jinja2 模板文件 │ └── *.j2 ├── files/ # 静态文件供 copy/script 模块使用 │ └── * ├── vars/ # 高优先级变量 │ └── main.yml ├── defaults/ # 默认变量低优先级 │ └── main.yml └── meta/ # 角色元数据依赖关系等 └── main.yml各目录的作用如下目录说明tasks/main.yml角色要执行的主要任务列表是 Role 的核心handlers/main.yml定义被任务通知时触发的处理器如重启服务templates/存放 Jinja2 模板文件后缀为.j2用于动态生成配置文件files/存放静态文件供copy或script模块调用vars/main.yml定义该角色使用的高优先级变量defaults/main.yml定义默认变量优先级极低——只有当该变量没有其他来源赋值时才会用到meta/main.yml角色的元数据包括角色依赖、Galaxy 平台支持信息等三、如何创建和使用 Roles3.1 创建 Role有两种方式创建 Role方式一使用ansible-galaxy命令推荐bashansible-galaxy role init role_name该命令会自动生成完整的标准目录结构省去手动创建各目录和main.yml文件的时间。例如bashansible-galaxy role init nginx执行后会在当前目录生成如下结构textnginx/ ├── defaults/ │ └── main.yml ├── files/ ├── handlers/ │ └── main.yml ├── meta/ │ └── main.yml ├── tasks/ │ └── main.yml ├── templates/ ├── tests/ │ ├── inventory │ └── test.yml └── vars/ └── main.yml方式二手动创建目录和文件bashmkdir -p roles/role_name/{tasks,handlers,templates,files,vars,defaults,meta} touch roles/role_name/{tasks,handlers,vars,defaults,meta}/main.yml3.2 在 Playbook 中使用 Role在 Playbook 中调用 Role 有三种方式方式一使用roles关键字yaml- hosts: webservers roles: - nginx - mysql使用roles选项列出的 Role 会在 Play 中的任何其他任务之前运行。方式二使用import_roleyaml- hosts: webservers tasks: - import_role: name: nginximport_role添加的角色同样会在其他任务之前运行。方式三使用include_roleyaml- hosts: webservers tasks: - include_role: name: nginxinclude_role添加的角色会按照任务列表中定义的顺序运行。3.3 变量的优先级理解变量优先级对于正确使用 Roles 至关重要defaults/main.yml优先级最低仅当变量没有其他来源赋值时才会生效vars/main.yml优先级较高会覆盖 defaults 中的同名变量Playbook 中的变量、Inventory 变量等优先级更高会覆盖 Role 中的 vars四、实战使用 Roles 部署 Nginx4.1 创建 Nginx Rolebashansible-galaxy role init nginx cd nginx4.2 编写任务tasks/main.ymlyaml--- # tasks file for nginx - name: 安装 EPEL 仓库 yum: name: epel-release state: latest - name: 安装 Nginx yum: name: nginx state: latest - name: 复制静态首页文件 copy: src: index.html dest: /usr/share/nginx/html/index.html - name: 复制 Nginx 配置文件使用模板 template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx - name: 确保 Nginx 服务运行并开机自启 service: name: nginx state: started enabled: yes4.3 编写处理器handlers/main.ymlyaml--- # handlers file for nginx - name: restart nginx service: name: nginx state: restarted4.4 准备模板文件templates/nginx.conf.j2nginx# nginx.conf.j2 - Jinja2 模板 worker_processes {{ ansible_processor_cores }}; events { worker_connections {{ worker_connections }}; } http { include /etc/nginx/mime.types; default_type application/octet-stream; server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } } }4.5 定义变量vars/main.ymlyaml--- # vars file for nginx worker_connections: 102404.6 准备静态文件files/index.htmlhtml!DOCTYPE html html headtitleNginx Deployed by Ansible Role/title/head body h1Welcome to Nginx!/h1 pThis server is deployed by Ansible Roles./p /body /html4.7 编写 Playbook 调用 Roleyaml# site.yml --- - hosts: webservers remote_user: root roles: - nginx执行部署bashansible-playbook site.yml五、实战使用 Roles 部署 Httpd (Apache)5.1 创建 Httpd Rolebashansible-galaxy role init httpd cd httpd5.2 编写任务tasks/main.ymlyaml--- # tasks file for httpd - name: 安装 Httpd yum: name: httpd state: present - name: 修改 Httpd 监听端口 lineinfile: path: /etc/httpd/conf/httpd.conf regexp: ^Listen line: Listen {{ httpd_port }} notify: restart httpd - name: 复制网站首页 copy: src: index.html dest: /var/www/html/index.html - name: 启动 Httpd 服务并设置开机自启 service: name: httpd state: started enabled: yes - name: 配置防火墙允许 Http 服务 firewalld: service: http permanent: yes state: enabled immediate: yes when: ansible_facts[os_family] RedHat5.3 编写处理器handlers/main.ymlyaml--- # handlers file for httpd - name: restart httpd service: name: httpd state: restarted5.4 定义变量vars/main.ymlyaml--- # vars file for httpd httpd_port: 80805.5 准备静态文件files/index.htmlhtml!DOCTYPE html html headtitleHttpd Deployed by Ansible Role/title/head body h1Welcome to Apache Httpd!/h1 pDeployed with Ansible Roles on port {{ httpd_port }}./p /body /html5.6 Playbook 调用yaml# site.yml --- - hosts: webservers remote_user: root roles: - httpd六、实战使用 Roles 部署 MySQL6.1 创建 MySQL Rolebashansible-galaxy role init mysql cd mysql6.2 编写任务tasks/main.ymlyaml--- # tasks file for mysql - name: 安装 MySQL (MariaDB) yum: name: - mariadb-server - mariadb - MySQL-python state: present - name: 启动 MariaDB 服务并设置开机自启 service: name: mariadb state: started enabled: yes - name: 设置 MySQL root 密码 mysql_user: name: root password: {{ mysql_root_password }} host: localhost login_user: root login_password: check_implicit_admin: yes state: present - name: 创建应用程序数据库 mysql_db: name: {{ mysql_database }} state: present login_user: root login_password: {{ mysql_root_password }} - name: 创建应用程序用户并授权 mysql_user: name: {{ mysql_app_user }} password: {{ mysql_app_password }} host: % priv: {{ mysql_database }}.*:ALL state: present login_user: root login_password: {{ mysql_root_password }} - name: 删除匿名用户安全加固 mysql_user: name: host_all: yes state: absent login_user: root login_password: {{ mysql_root_password }} - name: 删除测试数据库安全加固 mysql_db: name: test state: absent login_user: root login_password: {{ mysql_root_password }}6.3 定义默认变量defaults/main.ymlyaml--- # defaults file for mysql mysql_root_password: ChangeMe123! mysql_database: myapp mysql_app_user: appuser mysql_app_password: AppPass123!6.4 编写处理器handlers/main.ymlyaml--- # handlers file for mysql - name: restart mariadb service: name: mariadb state: restarted6.5 Playbook 调用yaml# site.yml --- - hosts: dbservers remote_user: root roles: - mysql七、同时部署多个 Roles在实际生产环境中我们常常需要在一台服务器上部署多个服务或者在不同服务器上部署不同服务。以下示例展示了如何在一套 Playbook 中组合使用多个 Rolesyaml# site.yml --- - hosts: webservers remote_user: root roles: - nginx # Web 服务器使用 Nginx - httpd # 或者使用 Httpd - hosts: dbservers remote_user: root roles: - mysql # 数据库服务器使用 MySQL - hosts: all_servers remote_user: root roles: - common # 所有服务器通用的基础配置也可以在同一台主机上应用多个角色注意端口冲突yaml- hosts: web_servers roles: - nginx - mysql八、Roles 的依赖管理Roles 之间可以存在依赖关系。当一个 Role 依赖于另一个 Role 时被依赖的 Role 会自动先执行。在meta/main.yml中定义依赖yaml--- # meta/main.yml dependencies: - role: common - role: firewall vars: firewall_allowed_ports: - 80 - 443这样当引用nginxRole 时common和firewallRole 会自动先执行。九、最佳实践总结使用ansible-galaxy init创建 Role节省时间确保目录结构规范合理区分defaults和vars可被用户覆盖的变量放在defaults/不应被覆盖的内部变量放在vars/善用模板Templates对于需要根据主机动态生成的配置文件使用 Jinja2 模板而非静态文件保持 Role 的单一职责每个 Role 专注于一个功能如一个 Role 只负责安装配置 Nginx使用notify和handlers配置文件变更时优雅地重启服务避免不必要的服务重启在 Role 中嵌入自定义模块可以在 Role 的library/目录中放置自定义模块版本控制将 Roles 纳入 Git 版本管理便于团队协作和版本追溯利用 Ansible Galaxy 分享可以将写好的 Role 上传到 Ansible Galaxy 与社区分享十、总结Ansible Roles 是构建标准化、模块化自动化部署方案的关键技能。通过将复杂的部署流程分解为功能单一的 Role我们实现了代码复用一次编写到处使用可维护性清晰的目录结构让代码易于理解和修改团队协作不同成员可以并行开发不同的 Roles标准化部署确保所有环境的一致性无论是部署简单的 Web 服务Nginx/Httpd还是复杂的数据库MySQLRoles 都能帮助我们高效、可靠地完成自动化运维任务。掌握 Ansible Roles是每一位运维工程师迈向自动化运维进阶之路的必修课。