14-ansible-role角色
官网文档
https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
为什么要用role
在 Ansible 中,Ansible Role(角色)是一种用于组织和重用 Ansible Playbook 代码的强大机制。它可以将相关的任务、变量、模板、文件等组织在一起,形成一个独立的、可复用的单元,从而提高代码的可维护性和可扩展性。以下从多个方面详细解释 Ansible Role。
1. 角色的作用
- 代码复用:当需要在多个 Playbook 中执行相似的任务时,例如安装和配置 Web 服务器、数据库服务器等,可以将这些任务封装成角色,在不同的 Playbook 中重复使用,避免代码重复编写。
- 提高可维护性:角色将相关的代码组织在一起,使得代码结构更加清晰。当需要修改某个功能时,只需要在对应的角色中进行修改,而不需要在多个 Playbook 中查找和修改代码。
- 团队协作:角色可以让不同的团队成员负责不同的功能模块,每个成员专注于自己的角色开发和维护,提高开发效率和代码质量。
2. 角色的目录结构
一个标准的 Ansible Role 具有特定的目录结构,以下是一个典型的角色目录结构示例:
roles/
└── webserver/
├── defaults/
│ └── main.yml
├── files/
├── handlers/
│ └── main.yml
├── meta/
│ └── main.yml
├── tasks/
│ └── main.yml
├── templates/
└── vars/
└── main.yml
各目录的作用如下:
defaults:包含角色的默认变量。这些变量具有最低的优先级,在运行时可以被其他地方定义的同名变量覆盖。files:存放需要复制到目标主机的静态文件,例如配置文件、脚本等。handlers:定义角色的处理程序(Handlers)。处理程序是在任务执行过程中被触发的特殊任务,通常用于重启服务等操作。meta:包含角色的元数据,例如角色的依赖关系、作者信息等。tasks:定义角色的主要任务。这些任务将按顺序执行,是角色的核心部分。templates:存放 Jinja2 模板文件。模板文件可以根据变量动态生成配置文件。vars:包含角色的变量。这些变量的优先级高于defaults中的变量。
3. 角色的使用方法
定义角色
要定义一个角色,只需要按照上述目录结构创建相应的目录和文件,并在其中编写任务、变量、模板等代码。例如,在 tasks/main.yml 中定义角色的主要任务:
---
- name: Install Nginx
apt:
name: nginx
state: present
- name: Start Nginx service
systemd:
name: nginx
state: started
enabled: yes
在 Playbook 中使用角色
在 Playbook 中,可以使用 roles 关键字引用角色。示例如下:
---
- name: Deploy Web Server
hosts: web_servers
become: true
roles:
- webserver
在这个 Playbook 中,roles 部分引用了名为 webserver 的角色,Ansible 会自动执行该角色中定义的任务。
传递变量给角色
可以在 Playbook 中为角色传递变量,覆盖角色的默认变量。示例如下:
---
- name: Deploy Web Server
hosts: web_servers
become: true
roles:
- role: webserver
vars:
nginx_port: 8080
在这个例子中,为 webserver 角色传递了一个变量 nginx_port,并将其值设置为 8080。在角色中可以使用这个变量来动态配置 Nginx 的端口。
4. 角色的依赖关系
角色之间可以存在依赖关系,通过 meta/main.yml 文件来定义。例如,webserver 角色依赖于 common 角色,可以在 webserver/meta/main.yml 中定义依赖关系:
---
dependencies:
- role: common
当使用 webserver 角色时,Ansible 会自动先执行 common 角色的任务。
5. 角色的分发和共享
Ansible Galaxy 是一个官方的角色库,你可以将自己开发的角色发布到 Ansible Galaxy 上,供其他用户下载和使用。同时,你也可以从 Ansible Galaxy 上下载其他用户共享的角色,方便快速搭建环境。例如,使用 ansible-galaxy 命令下载角色:
ansible-galaxy install geerlingguy.nginx
这将下载 geerlingguy 用户共享的 nginx 角色到本地。
通过使用 Ansible Role,可以将复杂的自动化任务分解为多个独立的、可复用的模块,提高 Ansible 代码的组织性和可维护性。
之前你部署的nfs、rsync、lsyncd、nginx是如何管理他们的palybook的?
想必是随便放在某一个文件夹里吧
而如果你部署这个备份方案的多个playbook,还使用到了一些额外的文件,如配置文件,网页文件,变量文件等等等,你该怎么管理?不能继续这样随便放,毫无章法吧。
role解决了什么问题
Ansible Role 解决了在使用 Ansible 进行自动化运维过程中遇到的诸多问题,以下从代码组织、复用性、可维护性、团队协作等多个方面详细阐述它所解决的问题。
1. 代码组织混乱问题
- 缺乏结构化:在没有使用角色之前,Ansible Playbook 可能会变得非常庞大和复杂。当需要管理多个不同的服务或系统配置时,所有的任务、变量和模板都混杂在一个或几个 Playbook 文件中,代码结构不清晰,难以理解和管理。
- Role 的解决方案:Role 提供了一种标准化的目录结构,将相关的任务、变量、模板、文件等组织在一起。例如,将与 Web 服务器相关的任务放在
tasks目录,默认变量放在defaults目录,模板文件放在templates目录等。这样可以让代码结构更加清晰,易于导航和维护。
2. 代码复用性差问题
- 重复编写代码:在多个 Playbook 中可能会有很多相似的任务,比如安装和配置 Nginx 服务,每次都需要在不同的 Playbook 中重复编写这些任务的代码,导致代码冗余。
- Role 的解决方案:可以将这些通用的任务封装成一个 Role,例如创建一个
nginxRole。在不同的 Playbook 中,只需要简单地引用这个 Role 即可,避免了代码的重复编写,提高了代码的复用性。例如: ```yaml
name: Deploy Nginx on Server 1 hosts: server1 roles:
- nginx
name: Deploy Nginx on Server 2 hosts: server2 roles:
- nginx ```
3. 可维护性低问题
- 修改困难:当代码重复且结构混乱时,一旦某个功能需要修改,比如修改 Nginx 的配置方式,就需要在多个 Playbook 中查找并修改相关代码,容易出现遗漏或不一致的情况,增加了维护的难度和风险。
- Role 的解决方案:使用 Role 后,只需要在对应的 Role 中进行修改,所有引用该 Role 的 Playbook 都会自动应用这些修改。例如,如果要修改
nginxRole 中的配置任务,只需要在nginx/tasks/main.yml文件中进行修改,而不需要在每个使用该 Role 的 Playbook 中修改。
4. 团队协作难题
- 协作冲突:在团队协作开发中,如果没有清晰的代码组织方式,不同成员可能会同时修改同一个 Playbook 文件,导致代码冲突和混乱。
- Role 的解决方案:Role 可以让不同的团队成员负责不同的功能模块,每个成员专注于自己的 Role 开发和维护。例如,一个成员负责开发
webserverRole,另一个成员负责开发databaseRole,这样可以减少代码冲突,提高团队协作效率。
5. 版本管理和分发问题
- 难以管理版本:对于复杂的自动化项目,管理代码的版本和分发变得困难。不同的环境可能需要不同版本的代码,手动管理这些版本和分发代码容易出错。
- Role 的解决方案:可以将 Role 发布到 Ansible Galaxy 等公共仓库或私有仓库中,方便进行版本管理和分发。其他用户可以根据需要下载和使用特定版本的 Role,同时可以使用版本控制工具(如 Git)对 Role 进行管理,确保代码的一致性和可追溯性。
6. 依赖管理问题
- 依赖不清晰:在复杂的自动化场景中,一个任务可能依赖于其他任务或软件包,手动管理这些依赖关系容易出错,导致自动化脚本执行失败。
- Role 的解决方案:Role 可以通过
meta/main.yml文件清晰地定义依赖关系。例如,一个webappRole 可能依赖于nginxRole 和phpRole,在webapp/meta/main.yml中可以明确指定这些依赖关系,Ansible 会自动处理这些依赖,确保任务按正确的顺序执行。
把单个的大剧本,拆分为小剧本,便于维护,修改、使用
完成解耦、结构更清晰、调试更方便
在实际的工作当中,一个完整的项目实际上是很多功能体的组合,如果将所有的功能写在一个playbook中会存在如代码耦合程度高、playbook长而维护成本大、灵活性低等一系列的问题。
使用roles能巧妙的解决这一系列的问题。
roles是ansible1.2版本后加入的新功能,适合于大项目playbook的编排架构。
该如何写role
编写 Ansible Role 时,采用正确的技巧和思路能显著提升角色的质量、可维护性和复用性。以下是编写 Ansible Role 的一些实用技巧和思路:
前期规划
明确功能边界
在开始编写 Role 之前,要精准定义该 Role 的功能。例如,如果要创建一个 nginx Role,就需明确它仅负责 Nginx 的安装、配置与启动,还是也涵盖虚拟主机的管理等。功能边界清晰,能避免 Role 过于庞大复杂,提高复用性。
分析依赖关系
确定 Role 所依赖的其他组件或角色。比如,安装 Nginx 可能依赖于特定版本的 OpenSSL,此时就要在 Role 中处理好这些依赖,确保安装过程顺利。
目录结构与文件编写
遵循标准目录结构
按照 Ansible 推荐的标准目录结构组织 Role,如下所示:
roles/
└── role_name/
├── defaults/
│ └── main.yml
├── files/
├── handlers/
│ └── main.yml
├── meta/
│ └── main.yml
├── tasks/
│ └── main.yml
├── templates/
└── vars/
└── main.yml
每个目录都有其特定用途,遵循此结构能让 Role 更易于理解和维护。
编写 defaults/main.yml
在该文件中定义 Role 的默认变量。这些变量应具有通用性,且易于被外部覆盖。例如:
# defaults/main.yml
nginx_port: 80
nginx_user: "www-data"
编写 tasks/main.yml
这是 Role 的核心文件,用于定义主要任务。任务应简洁明了,每个任务都要有清晰的描述。例如:
# tasks/main.yml
- name: Install Nginx
apt:
name: nginx
state: present
- name: Start Nginx service
systemd:
name: nginx
state: started
enabled: yes
编写 handlers/main.yml
处理程序通常用于重启服务等操作,在配置文件变更时被触发。例如:
# handlers/main.yml
- name: Restart Nginx
systemd:
name: nginx
state: restarted
编写 meta/main.yml
定义 Role 的元数据和依赖关系。例如:
# meta/main.yml
galaxy_info:
author: your_name
description: A role to install and configure Nginx
license: MIT
min_ansible_version: 2.9
dependencies:
- role: common
vars:
some_variable: value
变量使用与管理
合理使用变量
变量能让 Role 更具灵活性。尽量使用变量来配置 Role 中的关键参数,如软件版本、端口号等。例如:
# tasks/main.yml
- name: Configure Nginx port
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
vars:
nginx_port: "{{ nginx_port | default(80) }}"
notify:
- Restart Nginx
变量优先级管理
了解变量的优先级顺序,如命令行传递的变量优先级最高,defaults 中的变量优先级最低。合理利用这一特性,确保变量值符合预期。
模板使用
采用 Jinja2 模板
对于需要根据不同环境进行定制的配置文件,使用 Jinja2 模板。例如,nginx.conf.j2 模板文件:
# templates/nginx.conf.j2
server {
listen {{ nginx_port }};
server_name _;
...
}
错误处理与测试
错误处理
在任务中添加错误处理机制,如使用 ignore_errors 或 failed_when 等参数。例如:
# tasks/main.yml
- name: Check Nginx configuration
shell: nginx -t
register: nginx_check
ignore_errors: yes
- name: Fail if Nginx configuration is invalid
fail:
msg: "Nginx configuration is invalid"
when: nginx_check.rc != 0
测试 Role
编写测试用例对 Role 进行测试。可以使用 Molecule 等工具来自动化测试过程,确保 Role 在不同环境下都能正常工作。
文档编写
详细文档说明
为 Role 编写详细的文档,包括 Role 的功能、使用方法、可用变量及默认值等。良好的文档能让其他用户更容易理解和使用你的 Role。例如:
# Nginx Role
## 功能
该 Role 用于在目标主机上安装、配置和启动 Nginx 服务。
## 使用方法
在 Playbook 中引用该 Role:
```yaml
- name: Deploy Nginx
hosts: web_servers
roles:
- nginx
可用变量
| 变量名 | 默认值 | 描述 |
|---|---|---|
nginx_port |
80 | Nginx 监听端口 |
nginx_user |
www-data | Nginx 运行用户 |
通过以上技巧和思路,你可以编写出高质量、可维护且复用性强的 Ansible Role。
ansible-role介绍
role、角色用于层次化、结构化的组织多个playbook。
role主要的作用是可以单独的通过一个有组织的结构、通过单独的目录管理如变量、文件、任务、模块、以及处理任务等,并且可以通过include导入使用这些目录。
roles主要依赖于目录的命名和摆放,默认tasks/main.yml是所有任务的人口,使用roles的过程也可以认为是目录规范化命名的过程。
roles每个目录下均由main.yml定义该功能的任务集,tasks/main.yml默认执行所有定义的任务;
roles目录建议放在ansible.cfg中”roles_path”定义的目录下。
[root@master-61 /etc/ansible/roles]#grep 'roles_path' /etc/ansible/ansible.cfg
#roles_path = /etc/ansible/roles
角色目录规划
Ansible Role 有一套标准的目录结构,它将不同类型的文件和配置项进行了合理的分类,使得角色的管理、维护和复用变得更加方便。以下是详细的角色目录规划及各部分的作用:
标准角色目录结构
roles/
└── <role_name>/
├── defaults/
│ └── main.yml
├── files/
├── handlers/
│ └── main.yml
├── meta/
│ └── main.yml
├── tasks/
│ └── main.yml
├── templates/
├── tests/
│ ├── inventory
│ └── test.yml
└── vars/
└── main.yml
各目录及文件说明
1. defaults 目录
- 用途:存放角色的默认变量。这些变量具有最低的优先级,在运行时可以被其他地方定义的同名变量覆盖。通常用于设置一些通用的、可被用户自定义的参数。
- 示例文件:
defaults/main.yml# 定义 Nginx 服务的默认监听端口 nginx_port: 80 # 定义 Nginx 运行的默认用户 nginx_user: "www-data"
2. files 目录
- 用途:存放需要复制到目标主机的静态文件,例如配置文件、脚本等。这些文件在复制过程中不会进行内容的动态替换。
- 示例场景:如果你有一个自定义的
nginx.conf文件需要部署到目标主机,可以将其放在该目录下。
3. handlers 目录
- 用途:定义角色的处理程序(Handlers)。处理程序是在任务执行过程中被触发的特殊任务,通常用于重启服务、重新加载配置等操作。只有当与之关联的任务的状态为
changed时,处理程序才会被执行。 - 示例文件:
handlers/main.yml```yaml - name: Restart Nginx systemd: name: nginx state: restarted ```
4. meta 目录
- 用途:包含角色的元数据,如角色的作者信息、描述、依赖关系等。依赖关系的定义可以确保在使用该角色时,其依赖的其他角色会被先执行。
- 示例文件:
meta/main.yml```yaml galaxy_info: author: your_name description: A role to install and configure Nginx license: MIT min_ansible_version: 2.9
dependencies:
- role: common vars: some_variable: value ```
5. tasks 目录
- 用途:定义角色的主要任务。这些任务将按顺序执行,是角色的核心部分。任务可以调用各种 Ansible 模块来完成具体的操作,如安装软件、创建文件等。
- 示例文件:
tasks/main.yml```yaml name: Install Nginx apt: name: nginx state: present
name: Start Nginx service systemd: name: nginx state: started enabled: yes ```
6. templates 目录
- 用途:存放 Jinja2 模板文件。模板文件可以根据变量动态生成配置文件,使得配置文件可以根据不同的环境或需求进行定制。
- 示例场景:一个动态生成的
nginx.conf.j2模板文件,根据nginx_port变量来设置监听端口。server { listen ; server_name _; ... }
7. tests 目录
- 用途:用于存放角色的测试相关文件,包括测试用的清单文件(
inventory)和测试 Playbook(test.yml)。可以使用工具如Molecule结合这些文件对角色进行自动化测试,确保角色在不同环境下都能正常工作。 - 示例文件:
tests/inventory:定义测试用的主机清单。tests/test.yml:包含用于测试角色功能的任务。
8. vars 目录
- 用途:包含角色的变量。这些变量的优先级高于
defaults中的变量,但低于命令行传递的变量和在 Playbook 中定义的变量。通常用于设置一些与角色紧密相关,但又不适合作为默认值的变量。 - 示例文件:
vars/main.yml# 定义 Nginx 配置文件的路径 nginx_conf_path: "/etc/nginx/nginx.conf"
通过遵循这样的目录规划,你可以更清晰地组织 Ansible Role 的代码,提高角色的可维护性和复用性。
先来看一个role的结构化目录吧。
一个完整的roles是由task、handlers、files、vars、templates、meta等一系列目录组成,各目录存放不同的文件实现不同的功能,在调用时直接下文件名即可调用。
参考官网即可,且必须按照如下的目录格式来,不是随便定义的
https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-directory-structure
Ansible 角色具有定义的目录结构,其中包含八个主要的标准目录。您必须在每个角色中至少包含其中一个目录。您可以省略角色不使用的任何目录。例如如下的官网示例
# playbooks
site.yml
webservers.yml
fooservers.yml
roles/
common/
tasks/
handlers/
library/
files/
templates/
vars/
defaults/
meta/
webservers/
tasks/
defaults/
meta/
默认情况下,Ansible 将在角色中的每个目录中main.yml查找相关内容的文件(也main.yaml和main):
tasks/main.yml- 角色执行的任务的主要列表。handlers/main.yml- 处理程序,可以在此角色内部或外部使用。library/my_module.py- 可在此角色中使用的模块(有关更多信息,请参阅在角色中嵌入模块和插件)。defaults/main.yml- 角色的默认变量(有关更多信息,请参阅使用变量)。这些变量在所有可用变量中具有最低优先级,并且可以很容易地被任何其他变量(包括库存变量)覆盖。vars/main.yml- 角色的其他变量(有关更多信息,请参阅使用变量)。files/main.yml- 角色部署的文件。templates/main.yml- 角色部署的模板。meta/main.yml- 角色的元数据,包括角色依赖项。
role部署nginx
下面为你详细介绍使用 Ansible Role 部署 Nginx 的完整案例,包含角色的目录结构、各文件内容及使用方法。
1. 创建角色目录结构
首先,创建一个名为 nginx 的角色目录,其标准结构如下:
roles/
└── nginx/
├── defaults/
│ └── main.yml
├── files/
├── handlers/
│ └── main.yml
├── meta/
│ └── main.yml
├── tasks/
│ └── main.yml
├── templates/
└── vars/
└── main.yml
2. 编写各目录下的文件
defaults/main.yml
此文件用于定义角色的默认变量,可被外部变量覆盖。
# 定义 Nginx 监听端口
nginx_port: 80
# 定义 Nginx 运行的用户
nginx_user: "www-data"
handlers/main.yml
该文件定义处理程序,在配置文件变更时触发服务重启。
- name: Restart Nginx
systemd:
name: nginx
state: restarted
meta/main.yml
此文件包含角色的元数据和依赖关系。
galaxy_info:
author: Your Name
description: A role to install and configure Nginx
license: MIT
min_ansible_version: 2.9
dependencies: []
tasks/main.yml
这是角色的核心文件,定义主要任务。
- name: Update apt cache (for Ubuntu)
apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Install Nginx (for Ubuntu)
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Install Nginx (for CentOS)
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"
- name: Create Nginx configuration from template
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Restart Nginx
- name: Start Nginx service
systemd:
name: nginx
state: started
enabled: yes
templates/nginx.conf.j2
该模板文件根据变量动态生成 Nginx 配置文件。
user {{ nginx_user }};
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen {{ nginx_port }};
server_name _;
location / {
root /var/www/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html;
}
}
}
vars/main.yml
这里可定义一些特定于角色的变量。
# 定义 Nginx 配置文件的路径
nginx_conf_path: "/etc/nginx/nginx.conf"
3. 使用角色的 Playbook
创建一个 Playbook 文件(例如 deploy_nginx.yml)来使用这个角色。
---
- name: Deploy Nginx
hosts: web_servers
become: true
roles:
- nginx
4. 运行 Playbook
假设你的主机清单文件为 hosts.ini,包含 web_servers 主机组,可使用以下命令运行 Playbook:
ansible-playbook -i hosts.ini deploy_nginx.yml
说明
- 兼容性:上述案例考虑了 Ubuntu(Debian 系)和 CentOS(RedHat 系)系统,根据
ansible_os_family变量选择合适的包管理工具进行 Nginx 安装。 - 变量覆盖:如果需要修改默认的
nginx_port或nginx_user变量,可以在 Playbook 中传递新的变量值,例如: ```yaml
- name: Deploy Nginx
hosts: web_servers
become: true
roles:
- role: nginx vars: nginx_port: 8080 nginx_user: "nginxuser" ```
通过以上步骤,你可以使用 Ansible Role 方便地在多台主机上部署和配置 Nginx。
role综合案例
# yuchaoit.cn ansible-role
site.yml # role入口
nfs_servers.yml # role
rsync_servers.yml # role
roles/ # role规范目录结构
nfs_servers/ # role具体名字
tasks/ # 剧本任务
handlers/ # 剧本里存放的handlers
files/ # 如压缩文件,如需要拷贝的文件
templates/ # 存放配置文件
vars/ # 存放变量文件
rsync_servers/
tasks/
handlers/
files/
templates/
vars/

实践1:部署rsyncd服务
0.思路
1.写好剧本
2.创建角色的目录结构
3.拷贝需要操作的文件对应的结构目录下
4.拆分剧本
1.rsync剧本
- hosts: backup
vars:
user_id: '666'
rsync_user: 'www'
tasks:
# 1.创建www用户和组
- name: 01_create_group
group:
name: "{{ rsync_user }}"
gid: "{{ user_id }}"
# 2.创建www用户
- name: 02_create_user
user:
name: "{{ rsync_user }}"
gid: "{{ user_id }}"
group: "{{ rsync_user}}"
create_home: no
shell: /sbin/nologin
# 3.创建数据目录且授权
- name: 03_createUdata
file:
path: "{{ item }}"
state: direcotry
owner: "{{ rsync_user }}"
group: "{{ rsync_user}}"
mode: "755"
loop:
- /data
- /backup
# 4.安装rsync软件
- name: 04_install_rsync
yum:
name: rsync
state: latest
# 5.复制配置文件与密码文件
- name: 05_copy_config
copy:
src: "{{ item.src }}"
dest: /etc/
mode: "{{ item.mode }}"
notify:
- restart_rsyncd
loop:
- { src:/script/rsyncd.conf,mode:'644'}
- { src:/script/rsync.passwd,mode:'600'}
# 6.启动服务
- name: 06_start_rsync
systemd:
name: rsyncd
state: started
enabled: yes
# 7.重启服务
handlers:
- name: restart_rsyncd
systemd:
name: rsyncd
state: restarted
2.创建role结构目录
[root@master-61 /etc/ansible/roles]#mkdir -p rsync_server/{tasks,handlers,files,templates,vars}
[root@master-61 /etc/ansible/roles]#tree
.
└── rsync_server
├── files
├── handlers
├── tasks
├── templates
└── vars
6 directories, 0 files
[root@master-61 /etc/ansible/roles]#
3.创建playbook到tasks目录
任务么,就是安装rsync服务,生成main.yml即可
tasks/main.yml
- name: install rsync
hosts: backup
tasks:
- name: 01-yum
yum:
name: rsync
state: installed
- name: 03-group
group:
name: www
gid: 1000
- name: 03-user
user:
name: www
uid: 1000
group: www
create_home: no
shell: /sbin/nologin
- name: 04-file
file:
path: /backup
owner: www
group: www
state: directory
- name: 05-copy
copy:
src: "{{ item.src }}"
dest: /etc/
mode: "{{ item.mode }}"
loop:
- { src: '/script/rsyncd.conf', mode: '0644' }
- { src: '/script/rsync.passwd', mode: '0600' }
notify:
- restart rsyncd
- name: 07-systemd
systemd:
name: rsyncd
state: started
handlers:
- name: restart rsyncd
systemd:
name: rsyncd
state: restarted
4. 配置文件放入到files目录
files目录结构
[root@master-61 /etc/ansible/roles/rsync_server/tasks]#tree /etc/ansible/roles/rsync_server/
/etc/ansible/roles/rsync_server/
├── files
│ ├── rsyncd.conf
│ └── rsync.passwd
├── handlers
├── tasks
│ └── main.yml
├── templates
└── vars
5 directories, 3 files
Rsync.passwd
[root@master-61 /etc/ansible/roles/rsync_server]#cat files/rsync.passwd
rsync_backup:yuchao666
rsyncd.conf
[root@master-61 /etc/ansible/roles/rsync_server]#cat files/rsyncd.conf
uid = www
gid = www
port = 873
fake super = yes
use chroot = no
max connections = 200
timeout = 600
ignore errors
read only = false
list = false
auth users = rsync_backup
secrets file = /etc/rsync.passwd
log file = /var/log/rsyncd.log
[mybackup]
comment = chaoge rsync backup!
path = /backup
[data]
comment = yuchaoit.cn rsync!
path = /data
5.拆分handlers
rsync用到的handlers就是在修改完配置文件后,必须要重启这个任务
原本写在单个的大剧本中,现在可以单独写出来然后维护
[root@master-61 /etc/ansible/roles/rsync_server]#cat handlers/main.yml
- name: restart rsyncd
systemd:
name: rsyncd
state: restarted
6.拆分vars
提取出安装rsync脚本中使用到的变量,如用户信息
[root@master-61 /etc/ansible/roles/rsync_server]#cat vars/main.yml
user_id: '666'
rsync_user: 'www'
7. 优化tasks任务文件main.yml
超哥教你写role的口诀
该拆的全给拆开
如何拆,以role提供的目录结构拆,对应着拆
- 对应的目录填入对应的数据
- 内容需要反复写的定义为变量
- 如果要填写多个数据,如文件列表,可以写loop循环
# 1.创建www组
- name: 01_create_group
group:
name: "{{rsync_user}}"
gid: "{{user_id}}"
# 2.创建www用户
- name: 02_create_user
user:
name: "{{rsync_user}}"
uid: "{{user_id}}"
group: "{{rsync_user}}"
create_home: no
shell: /sbin/nologin
# 3.创建数据目录并更改授权
- name: 03_create_data
file:
path: "{{item}}"
state: directory
owner: "{{rsync_user}}"
group: "{{rsync_user}}"
mode: '755'
loop:
- /data
- /backup/
# 4.安装rsync软件
- name: 04_install_rsync
yum:
name: rsync
state: latest
# 5.复制文件
- name: 05-copy config
copy:
src: "{{item.src}}"
dest: /etc
mode: "{{item.mode}}"
notify:
- restart rsyncd
loop:
- {src: rsyncd.conf,mode: '644'}
- {src: rsync.passwd,mode: '600'}
# 6. 启动服务
- name: start service
systemd:
name: rsyncd
state: started
enabled: yes
8.编写启动role文件
- 注意启动文件的路径,和roles平级
- 最终是以tasks/main.yml作为入口
[root@master-61 /etc/ansible]#cat /etc/ansible/rsync_server.yml
- hosts: backup
roles:
- rsync_server
9.检查roles所有文件
[root@master-61 /etc/ansible]#tree /etc/ansible/roles/rsync_server/
/etc/ansible/roles/rsync_server/
├── files
│ ├── rsyncd.conf
│ └── rsync.passwd
├── handlers
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
└── vars
└── main.yml
5 directories, 5 files
10.调试运行role
[root@master-61 /etc/ansible]#ansible-playbook -C rsync_server.yml
实际执行,安装rsync服务
[root@master-61 /etc/ansible]#ansible-playbook rsync_server.yml
至此,关于安装rsync服务的roles已经写好了,主要就是区别于纯手写plabook,解决纯playbook的问题
- 提供files、handlers、tasks、vars单独放置各自需要的yaml
- 把一个臃肿的大playbook,拆成小部分,分门别类的管理。
实践2:部署sshd服务
1.思路
1.需要新知识role中提供的template模板功能,编写j2文件
2.主体功能写在tasks中
3.调试运行
2.创建新的role目录
[root@master-61 /etc/ansible]#cd roles/
[root@master-61 /etc/ansible/roles]#mkdir sshd_server/{tasks,handlers,files,templates,vars} -p
3.编写jinja2模板文件
这是一个特有的模板语言,主要作用就是能让普通的文件,能读取程序设置的变量,用模板语法,动态替换数据。
语法规则
1.必须是以.j2结尾的文件
2.必须放入在template目录下
3.使用的ansible模块是template模块
实践
1.拷贝sshd配置文件,改名为.j2后缀,放入template目录
[root@master-61 /etc/ansible/roles]#cp /etc/ssh/sshd_config /etc/ansible/roles/sshd_server/templates/sshd_config.j2
2.修改配置文化语法,替换为jinja2的语法
比如你部署一个sshd服务,你希望动态的修改sshd的端口,那么配置文件就不能写死固定的数字;
而可以采用
- j2模板文件
- 变量文件
- 两者结合,实现在ansible部署中,方便的修改配置文件
[root@master-61 /etc/ansible/roles]#grep '^Port' /etc/ansible/roles/sshd_server/templates/sshd_config.j2
Port {{ ssh_port }}
4.编写变量文件
角色定义的yml文件,就无须再写vars关键字定义变量, 默认通过这个文件夹就可以识别是变量文件了
[root@master-61 /etc/ansible/roles/sshd_server]#cat vars/main.yml
ssh_port: '22'
5.编写handlers文件
用于确保修改配置文件后,重启服务的任务
[root@master-61 /etc/ansible/roles/sshd_server]#cat handlers/main.yml
- name: restart sshd
systemd:
name: sshd
state: restarted
6.编写主任务tasks文件
启动sshd服务的主体剧本如下,只不过以前所有的参数都是固定写死的,现在全拆开了,更容易修改了
细节提示
- 配置文件的拷贝,不是copy固定死的文件内容,而是template模块,利用j2模板文件,动态设置配置文件的值
[root@master-61 /etc/ansible/roles/sshd_server]#cat tasks/main.yaml
# 1.复制文件
- name: 01_copy_sshd
template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
mode: '600'
backup: yes
notify:
- restart sshd
# 2.启动服务
- name: start sshd service
systemd:
name: sshd
state: started
enabled: yes
7.最终roles目录
[root@master-61 /etc/ansible/roles/sshd_server]#tree
.
├── files
├── handlers
│ └── main.yml
├── tasks
│ └── main.yaml
├── templates
│ └── sshd_config.j2
└── vars
└── main.yml
8.编写启动role文件
注意该文件,存放于/etc/ansible下,和roles同级
[root@master-61 /etc/ansible]#cat sshd_server.yml
- hosts: backup
roles:
- sshd_server
[root@master-61 /etc/ansible]#ls
ansible.cfg hosts roles rsync_server.yml sshd_server.yml
9.调试测试role
确保没有错误,可以正确发生change修改动作即可。
[root@master-61 /etc/ansible]#ansible-playbook -C sshd_server.yml
实践3: 部署nfs服务
1.思路
1.拷贝nfs服务端配置文件,生成templates目录下的j2模板文件,用于变量替换配置文件信息
2.编写handlers
3.编写tasks
4.编写vars
5.编写role启动文件
2.创建role目录结构
[root@master-61 /etc/ansible/roles]#mkdir nfs_server/{tasks,handlers,files,templates,vars} -p
3.创建jinja模板文件
[root@master-61 /etc/ansible/roles]#cat nfs_server/templates/exports.j2
/data {{ server_ip }}(rw,sync,all_squash,anonuid=66,anongid=666)
4.创建变量文件
[root@master-61 /etc/ansible/roles]#cat nfs_server/vars/main.yml
server_ip: '172.16.1.0/24'
5.编写handlers文件
[root@master-61 /etc/ansible/roles]#cat nfs_server/handlers/main.yml
- name: restart nfs
systemd:
name: nfs
state: restarted
6.编写tasks任务文件
[root@master-61 /etc/ansible/roles]#vim nfs_server/tasks/main.yml
# 1.创建www组
- name: 01-add group
group:
name: www
gid: '666'
# 2.创建www用户
- name: 02-useradd
user:
name: www
create_home: no
shell: /sbin/nologin
uid: '666'
# 3.安装nfs
- name: 03-nfs install
yum:
name: nfs-utils
state: latest
# 4.拷贝配置文件
- name: 04-cp
template:
src: exports.j2
dest: /etc/exports
notify:
- restart nfs
# 5.创建数据目录且授权
- name: create data dir
file:
path: "{{ item }}"
state: directory
owner: www
group: www
mode: '755'
loop:
- /data
- /backup
# 6. 启动rpcbind服务
- name: start prcbind
service:
name: rpcbind
state: started
# 7.启动nfs服务
- name: start nfs
service:
name: nfs
state: started
# 8.开机启动
- name: enable rpcbind
systemd:
name: rpcbind
enabled: yes
- name: enable nfs
systemd:
name: nfs
enabled: yes
7.编写启动role文件
注意就是roles的值,和roles目录下的文件夹对应
[root@master-61 /etc/ansible/roles]#cat /etc/ansible/nfs_server.yml
- hosts: nfs
roles:
- nfs_server
8.测试role执行
[root@master-61 /etc/ansible/roles]#ansible-playbook -C /etc/ansible/nfs_server.yml
总结roles角色用法
1.roles有固定的格式,需要创建固定的文件夹结构,以及每个文件夹都对应的固定的作用
2.写roles其实就是改造、拆分以前写的部署服务的playbook
3.最后就是注意细节,语法,别敲错了单词,出错了看日志报错,对应出错的文件,按照正确规则,编写即可
4.动手练习,完成rsyncd,nfs,sshd服务的部署,理解roles的用法
生产环境下的ansible-role
给大家看看于超老师维护的role,了解下为什么让你学role,以及给你讲解这些知识点,理解role的目录结构。
1.ansible总目录

2.涉及的组件列表
也就30多个吧,花一个月把剧本全看明白就行了,没什么高级用法,都是超哥讲解的ansible模块,以及那些高级语法。
- ansible模块
- playbook语法、yaml、高级语法
- role规范

3.听超哥指挥,能打胜仗
我说的对吗 老铁们。
[汗]这个图的意思就是想告诉你们,工作里的运维部署内容,必然会更复杂,更多,但是只要你把课堂上讲的语法学会,作业做出来,就能搞定工作里的活。也就是我贴的这个图,里面的语法应该是能看懂的吧。
然后就是拿着这个剧本去部署公司的产品,出了问题,自己要会修改这个剧本
4.例如安装mysql的角色
以下是一个用于在生产环境中部署和配置 MySQL 的 Ansible Role 案例,包含了详细的目录结构、各文件内容及使用说明。
1. 角色目录结构
roles/
└── mysql/
├── defaults/
│ └── main.yml
├── files/
├── handlers/
│ └── main.yml
├── meta/
│ └── main.yml
├── tasks/
│ └── main.yml
├── templates/
└── vars/
└── main.yml
2. 各目录及文件详细内容
defaults/main.yml
定义角色的默认变量,可在使用角色时被覆盖。
# MySQL 版本,可根据实际需求修改
mysql_version: 8.0
# MySQL root 用户密码
mysql_root_password: "default_root_password"
# MySQL 数据目录
mysql_data_dir: "/var/lib/mysql"
# MySQL 配置文件路径
mysql_conf_path: "/etc/mysql/mysql.conf.d/mysqld.cnf"
handlers/main.yml
定义处理程序,用于在 MySQL 配置文件变更时重启服务。
- name: Restart MySQL
systemd:
name: mysql
state: restarted
meta/main.yml
包含角色的元数据和依赖关系。
galaxy_info:
author: Your Name
description: A role to install and configure MySQL in production environment
license: MIT
min_ansible_version: 2.9
dependencies: []
tasks/main.yml
角色的核心任务文件,包含安装、配置和初始化 MySQL 的任务。
- name: Update apt cache (for Ubuntu)
apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Install MySQL (for Ubuntu)
apt:
name: "mysql-server-{{ mysql_version }}"
state: present
when: ansible_os_family == "Debian"
- name: Install MySQL (for CentOS)
yum:
name: "mysql-server-{{ mysql_version }}"
state: present
when: ansible_os_family == "RedHat"
- name: Create MySQL configuration from template
template:
src: mysqld.cnf.j2
dest: "{{ mysql_conf_path }}"
notify:
- Restart MySQL
- name: Start and enable MySQL service
systemd:
name: mysql
state: started
enabled: yes
- name: Secure MySQL installation
mysql_secure_installation:
login_user: root
login_password: "{{ mysql_root_password }}"
remove_anonymous_users: yes
disallow_root_login_remotely: yes
remove_test_database: yes
reload_privilege_tables: yes
ignore_errors: true
- name: Set root password
mysql_user:
name: root
password: "{{ mysql_root_password }}"
login_unix_socket: /var/run/mysqld/mysqld.sock
templates/mysqld.cnf.j2
Jinja2 模板文件,用于生成 MySQL 配置文件。
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = {{ mysql_data_dir }}
log-error = /var/log/mysql/error.log
bind-address = 0.0.0.0
# 字符集设置
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# 其他配置参数,可根据生产环境需求调整
max_connections = 200
innodb_buffer_pool_size = 512M
vars/main.yml
定义特定于角色的变量,可覆盖默认变量。
# 可根据实际情况添加更多特定变量
3. 使用该角色的 Playbook
创建一个名为 deploy_mysql.yml 的 Playbook 文件来使用这个角色。
---
- name: Deploy MySQL in production
hosts: mysql_servers
become: true
roles:
- mysql
4. 运行 Playbook
假设你的主机清单文件为 hosts.ini,其中包含 mysql_servers 主机组,使用以下命令运行 Playbook:
ansible-playbook -i hosts.ini deploy_mysql.yml
注意事项和说明
- 兼容性:该案例同时支持 Ubuntu(Debian 系)和 CentOS(RedHat 系)系统,根据
ansible_os_family变量选择合适的包管理工具进行 MySQL 安装。 - 密码安全:在实际生产环境中,建议使用 Ansible Vault 来加密敏感信息,如
mysql_root_password,以提高安全性。 - 配置调整:
templates/mysqld.cnf.j2中的配置参数可根据生产环境的具体需求进行调整,如max_connections、innodb_buffer_pool_size等。 - 错误处理:在
tasks/main.yml中,mysql_secure_installation任务使用了ignore_errors: true,这是因为在某些情况下,如已经进行过安全初始化,再次执行可能会报错。你可以根据实际情况调整错误处理逻辑。
通过以上步骤,你可以使用 Ansible Role 在生产环境中高效地部署和配置 MySQL。

Jinja2
下面为你提供一个 Ansible Playbook 结合 Jinja2 的完整案例,此案例用于在多台服务器上部署并配置 Nginx,借助 Jinja2 模板动态生成 Nginx 配置文件。
1. 项目结构
ansible-project/
├── inventory.ini
├── nginx-playbook.yml
├── roles/
│ └── nginx/
│ ├── defaults/
│ │ └── main.yml
│ ├── templates/
│ │ └── nginx.conf.j2
│ └── tasks/
│ └── main.yml
2. 各文件详细内容
inventory.ini
该文件定义了目标主机列表。
[web_servers]
server1.example.com
server2.example.com
nginx-playbook.yml
这是主 Playbook 文件,用于调用 nginx 角色。
---
- name: Deploy and Configure Nginx
hosts: web_servers
become: true
roles:
- nginx
roles/nginx/defaults/main.yml
此文件定义了 nginx 角色的默认变量。
nginx_port: 80
nginx_server_name: _
nginx_root_dir: /var/www/html
roles/nginx/templates/nginx.conf.j2
这是 Jinja2 模板文件,用于生成 Nginx 配置文件。
user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen {{ nginx_port }};
server_name {{ nginx_server_name }};
location / {
root {{ nginx_root_dir }};
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root {{ nginx_root_dir }};
}
}
}
roles/nginx/tasks/main.yml
该文件定义了 nginx 角色的主要任务。
- name: Install Nginx
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Install Nginx
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"
- name: Generate Nginx configuration file
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Restart Nginx
- name: Start and enable Nginx service
systemd:
name: nginx
state: started
enabled: yes
handlers:
- name: Restart Nginx
systemd:
name: nginx
state: restarted
3. 案例说明
- 变量传递:在
roles/nginx/defaults/main.yml中定义了默认变量,这些变量可在 Jinja2 模板nginx.conf.j2中使用。如果需要修改默认值,可在 Playbook 中通过vars关键字传递新的变量值。 - 模板生成:
roles/nginx/tasks/main.yml中的template模块会使用 Jinja2 引擎将nginx.conf.j2模板文件根据变量动态生成实际的 Nginx 配置文件,并复制到目标主机的/etc/nginx/nginx.conf路径。 - 服务管理:使用
systemd模块启动并启用 Nginx 服务,当配置文件发生变化时,会触发Restart Nginx处理程序重启服务。
4. 运行 Playbook
在项目根目录下,使用以下命令运行 Playbook:
ansible-playbook -i inventory.ini nginx-playbook.yml
通过这个案例,你可以看到如何利用 Ansible Playbook 结合 Jinja2 模板动态生成配置文件,实现自动化部署和配置。