Ansible

Ansible is a radically simple IT automation system. It handles configuration management, application deployment, cloud provisioning, ad-hoc task execution, network automation, and multi-node orchestration. Ansible makes complex changes like zero-downtime rolling updates with load balancers easy. More information on the Ansible website.
Ansible 是一套软件工具,其可实现基础架构即程式码。它是开源软件,并且该套件包括软件供应、组态管理和应用程序部署等功能。
Ansible 是无代理的,借由透过 SSH 或允许 PowerShell 执行的 Windows 远端管理机制来建立临时远端连线。 Ansible 的控制节点在大多数已安装 Python 的类 Unix 系统上执行。系统组态部分是透过使用它自己的宣告式语言来定义的。
项目介绍说明
发展史
Ansible 最初由 Michael DeHaan 编写,于 2012-03-09 发布 0.0.1 版;并于 2015-10-17 年被 Red Hat(红帽)公司以 1.5 亿美元收购,其旨在自动化设定类 Unix 系统和 Microsoft Windows 的环境。
"ansible"一词是由 Ursula K. Le Guin(厄休拉・克罗伯・勒古恩)在她 1966 年的小说 Rocannon’s World(罗坎农的世界)中所创造的,指的是虚构的即时通讯系统。
特性
- 模块化:调用特定的模块完成特定任务,支持自定义模块,可使用任何编程语言写模块
- Paramiko(python 对 ssh 的实现)模块,PyYAML,Jinja2(模板语言)三个关键模块
- 基于 Python 语言实现
- 部署简单,基于 python 和 SSH (默认已安装),agentless,无需代理不依赖 PKI (无需ssl)
- 基于 OpenSSH
- 暴等性:一个任务执行 1 遍和执行 n 遍效果一样,不因重复执行带来意外情况
- 支持 playbook 编排任务,YAML 格式,编排任务,支持丰富的数据结构
- 较强大的多层解决方案 role
Ansible 主要组成
- PLAYBOOKS:任务剧本(任务集),编排定义 Ansible 任务集的配置文件,由 Ansible 顺序依次执行,通常是 JSON 格式的 YML 文件
- INVENTORY:Ansible 管理主机的清单 /etc/anaible/hosts
- MODULES:Ansible 执行命令的功能模块,多数为内置核心模块,也可自定义
- PLUGINS:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用
- API:供第三方程序调用的应用程序编程接口
官网
安装部署
准备工作
# 安装 epel (Fedora项目)维护的一个社区软件包仓库
[root@localhost ~]# dnf install epel-release -y
[root@localhost ~]# dnf info ansible
上次元数据过期检查:0:00:18 前,执行于 2025年06月21日 星期六 13时31分09秒。
可安装的软件包
名称 : ansible
时期 : 1
版本 : 7.7.0 # 精选集合的 ansible 软件包版本,不是 ansible-core 的版本
发布 : 1.el9
架构 : noarch
大小 : 34 M
源 : ansible-7.7.0-1.el9.src.rpm
仓库 : epel
概况 : Curated set of Ansible collections included in addition to ansible-core
URL : https://ansible.com
协议 : GPL-3.0-or-later AND Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND MIT AND MPL-2.0 AND PSF-2.0
描述 : Ansible is a radically simple model-driven configuration management,
: multi-node deployment, and remote task execution system. Ansible works
: over SSH and does not require any software or daemons to be installed
: on remote nodes. Extension modules can be written in any language and
: are transferred to managed machines automatically.
:
: This package provides a curated set of Ansible collections included in addition
: to ansible-core.
安装 Ansible 软件包
dnf install ansible -y
验证成功安装
2025-06-21 目前 Github 最新版本是 v2.18.6,epel 源中用的是 2.14.18 版本
[root@localhost ~]# ansible --version
ansible [core 2.14.18]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.9/site-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.9.19 (main, Sep 11 2024, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-2)] (/usr/bin/python3)
jinja version = 3.1.2
libyaml = True
[root@localhost ~]# which ansible
/usr/bin/ansible
# 查看可用的模块
[root@localhost ~]# ansible-doc -l | wc -l
7736
相关文件
配置文件
- /etc/ansible/ansible.cfg 主配置文件,配置 ansible 工作特性
- /etc/ansible/hosts 主机清单
- /etc/ansible/roles/ 存放角色的目录
ansible.cfg 主配置文件
Ansible 的配置文件 /etc/ansible/ansible.cfg,其中大部分的配置内容无需进行修改
# 生成 example 配置文件模板
[root@localhost ~]# ansible-config init --disabled > /etc/ansible/ansible.cfg
[root@localhost ~]# grep -v '^#' /etc/ansible/ansible.cfg | grep -v '^;' | grep -v '^$'
[defaults]
log_path=/var/log/ansible.log # # 设置日志文件保存位置,默认不保存日志
host_key_checking = False # 取消对 ssh key 的验证(免去首次ssh连接时输入yes的操作)
或:
# 将 ssh 配置文件中 33 行 StrictHostKeyChecking 的 ask 改成 no 即可
[root@localhost ~]# vim /etc/ssh/ssh_config
# StrictHostKeyChecking ask
hosts 主机配置文件
[root@localhost ~]# grep -v '^#' /etc/ansible/hosts | grep -v '^;' | grep -v '^$'
[centos]
192.168.110.136
[rocky]
192.168.110.129
192.168.110.132
相关工具
- /usr/bin/ansible:主程序,临时命令执行工具
- /usr/bin/ansible-doc:查看配置文档,模块功能查看工具,相当于 man 命令
- /usr/bin/ansible-playbook:定制自动化任务,编排剧本工具,相当于脚本
- /usr/bin/ansible-pull:远程执行命令的工具
- /usr/bin/ansible-vault:文件加密工具
- /usr/bin/ansible-console:基于 Console 界面与用户交互的执行工具
- /usr/bin/ansible-galaxy:下载/上传优秀代码或 Roles 模块的官网平台
利用 ansible 实现管理的主要方式:
- Ad-Hoc:即利用 ansible 命令,主要用于临时命令使用场景
- Ansible-playbook:主要用于长期规划好的大型项目的场景,需要有前期的规划过程
工具使用方式
ansible-doc
# -s 查看 ping 的关键用法
[root@localhost ~]# ansible-doc -s ping
- name: Try to connect to host, verify a usable python and return `pong' on success
ping:
data: # Data to return for the `ping' return value. If this parameter is set to `crash', the module will cause an exception.
ansible
ansible 命令执行过程
- 加载配置文件,默认 /etc/ansible/ansible.cfg
- 加载自己对应的模块文件,如:command
- 通过 ansible 将模块或命令生成对应的临时 py 文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY 文件
- 给文件 +x 执行权限
- 执行并返回结果
- 删除临时 py 文件,退出
ansible <host-pattern> [-m module_name] [-a args]
选项说明:
--version #显示版本
-m module #指定模块,默认为command
-V #详细过程-VV-VVV更详细
--1ist-hosts #显示主机列表,可简写--list
-k,--ask-pass #提示输入ssh连接密码,默认Key验证
-C,--check #检查,并不执行
-T,--timeout=TIMEOUT #执行命令的超时时间,默认10s
-u,--user=REMOTE_USER #执行远程执行的用户
-b,--become #代替旧版的sudo切换
--become-user=USERNAME #指定sudo的runas用户,默认为root
-K,--ask-become-pass #提示输入sudo时的口令
基于密码验证连接主机使用 Ansible ping
# 列出管理的主机地址
[root@localhost ~]# ansible all --list
hosts (3):
192.168.110.136
192.168.110.129
192.168.110.132
[root@localhost ~]# ansible rocky --list
hosts (2):
192.168.110.129
192.168.110.132
# -k 使用密码验证
[root@localhost ~]# ansible all -k -m ping
SSH password: # 此处输入密码,每台被管理的主机密码必须相同
192.168.110.136 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.110.129 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
192.168.110.132 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
基于 Key 验证的脚步案例
push_ssh_key.sh 脚本
#!/bin/bash
# push_ssh_key.sh
# 使用数组定义 IP 地址,避免换行符问题
IPLIST=(
192.168.110.129
192.168.110.132
192.168.110.136
)
# 检查并安装 sshpass
rpm -q sshpass &> /dev/null || yum install sshpass -y
# 生成 SSH 密钥,如果不存在
[ -f /root/.ssh/id_rsa ] || ssh-keygen -t rsa -f /root/.ssh/id_rsa -N ''
# 设置 SSHPASS 环境变量
export SSHPASS=Root@2020
# 循环遍历 IP 地址列表
for IP in "${IPLIST[@]}"; do
# 使用 sshpass 和 ssh-copy-id 推送 SSH 密钥
sshpass -e /usr/bin/ssh-copy-id root@$IP
done
echo "SSH keys pushed to the following hosts:"
printf "%s\n" "${IPLIST[@]}"
执行脚本推送公钥到服务器
[root@localhost ~]# bash push_ssh_key.sh
Generating public/private rsa key pair.
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:pi3i+wqqsHw8M0B+f7rDbdQ2nzrBtQHnnTFkw7nCi+M root@localhost.localdomain
The key's randomart image is:
+---[RSA 3072]----+
| o+. |
| . ..=. |
| = . = |
| . * + |
|o S o = |
| o . = O o |
|. = + = + = . |
|oo O = = E o |
|=.. B*B .o |
+----[SHA256]-----+
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'root@192.168.110.129'"
and check to make sure that only the key(s) you wanted were added.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'root@192.168.110.132'"
and check to make sure that only the key(s) you wanted were added.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'root@192.168.110.136'"
and check to make sure that only the key(s) you wanted were added.
SSH keys pushed to the following hosts:
192.168.110.129
192.168.110.132
192.168.110.136
[root@localhost ~]# cat .ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDL1hmqIssxT5xm/Pb5SLtwmOqgpAIQkRzAWxhMYcENtcAGDqqcov/6vHsf4oYzmKBS5s5eA4U7X6WEfUacujur383F9ANZC8tP9p1hjEc3v5qBtyusMAhLawDBSe7aS3KGtz1TQBEwu+WDtmaaCE5Y81RfHS7s0PdCNAAf6GD9EILgFgJy4l3Y7TuNbilHE2AI+7T57SOFDjDQ7b+nP0X8bal9WZqXwsgx/8buwzTst/GT1FrNbXI0VApcRFLJPQXmGgqsBkzUMqZjFbZAuNyU93STc0pNQINMFNC0rjYzFR0FOVIN75Q8sLJe6tLIWjaEBK0RMw+T7SG6lhAnj5M3/1FN0EOAxfRWC2pZQjVzHZlpyukhB9YXuKKbqTN1Qzv1HjEpJZN/AMGZ6wYtZC2osm3/ZDt2V1Hl/RGHelTjFGYOcEfW4GWt+es7WmFKkEuQrsyYX06X3QF4ZMVoNoUrVzgJEDigRNq+lJMYrQPmcajsgmISF1oGrX7wQS63rMM= root@localhost.localdomain
无需输入密码连接主机
[root@ansible ~]# ansible all -m ping
192.168.110.136 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.110.132 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
192.168.110.129 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
# 重启除了 192.168.110.129 以外的所有主机
[root@ansible ~]# ansible 'all:!192.168.110.129' -a reboot
ansible-playbook
hello.yaml
# hello.yaml
- hosts: rocky
remote_user: root
tasks:
- name: hello world
command: /usr/bin/wall hello world!
[root@ansible ~]# ansible-playbook hello.yaml
PLAY [rocky] ************************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [192.168.110.132]
ok: [192.168.110.129]
TASK [hello world] ******************************************************************************************************************************************
来自 root@ansible (somewhere) (Sat Jun 21 15:50:46 2025) 的广播消息:
hello world!
changed: [192.168.110.132]
changed: [192.168.110.129]
PLAY RECAP **************************************************************************************************************************************************
192.168.110.129 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.110.132 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-vault
格式:
ansible-vault [--version] {create,decrypt,edit,view,encrypt,encrypt_string,rekey}
范例:
[root@ansible ~]# ansible-vault --version
ansible-vault [core 2.14.18]
#加密
[root@ansible ~]# ansible-vault encrypt hello.yaml
New Vault password:
Confirm New Vault password:
Encryption successful
#解密
[root@ansible ~]# ansible-vault decrypt hello.yaml
Vault password:
Decryption successful
#查看
[root@ansible ~]# ansible-vault view hello.yaml
#编辑加密文件
ansible-vault edit hello.yaml
#修改口令
ansible-vault rekey hello.yaml
#创建新文件
ansible-vault create hello.yaml
ansible-console
此工具可交互执行命令,支持 tab,ansible2.0+ 新增
提示符格式:
执行用户@当前操作的主机组(当前组的主机数量)[f:并发数]$
常用子命令:
- 设置并发数:forks n 例如:forks 10
- 切换组:cd 主机组 例如:cd centos
- 列出当前组主机列表:list
- 列出所有的内置命令:? 或 help
范例
[root@ansible ~]# ansible-console
Welcome to the ansible console. Type help or ? to list commands.
root@all (3)[f:5]$ list
192.168.110.136
192.168.110.129
192.168.110.132
root@all (3)[f:5]$ centos
root@all (3)[f:5]$ cd centos
root@centos (1)[f:5]$ list
192.168.110.136
root@centos (1)[f:5]$ ping
192.168.110.136 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
ansible-galaxy
此工具会连接 https://galaxy.ansible.com 下载相应的roles
范例:
#列出所有已安装的galaxy
ansible-galaxy list
#安装galaxy
ansible-galaxy install geerlingguy.mysq1
ansible-galaxy install geerlingguy.redis
#删除galaxy
ansible-galaxy remove geerlingguy.redis
常用模块
2015年底270多个模块,2016年达到540个,2018年01月12日有1378个模块,2018年07月15日1852个模块,2019年05月25日(ansible2.7.10)时2080个模块,2020年03月02日有3387个模块,2025年06月21日有7736个,虽然模块众多,但最常用的模块也就2,30个而已,针对特定业务只用10几个模块
常用模块帮助文档参考:https://docs.ansible.com/ansible/latest/module_plugin_guide/index.html
Command
功能:在远程主机执行命令,为 ansible 的默认模块,可省略 -m 选项
注意:此命令不支持$VARNAME <> | ; & 等,用 shell 模块实现
范例:
# 查看 ansible 使用的默认模块
[root@ansible ~]# cat /etc/ansible/ansible.cfg | grep 'module_name'
;module_name=command
[root@ansible ~]# ansible all -m command -a 'hostname'
192.168.110.136 | CHANGED | rc=0 >>
host2
192.168.110.132 | CHANGED | rc=0 >>
host1
192.168.110.129 | CHANGED | rc=0 >>
ansible
或:
[root@ansible ~]# ansible all -a 'hostname'
Shell
功能:和 command 相似,用 shell 执行命令(完美适配 Linux 命令)
范例:
[root@ansible ~]# ansible all -m shell -a "mkdir /data && echo Hellow World! > /data/hello.txt"
192.168.110.136 | CHANGED | rc=0 >>
192.168.110.129 | CHANGED | rc=0 >>
192.168.110.132 | CHANGED | rc=0 >>
[root@ansible ~]# ansible all -m shell -a "cat /data/hello.txt"
192.168.110.136 | CHANGED | rc=0 >>
Hellow World!
192.168.110.132 | CHANGED | rc=0 >>
Hellow World!
192.168.110.129 | CHANGED | rc=0 >>
Hellow World!
[root@ansible ~]# ansible all -m shell -a 'echo $HOSTNAME'
192.168.110.136 | CHANGED | rc=0 >>
host2
192.168.110.132 | CHANGED | rc=0 >>
host1
192.168.110.129 | CHANGED | rc=0 >>
ansible
# -vvv 显示执行的详细信息
[root@ansible ~]# ansible all -vvv -m shell -a 'pwd' > ansible.log
# 查看执行的信息中,最后 ansible 会删除/root/.ansible/tmp/目录中执行时的文件
[root@ansible ~]# cat ansible.log | grep 'rm -f -r'
<192.168.110.136> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/root/.ansible/cp/7708d1067a"' 192.168.110.136 '/bin/sh -c '"'"'rm -f -r /root/.ansible/tmp/ansible-tmp-1750516555.2640955-231392-54371291020814/ > /dev/null 2>&1 && sleep 0'"'"''
<192.168.110.129> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/root/.ansible/cp/6d9303b522"' 192.168.110.129 '/bin/sh -c '"'"'rm -f -r /root/.ansible/tmp/ansible-tmp-1750516555.355576-231393-47609501383121/ > /dev/null 2>&1 && sleep 0'"'"''
<192.168.110.132> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/root/.ansible/cp/0d0972515f"' 192.168.110.132 '/bin/sh -c '"'"'rm -f -r /root/.ansible/tmp/ansible-tmp-1750516555.3586736-231396-183365063470160/ > /dev/null 2>&1 && sleep 0'"'"''
Script
功能:在远程主机上运行 ansible 服务器上的脚本(无需拷贝脚本到远端主机、无需单独配置脚本权限)
范例:
[root@ansible ~]# echo "uname -a" > test.sh
[root@ansible ~]# ansible all -m script -a 'test.sh'
192.168.110.136 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.110.136 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.110.136 closed."
],
"stdout": "Linux host2 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux\r\n",
"stdout_lines": [
"Linux host2 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux"
]
}
192.168.110.129 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.110.129 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.110.129 closed."
],
"stdout": "Linux ansible 5.14.0-503.14.1.el9_5.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Nov 15 12:04:32 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux\r\n",
"stdout_lines": [
"Linux ansible 5.14.0-503.14.1.el9_5.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Nov 15 12:04:32 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux"
]
}
192.168.110.132 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.110.132 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.110.132 closed."
],
"stdout": "Linux host1 5.14.0-503.14.1.el9_5.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Nov 15 12:04:32 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux\r\n",
"stdout_lines": [
"Linux host1 5.14.0-503.14.1.el9_5.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Nov 15 12:04:32 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux"
]
}
Copy
功能:从 ansible 服务器主控端复制文件到 远程主机
# 如目标存在,默认覆盖,此处指定先备份
ansible all -m copy -a "src=/root/test.sh dest=/tmp/test1.sh owner=junlan mode=600 backup=yes"
# 指定内容,直接生成目标文件
ansible all -m copy -a "content='Hello World\nHello World2' dest=/tmp/test.txt"
# 将/data 目录一起复制,注意 /data 后面没有/
ansible all -m copy -a "src=/data dest=/backup"
# 只复制 /data 下的文件,不包括 /root 目录自身,注意 /data 后面有/
ansible websrvs -m copy -a "src=/etc/ dest=/backup"
Fetch
功能:从 远程主机 提取文件至 ansible 的主控端,和 copy 相反(不支持目录)
范例:
ansible all -m fetch -a "src=/etc/os-release dest=/backup/"
[root@ansible ~]# tree /backup
/backup
├── 192.168.110.129
│ └── etc
│ └── os-release
├── 192.168.110.132
│ └── etc
│ └── os-release
├── 192.168.110.136
│ └── etc
│ └── os-release
└── data
└── hello.txt
File
功能:设置文件属性,对文件的操作
# 创建文件
ansible all -m file -a "path=/data/file.log state=touch mode=000 owner=junlan"
# 创建目录
ansible all -m file -a "path=/data/folder state=directory"
# 删除目录
ansible all -m file -a "path=/data/folder state=absent"
# 创建软链接
ansible all -m file -a "src=/data/hello.txt state=link dest=/data/hello.txt.link"
[root@ansible ~]# ansible all -m shell -a "ls -l /data/"
192.168.110.136 | CHANGED | rc=0 >>
总用量 4
----------. 1 junlan root 0 6月 21 23:22 file.log
drwxr-xr-x. 2 root root 6 6月 21 23:25 folder
-rw-r--r--. 1 root root 14 6月 21 22:29 hello.txt
192.168.110.129 | CHANGED | rc=0 >>
总用量 4
----------. 1 junlan root 0 6月 21 23:22 file.log
drwxr-xr-x. 2 root root 6 6月 21 23:25 folder
-rw-r--r--. 1 root root 14 6月 21 22:29 hello.txt
192.168.110.132 | CHANGED | rc=0 >>
总用量 4
----------. 1 junlan root 0 6月 21 23:22 file.log
drwxr-xr-x. 2 root root 6 6月 21 23:25 folder
-rw-r--r--. 1 root root 14 6月 21 22:29 hello.txt
unarchive
功能:解包解压缩工
实现有两种用法:
1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes
2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
常用参数:
- copy:默认为 yes,当 copy=yes,拷贝的文件是从 ansible 主机复制到远程主机上,如果设置为copy=no,则在远程主机上寻找 src 源文件
- remote_src:和 copy 功能一样且互斥,yes 表示在远程主机,不在 ansible 主机,no 表示文件在ansible 主机上
- src:源路径,可以是 ansible 主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置 copy=no
- dest:远程主机上的目标路径
- mode:设置解压缩后的文件权限
# 创建压缩包
tar Jcvf data.xz /data
# 将 ansible 主机上的 data.xz 文件解压到目标主机的 /tmp 目录
ansible all -m unarchive -a 'src=data.xz dest=/tmp owner=junlan'
# 将文件拷贝到远程主机
ansible all -m copy -a 'src=/root/data.xz dest=/tmp'
# 在远程主机上将 /tmp/data.xz 解压到 /tmp 目录
ansible all -m unarchive -a 'src=/tmp/data.xz dest=/tmp owner=junlan copy=no'
# 原路径也可以是互联网路径
ansible all -m unarchive -a src=https://example.com/example.zip dest=/data copy=no'
Archive
功能:打包压缩保存到被管理节点
范例:
ansible all -m archive -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2 owner=junlan mode=0600'
Hostname
功能:管理主机名
范例:
ansible node1 -m hostname-a "name=websrv"
ansible 10.0.0.18 -m hostname -a 'name=node18.magedu.com'
DNF/YUM
功能:管理软件包,只支持 RHEL,CentOS,Fedora;Ubuntu 需要用 apt 模块
# 安装 iotop 和 cowsay 软件
ansible all -m dnf -a 'name=iotop,cowsay'
# 卸载 iotop 和 cowsay 软件
ansible all -m dnf -a 'name=iotop,cowsay state=absent'
# cowsay 软件包在 epel 有
[root@ansible ~]# cowsay I Love You!
_____________
< I Love You! >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Service
功能:管理服务
范例:
ansible all -m service -a 'name=httpd state=started enabled=yes'
ansible all -m service -a ' name=httpd state=stopped'
ansible all -m service -a 'name=httpd state=reloaded'
ansible all -m shell -a "sed -i's/AListen 80/Listen 8080/' /etc/httpd/conf/httpd. conf"
ansible all -m service -a 'name=httpd state=restarted'
User
功能:管理用户
范例:
#创建用户
ansible all -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1
group=root'
ansible all -m user -a 'name=nginx comment=nginx uid=88 group=nginx groups="root, daemon"
she11=/sbin/nologin system=yes create_home=no home=/data/nginx non_unique=yes'
#remove=yes表示删除用户及家目录等数据,默认remove=no
ansible all-m user -a 'name=nginx state=absent remove=yes'
Group
功能:管理组
范例:
#创建组
ansible all -m group -a 'name=nginx gid=88 s system=yes'
#删除组
ansible all -m group -a 'name=nginx state=absent'
Lineinfile
ansible在使用 sed 进行替换时,经常会遇到需要转义的问题,而且 ansible 在遇到特殊符号进行替换时,存在问题,无法正常进行替换。在 ansible 自身提供了两个模块:lineinfile 和 replace 模块,可以方便的进行替换
功能:相当于sed,可以修改文件内容
ansible 192.168.110.132 -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=disable'"
Setup
setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机较多,会影
响执行速度,可以使用 gather_facts: no 来禁止 Ansible 收集 facts 信息
范例:
# 输出所有信息
ansible all -m setup
# 只输出主机名
ansible all -m setup -a "filter=ansible_hostname"
# 只输出python版本
ansible all -m setup -a "filter=ansible_python_version"
ansible all-m setup-a"filter=ansible_domain"
ansible all -m setup -a "filter=ansible_memtotal_mb"
ansible all -m setup -a "filter=ansible_memory_mb"
ansible all -m setup -a "filter=ansible_memfree_mb"
ansible all -m setup -a "filter=ansible_os_family"
ansible all -m setup -a "filter=ansible_distribution_major_version"
ansible all -m setup -a "filter=ansible_distribution_version"
ansible all-m setup-a"filter=ansible_processor_vcpus"
ansible all-m setup -a "filter=ansible_all_ipv4_addresses"
ansible all -m setup -a "filter=ansible_architecture"
ansible all -m setup -a "filter=ansible_processor*"
Playbook
playbook 剧本是由一个或多个 “play” 组成的列表,采用YAML语言编写
play的主要功能在于将预定义的一组主机,装扮成事先通过 ansible 中的 task 定义好的角色。Task实际是调用 ansible 的一个 module,将多个 play 组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作。
YAMI
YAML(Yet Another Markup Language,仍是一种标记语言)是一个可读性高的用来表达资料序列的格式。
YAML参考了其他多种语言,包括:XML、C、Python、Perl 以及电子邮件格式 RFC2822 等。Clark Evans 在2001 年在首次发表了这种语言,另外 Ingy dot Net 与 Oren Ben-Kiki 也是这语言的共同设计者,目前很多软件中采有此格式的文件,如:ubuntu,anisble,docker,k8s等。YAML:YAML Ain’t Markup Language,即 YAML不是XML。YAML 官方网站:https://yaml.org/
YAML语言特性
- 可读性好
- 脚本语言的交互性好
- 使用实现语言的数据类型
- 有一个一致的信息模型
- 易于实现
- 可以基于流来处理
- 表达能力强,扩展性好
语法简介
YAML 的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用“-“来代表,Map里的键值对用”:"分隔。
- 在单一文件第一行,用连续三个连字号 “-” 开始,还有选择性的连续三个点号“…” 用来表示文件的结尾
- 次行开始正常写 Playbook 的内容,一般建议写明该 Playbook 的功能
- 使用 # 号注释代码
- 缩进必须是统一的,不能空格和 tab 混用
- 缩进的级别必须是一致,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现
- 内容区别大小写,key/value 的值均大小写敏感
- 多个 key/value 可同行写也可换行写,同行使用 , 分隔
- 一个 name 只能包括一个 task
List 列表
列表由多个元素组成,每个元素放在不同行,且元素前均使用“-"打头,或者将所有元素用[]括起来放在同一行
范例:
#不同行,行以-开头,后面有一个空格
#A list of tasty fruitsI
- Apple
- Orange
- strawberry
- Mango
#同一行
[Apple, orange, strawberry, Mango]
Dictionary 字典
字典由多个key与value构成,key和value之间用:分隔,所有k/v可以放在一行,或者每个k/v分别放在不同行
范例:
#不同行
# An employee record
name:ExampleDeveloper
job:Developer
ski11:Elite
#同一行,也可以将key:value放置于花括号中进行表示,用,分隔多个key:value
# An employee record
{name:"Example Developer", job: "Developer", ski11:"Elite"}}
三种常见的数据格式
- XML(Extensible Markup Language):可扩展标记语言,可用于数据交换和配置
- JSON(JavaScript Object Notation):JavaScript 对象表记法,主要用来数据交换或配置,不支持注释,常用于网络传输
- YAML(YAML Ain’t Markup Language YAML):不是一种标记语言,大小写敏感,不支持 tab,常用于配置文件
可以用工具互相转换,参考网站:
https://www.json2yaml.com/
http://www.bejson.com/json/json2yaml/
Playbook核心元素
一个 playbook 中由一个列表组成,到表的元素类型如下:
- Hosts 执行的远程主机列表
- Tasks 任务集,由多个 task 的元素组成的列表实现,每个 task 是一个字典
- Variables 内置变量或自定义变量在 playbook 中调用
- Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
- Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
- tags 标签指定某条任务执行,用于选择运行 playbook 中的部分代码。ansible 具有幕等性,因此会自动跳过;没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过 tags 跳过此些代码片断
- 一个完整的代码块功能需最少元素需包括name和task,一个name只能包括一个task
hosts 组件
Hosts:playbook 中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中。写法如下:
one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
Websrvs:dbsrvs #或者,两个组的并集
Websrvs:&dbsrvs #与,两个组的交集
webservers:!phoenix #在websrvs组,但不在dbsrvs组
- hosts: websrvs:appsrvs
remote_user组件
remote_user:可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: websrvs
remote_user: root
tasks:
- name: test connection
ping:
remote_user:magedu
sudo:yes #默认sudo为root
sudo_user:junlan #sudo为junlan
task列表和action组件
play 的主体部分是task list,task list 中有一个或多个 task,各个 task 按次序逐个在 hosts 中指定的所有主机上执行,即在所有主机上完成第一个 task 后,再开始第二个task
task 目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致
每个 task 都应该有其 name,用于 playbook 的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则 action 的结果将用于输出
task两种格式
(1) action:module arguments
(2) module:arguments 建议使用
注意:shell 和 command 模块后面跟命令,而非 key=value
playbook基本用法案例
yaml 文件
# install_http.yaml
---
- hosts: rocky
remote_user: root
tasks:
- name: 安装 nginx
dnf: name=nginx
- name : start nginx
service: name=nginx state=started enabled=yes
执行文件
# 检测 yaml 文件语法是否正确
ansible-playbook -C install_http.yaml
# 执行 playbook
ansible-playbook -C install_http.yaml
playbook命令
格式
ansible-playbook <filename.yml>... [options]
# 例:
ansible-playbook --list-hosts install_http.yaml
常见选项
-C--check #只检测可能会发生的改变,但不真正执行操作
--1ist-hosts #列出运行任务的主机
--list-tags #列出tag
--1ist-tasks #列出task
--1imit 主机列表 #只针对主机列表中的特定主机执行
-V-VV-VVV #显示过程
handlers和notify用法
Handlers 本质是task list,类似于MySQL中的触发器触发的行为,其中的 task 与前述的 task 并没有本质上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而 Notify 对应的 action 可用于在每个 play 的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在 notify 中列出的操作称为 handler,即 notify 中调用 handler 中定义的操作
案例:
# install_httpd.yaml
- hosts: rocky
remote_user: root
gather_facts: no
tasks:
- name: 安装Apache
dnf: name=httpd state=present
#- name: 修改配置文件
# copy: src=files/httpd.conf dest=/etc/httpd/conf/
- name : modify config
Lineinfile: path=/etc/httpd/conf/httpd.conf regexp='^Listen' Line='Listen 8080'
#- name: mkdir website dir
# file:path=/data/html state=directory
#- name: web html
# copy:src=files/index.html dest=/data/html/
- name: start service
service: name=httpd state=started enabled=yes
变量用法
使用已有的变量
# var1.yaml
- hosts: rocky
remote_user: root
gather_facts: yes
tasks:
- name: create log file
file: name=/data/{{ ansible_nodename }}-{{ ansible_distribution_major_version }}.log state=touch owner=junlan mode=600
使用自定义变量
案例1:通过-e 参数传递变量
[root@ansible ~]# cat var2.yaml
- hosts: rocky
remote_user: root
tasks:
- name: 安装指定的软件包
dnf: name={{ pkname }} state=present
ansible-playbook -e pkname=cowsay var2.yaml
[root@ansible ~]# cat var3.yaml
- hosts: rocky
remote_user: root
vars:
- username: user1
- groupname: group1
tasks:
- name: create group
group: name={{ groupname }}
- name: create user
user: name={{ username }} group={{ groupname }}
ansible-playbook var3.yaml
案例3:将变量存放在单独配置文件中
# vars.yaml
---
package_name: mariadb-server
service_name: mariadb
# cat var4.yaml
---
- hosts: rocky
remote_user: root
vars_files:
- /root/vars.yaml
tasks:
- name: install package
dnf: name={{ package_name }}
tags: install
- name: start service
service: name={{ service_name }} state=started enabled=yes
ansible-playbook var4.yaml
4.6.5主机清单文件中定义变量
4.6.5.1主机变量
在inventory主机清单文件中为指定的主机定义变量以便于在playbook中使用
范例:
[websrvs]
www1.magedu.com http_port=80 maxRequestsperchi1d=808
www2.magedu.com http_port=8080 maxRequestsperchild=909
4.6.5.2组(公共)变量
在inventory主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变是同名,优
级低于主机变量
范例:
[websrvs]
www1.magedu.com
www2.magedu.com
[websrvs:vars] I
ntp_server=ntp.magedu.com
nfs_server=nfs.magedu.com
Template(模板)模块
jinja2语言
jinja2 语言使用字面量,有下面形式:
- 字符串:使用单引号或双引号
- 数字:整数,浮点数
- 列表:[item1,item2,…]
- 元组:(item1,item2,…)
- 字典:{key1:value1,key2:value2,…}
- 布尔型:true/false
- 算术运算:+,-,*,/,//,%,**
- 比较操作:==,!=,>,>,<,<=
- 逻辑运算:and,or,not
- 流表达式:For,If,When
字面量:
表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如"Hello World" 双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),如42,42.23数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在Python 里,42和42.0是不一样的
算术运算:
Jinja允许用计算值。支持下面的运算符
十:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这种方式来衔接它们。无论
如何这不是首选的连接字符串的方式!连接字符串见~运算符。{1+1}等于2
-:用第一个数减去第二个数。{3-2}等于1
/:对两个数做除法。返回值会是一个浮点数。{1/2}等于{0.5}
//:对两个数做除法,返回整数商。{20//7}等于2
%:计算整数除法的余数。{11%7}等于4工
:用右边的数乘左边的操作数。{22}会返回4。也可以用于重复一个字符串多次。{一*80}会打印80
个等号的横条
** : 取左操作数的右操作数次雾。{[2**3}}会返回8
逻辑运算符
对于if语句,在for过滤或if表达式中,它可以用于联合多个表达式
and如果左操作数和右操作数同为真,返回true
or 如果左操作数和右操作数有一个为真,返回true
not对一个表达式取反
(expr)表达式组
true/false true永远是true,而false始终是false
template
template 可以根据和参考模块文件,动态生成相类似的配置文件;template 文件必须存放于 templates 目录下,且命名为 .j2 结尾,yaml/yml 文件需和 templates 目录平级,目录结构如下示例:
[root@localhost ansible_data]# tree /ansible_data/
/ansible_data/
├── templates
│ └── nginx.conf.j2
└── temp_nginx.yaml
案例1:
根据机器的CPU数量,批量修改nginx配置文件 worker_processes 的值
# 获取机器的 cpu 核数
[root@localhost ansible_data]# ansible all -m setup -a "filter=ansible_processor_vcpus"
192.168.110.136 | SUCCESS => {
"ansible_facts": {
"ansible_processor_vcpus": 1,
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
192.168.110.129 | SUCCESS => {
"ansible_facts": {
"ansible_processor_vcpus": 2,
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false
}
192.168.110.132 | SUCCESS => {
"ansible_facts": {
"ansible_processor_vcpus": 2,
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false
}
# 生成 nginx 配置文件
[root@localhost ansible_data]# dnf install nginx -y
# 创建 templates 目录
[root@localhost ansible_data]# mkdir templates
# 将配置文件拷贝到 templates 目录,并重名为 .j2 结尾的文件
[root@localhost ansible_data]# cp /etc/nginx/nginx.conf templates/nginx.conf.j2
# 修改配置文件,将 worker_processes 的 auto 改为:{{ ansible_processor_vcpus**2 }}
[root@localhost ansible_data]# vim templates/nginx.conf.j2
user nginx;
#worker_processes auto;
worker_processes {{ ansible_processor_vcpus**2 }};
......
temp_nginx.yaml:
---
# temp_nginx.yaml
- hosts: rocky
remote_user: root
tasks:
- name: install nginx
dnf: name=nginx
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: start service
service: name=nginx state=started enabled=yes
# 执行
[root@localhost ansible_data]# ansible-playbook temp_nginx.yaml
PLAY [rocky] ************************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [192.168.110.129]
ok: [192.168.110.132]
TASK [install nginx] ****************************************************************************************************************************************
ok: [192.168.110.129]
changed: [192.168.110.132]
TASK [template config to remote hosts] **********************************************************************************************************************
changed: [192.168.110.129]
changed: [192.168.110.132]
TASK [start service] ****************************************************************************************************************************************
changed: [192.168.110.129]
changed: [192.168.110.132]
PLAY RECAP **************************************************************************************************************************************************
192.168.110.129 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.110.132 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 查看配置文件 worker_processes 为 4(2个cpu*2=4)
[root@localhost ansible_data]# ansible rocky -m shell -a 'cat /etc/nginx/nginx.conf | grep worker_processe'
192.168.110.129 | CHANGED | rc=0 >>
#worker_processes auto;
worker_processes 4;
192.168.110.132 | CHANGED | rc=0 >>
#worker_processes auto;
worker_processes 4;
# 查看确实是创建了 4 个 worker 进程
[root@localhost ansible_data]# ansible rocky -m shell -a 'ps -aux | grep nginx'
192.168.110.129 | CHANGED | rc=0 >>
root 47180 0.0 0.0 11236 1596 ? Ss 20:53 0:00 nginx: master process /usr/sbin/nginx
nginx 47181 0.0 0.2 15560 5052 ? S 20:53 0:00 nginx: worker process
nginx 47182 0.0 0.2 15560 5052 ? S 20:53 0:00 nginx: worker process
nginx 47183 0.0 0.2 15560 5052 ? S 20:53 0:00 nginx: worker process
nginx 47184 0.0 0.2 15560 5052 ? S 20:53 0:00 nginx: worker process
192.168.110.132 | CHANGED | rc=0 >>
root 9867 0.0 0.0 11236 1468 ? Ss 20:53 0:00 nginx: master process /usr/sbin/nginx
nginx 9868 0.0 0.2 15560 5052 ? S 20:53 0:00 nginx: worker process
nginx 9869 0.0 0.2 15560 5052 ? S 20:53 0:00 nginx: worker process
nginx 9870 0.0 0.2 15560 5052 ? S 20:53 0:00 nginx: worker process
nginx 9871 0.0 0.2 15560 5052 ? S 20:53 0:00 nginx: worker process
案例2:
when 语句,可以实现条件测试。如果需要根据变量、facts 或此前任务的执行结果来做为某 task 执行与否的前提时要用到条件测试,通过在 task 后添加 when 子句即可使用条件测试,jinja2 的语法格式
批量重启 Centos 系统
# temp_when.yaml
---
- hosts: all
remote_user: root
tasks:
- name: "Reboot Centos System"
command: reboot
when: ansible_distribution == "CentOS"
# 执行playbook
[root@localhost ansible_data]# ansible-playbook temp_when.yaml
PLAY [all] **************************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [192.168.110.136]
ok: [192.168.110.132]
ok: [192.168.110.129]
TASK [Reboot Centos System] *********************************************************************************************************************************
skipping: [192.168.110.129]
skipping: [192.168.110.132]
fatal: [192.168.110.136]: FAILED! => {"msg": "Failed to connect to the host via ssh: kex_exchange_identification: read: Connection reset by peer\r\nConnection reset by 192.168.110.136 port 22"}
PLAY RECAP **************************************************************************************************************************************************
192.168.110.129 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.110.132 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.110.136 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
# 验证 centos 7 系统确实被重启了
[root@localhost ~]# hostnamectl | grep System
Operating System: CentOS Linux 7 (Core)
[root@localhost ~]# uptime
21:21:02 up 0 min, 1 user, load average: 3.18, 0.77, 0.25
解决管理节点过多导致的超时问题
默认情况下,Ansible 将尝试并行管理 playbook中所有的机器。对于滚动更新用例,可以使用 serial 关键字定义 Ansible 一次要管理多少主机,还可以将 serial 关键字指定为百分比,表示每次并行执行的主机数占总数的比例。
范例:
vim test_serial.ym7
- hosts:a11
serial:2 # 每次只同时处理 2 个主机
#serial:"20%" #每次只同时处理20%的主机
gather_facts:FaTse
tasks :
- name : task one
comand:hostname
- name : task two
command:hostname
roles 角色
角色是 ansible 自 1.2 版本引入的新特性,用于层次性、结构化地组织 playbook。roles 能够根据层次型结构自动装载变量文件、tasks 以及 handlers 等。要使用 roles 只需要在 playbook 中使用 include 指令即可。
简单来讲,roles 就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include 它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
运维复杂的场景:建议使用roles,代码复用度高
roles:多个角色的集合,可以将多个的 role,分别放至 roles 目录下的独立子目录中
roles/
mysql/
httpd/
nginx/
redis/
galaxy
[root@localhost ansible_data]# ansible-galaxy list
# /usr/share/ansible/roles
# /etc/ansible/roles
[WARNING]: - the configured path /root/.ansible/roles does not exist.
http://ansible.com.cn/ # 中文站点
http://galaxy.ansible.com
https://galaxy.ansible.com/explore#/
http://github.com/
https://github.com/ansible/ansible
https://github.com/ansible/ansible-examples