200字
ansible
2026-03-19
2026-03-19

Ansible

Ansible 特点

优点

  • 功能丰富的模块:提供了多达数千个的各种功能的模块,完成特定任务只需调用特定模块即可,还支持自定义模块,可使用任何编程语言写模块
  • 使用和部署简单: 无需安装专用代理软件,基于python和SSH(默认已安装)实现
  • 安全: 基于OpenSSH实现安全通讯无需专用协议
  • 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况,此特性和模块有关
  • 支持playbook编排任务,YAML格式,编排任务,支持丰富的数据结构
  • 较强大的多层解决方案 Role
  • Python语言实现, 基于Paramiko(python对ssh的实现),PyYAML,Jinja2(模板语言)三个关键模块
  • 属于红帽(IBM)公司产品,背景强大,未来发展前景光明

缺点

  • 如果管理的主机较多时,执行效率不如saltstack高
  • 当前还不支持像MySQL数据库一样的事务回滚

Ansible 架构

组合INVENTORY、API、MODULES、PLUGINS的绿框,为ansible命令工具,其为核心执行工具

  • INVENTORY:Ansible管理主机的清单文件,默认为 /etc/ansible/hosts
  • MODULES:Ansible执行命令的功能模块,多数为内置核心模块,也可自定义
  • PLUGINS:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用
  • API:供第三方程序调用的应用程序编程接口

Ansible 命令执行来源

  • USER 普通用户,即SYSTEM ADMINISTRATOR
  • PLAYBOOKS:任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执行,通常是JSON格式的YML文件
  • CMDB(配置管理数据库) API 调用
  • PUBLIC/PRIVATE CLOUD API调用
  • USER-> Ansible Playbook -> Ansibile

注意事项

  • 执行ansible的主机一般称为管理端, 主控端,中控,master或堡垒机
  • 主控端Python版本需要2.6或以上
  • 被控端Python版本小于2.4,需要安装python-simplejson
  • 被控端如开启SELinux需要安装libselinux-python
  • windows 不能做为主控端,只能做为被控制端

Ansible 安装和常见模块

Ansible 安装

ansible的安装方法有多种

官方文档

https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.ht

下载

https://releases.ansible.com/ansible/

pip 下载

https://pypi.org/project/ansible/

包安装方式

#CentOS 的EPEL源的rpm包安装
[root@centos ~]#yum install ansible

#ubuntu 安装
[root@ubuntu ~]#apt -y install ansible

范例:查看ansible版本

[root@centos8 ~]#yum info ansible
Name : ansible
Version : 2.9.16
Release : 1.el8
[root@centos7 ~]#yum info ansible
Available Packages
Name : ansible
Arch : noarch
Version : 2.9.16

root@ubuntu2004:~# apt show ansible
Package: ansible
Version: 2.9.6+dfsg-1

[root@ubuntu1804 ~]#apt show ansible
Package: ansible
Version: 2.5.1+dfsg-1ubuntu0.1

范例: Ubuntu20.04 安装ansible

[root@ubuntu2004 ~]#apt update
[root@ubuntu2004 ~]#apt -y install ansible
[root@ubuntu2004 ~]#ansible --version
ansible 2.9.6

[root@ubuntu2004 ~]#dpkg -L ansible |head
/.
/etc
/etc/ansible
/etc/ansible/ansible.cfg
/etc/ansible/hosts
/usr
/usr/bin
/usr/lib
/usr/lib/python3
/usr/lib/python3/dist-packages

范例:ubuntu18.04安装最新版的ansible

[root@ubuntu1804 ~]#apt update
[root@ubuntu1804 ~]#apt install software-properties-common
[root@ubuntu1804 ~]#apt-add-repository --yes --update ppa:ansible/ansible
[root@ubuntu1804 ~]#apt install ansible
[root@ubuntu1804 ~]#ansible --version
ansible 2.9.17

pip 安装

pip 是安装Python包的管理器,类似 yum

范例: 在rocky8上通过pip3安装ansible

[root@rocky8 ~]#yum -y install python39 rust
[root@rocky8 ~]#pip3 install ansible
[root@rocky8 ~]#ansible --version
ansible [core 2.12.6]

范例: 安装python3.8 支持ansible2.12以上版本

[root@rocky8 ~]#yum -y install python38 python38-pip
[root@rocky8 ~]#pip3 install --upgrade pip -i https://pypi.douban.com/simple
[root@rocky8 ~]#pip3 install ansible -i https://pypi.douban.com/simple/
[root@rocky8 ~]#ansible --version
ansible [core 2.12.6]

范例: 安装默认的python3.6版本会有警报提示‘

[root@rocky8 ~]#yum -y install python3
[root@rocky8 ~]#pip3 install --upgrade pip -i https://pypi.douban.com/simple
[root@rocky8 ~]#pip3 install ansible -i https://pypi.douban.com/simple/
[root@rocky8 ~]#ansible --version
[DEPRECATION WARNING]: Ansible will require Python 3.8 or newer on the
controller starting with Ansible 2.12. Current version: 3.6.8 (default, Nov
9 2021, 14:44:26) [GCC 8.5.0 20210514 (Red Hat 8.5.0-3)]. This feature will be
removed from ansible-core in version 2.12. Deprecation warnings
can be disabled by setting deprecation_warnings=False in ansible.cfg.
/usr/local/lib/python3.6/site-packages/ansible/parsing/vault/__init__.py:44:
CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python
core team. Therefore, support for it is deprecated in cryptography and will be
removed in a future release.
from cryptography.exceptions import InvalidSignature
ansible [core 2.11.12]
config file = None
configured module search path = ['/root/.ansible/plugins/modules',
'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.6/site-
packages/ansible
ansible collection location =
/root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible
python version = 3.6.8 (default, Nov 9 2021, 14:44:26) [GCC 8.5.0 20210514
(Red Hat 8.5.0-3)]
jinja version = 3.0.3
libyaml = True

范例

[root@centos7 ~]#yum -y install python-pip
[root@centos7 ~]#pip install --upgrade pip
[root@centos7 ~]#pip install ansible --upgrade
[root@centos7 ~]#ansible --version
/usr/lib64/python2.7/site-packages/cryptography/__init__.py:39:
CryptographyDeprecationWarning: Python 2 is no longer supported by the Python
core team. Support for it is now deprecated in cryptography, and will be removed
in a future release.
CryptographyDeprecationWarning,
ansible 2.9.12

Ansible 相关文件

Ansible 配置文件列表

  • /etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性,也可以在项目的目录中创建此文件,当前目录下如果也有ansible.cfg,则此文件优先生效,建议每个项目目录下,创建独有的ansible.cfg文件
  • /etc/ansible/hosts 主机清单
  • /etc/ansible/roles/ 存放角色的目录

Ansible 主配置文件

Ansible 的配置文件可以放在多个不同地方,优先级从高到低顺序如下

ANSIBLE_CONFIG #环境变量,目录下的文件必须存在才能生效
./ansible.cfg #当前目录下的ansible.cfg,一般一个项目对应一个专用配置文件,推荐使用
~/.ansible.cfg #当前用户家目录下的.ansible.cfg
/etc/ansible/ansible.cfg #系统默认配置文件

Ansible 的默认配置文件 /etc/ansible/ansible.cfg ,其中大部分的配置内容无需进行修改

[defaults]
#inventory = /etc/ansible/hosts #主机列表配置文件
#library = /usr/share/my_modules/ #库文件存放目录
#remote_tmp = $HOME/.ansible/tmp #临时py命令文件存放在远程主机目录
#local_tmp = $HOME/.ansible/tmp #本机的临时命令执行目录
#forks = 5 #默认并发数
#sudo_user = root #默认sudo 用户
#ask_sudo_pass = True #每次执行ansible命令是否询问ssh密码
#ask_pass = True
#remote_port = 22
#host_key_checking = False #检查对应服务器的host_key,建议取消此行注释,实现第一次连接自动信任目标主机
#log_path=/var/log/ansible.log #日志文件,建议启用
#module_name = command #默认模块,可以修改为shell模块
[privilege_escalation] #普通用户提权配置
#become=True
#become_method=sudo
#become_user=root
#become_ask_pass=False

Inventory 主机清单文件

ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory 主机清单文件中将其分组组织

默认的inventory file为 /etc/ansible/host

inventory file可以有多个,且也可以通过Dynamic Inventory来动态生成

注意:

  • 生产建议在每个项目目录下创建项目独立的hosts文件
  • 通过项目目录下的ansible.cfg文件中的 inventory = ./hosts实现

主机清单文件格式

inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组

此外,当如若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明

如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机

Inventory 参数说明

ansible_ssh_host #将要连接的远程主机名.与你想要设定的主机的别名不同的话,可通过此变量设置.
ansible_ssh_port #ssh端口号.如果不是默认的端口号,通过此变量设置.这种可以使用 ip:端口192.168.1.100:2222
ansible_ssh_user #默认的 ssh 用户名
ansible_ssh_pass #ssh 密码(这种方式并不安全,我们强烈建议使用 --ask-pass 或 SSH 密钥)
ansible_sudo_pass #sudo 密码(这种方式并不安全,我们强烈建议使用 --ask-sudo-pass)
ansible_sudo_exe (new in version 1.8) #sudo 命令路径(适用于1.8及以上版本)
ansible_connection #与主机的连接类型.比如:local, ssh 或者 paramiko. Ansible 1.2 以前默认使用 paramiko.1.2 以后默认使用 'smart','smart' 方式会根据是否支持 ControlPersist,来判断'ssh' 方式是否可行.
ansible_ssh_private_key_file #ssh 使用的私钥文件.适用于有多个密钥,而你不想使用 SSH 代理的情况
ansible_shell_type #目标系统的shell类型.默认情况下,命令的执行使用 'sh' 语法,可设置为'csh' 或 'fish'.
ansible_python_interpreter #目标主机的 python 路径.适用于的情况: 系统中有多个 Python,或者命令路径不是"/usr/bin/python",比如 \*BSD, 或者 /usr/bin/python 不是 2.X 版本的Python.之所以不使用 "/usr/bin/env" 机制,因为这要求远程用户的路径设置正确,且要求 "python"可执行程序名不可为 python以外的名字(实际有可能名为python26).与ansible_python_interpreter 的工作方式相同,可设定如 ruby 或 perl 的路径....

范例:

ntp.wang.org
[webservers]
www1.wang.org:2222
www2.wang.org

[dbservers]
db1.wang.org
db2.wang.org
db3.wang.org
#或者
db[1:3].wang.org

范例: 组嵌套

[webservers]
www[1:100].example.com

[dbservers]
db-[a:f].example.com

[appservers]
10.0.0.[1:100]

#定义testsrvs组中包括两个其它分组,实现组嵌套
[testsrvs:children]
webservers
dbservers

范例: 基于用户名和密码的ssh连接主机清单

[test]
10.0.0.8 ansible_connection=local #指定本地连接,无需ssh配置

#每个主机分别指定用户和密码,ansible_connection=ssh 需要StrictHostKeyChecking no 或者host_key_checking = False
10.0.0.7 ansible_connection=ssh ansible_ssh_port=2222 ansible_ssh_user=wang ansible_ssh_password=123456
10.0.0.6 ansible_ssh_user=root ansible_ssh_password=123456

#对每个分组的所有主机统一定义用户和密码,执行ansible命令时显示别名,如web01
[websrvs]
web01 ansible_ssh_host=10.0.0.101
web02 ansible_ssh_host=10.0.0.102
[websrvs:vars]
ansible_ssh_password=ayaka

some_host ansible_ssh_port=2222 ansible_ssh_user=manager
aws_host ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
freebsd_host ansible_python_interpreter=/usr/local/bin/python
ruby_module_host ansible_ruby_interpreter=/usr/bin/ruby.1.9.

Ansible相关工具

  • /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实现管理的主要方式:

  • Ansible Ad-Hoc 即利用ansible命令,主要用于临时命令使用场景
  • Ansible playbook 主要用于长期规划好的,大型项目的场景,需要有前期的规划过程

ansible 使用前准备

ansible 相关工具大多数是通过ssh协议,实现对远程主机的配置管理、应用部署、任务执行等功能

建议:使用此工具前,先配置ansible主控端能基于密钥认证的方式联系各个被管理节点

范例:利用sshpass批量实现基于key验证脚本

[root@centos8 ~]#vim /etc/ssh/ssh_config
#修改下面一行
StrictHostKeyChecking no
#!/bin/bash

# --- 自定义配置 ---
NETWORK="192.168.1.0/24"
REMOTE_USER="root"
REMOTE_PASS="YourPassword123"

# 1. 智能环境检查与安装
install_tool() {
    local tool=$1
    if ! command -v $tool &> /dev/null; then
        echo "[*] 正在安装依赖: $tool ..."
        if command -v dnf &> /dev/null; then
            # 红帽系 (RHEL 8+, Fedora)
            sudo dnf install -y epel-release && sudo dnf install -y $tool
        elif command -v yum &> /dev/null; then
            # 红帽系 (CentOS 7-)
            sudo yum install -y epel-release && sudo yum install -y $tool
        elif command -v apt-get &> /dev/null; then
            # Debian/Ubuntu 系
            sudo apt-get update && sudo apt-get install -y $tool
        else
            echo "[!] 错误: 未知系统,请手动安装 $tool" && exit 1
        fi
    fi
}

install_tool "nmap"
install_tool "sshpass"

# 2. 准备本地 SSH 密钥
if [ ! -f "$HOME/.ssh/id_rsa" ]; then
    echo "[*] 正在初始化本地密钥..."
    ssh-keygen -t rsa -b 2048 -N "" -f "$HOME/.ssh/id_rsa"
fi

# 3. 跨系统扫描 (兼容 nmap 各版本输出)
echo "[*] 正在探测网络中的存活主机 ($NETWORK)..."
# 使用 -sn (Ping 扫描) 结合端口探测,速度最快
HOSTS=$(nmap -n -p 22 --open $NETWORK | grep "Nmap scan report for" | awk '{print $NF}' | sed 's/[()]//g')

if [ -z "$HOSTS" ]; then
    echo "[!] 未发现可连接的 SSH 主机。"
    exit 1
fi

echo "---------------------------------------"
echo "[发现目标]:"
echo "$HOSTS"
echo "---------------------------------------"

# 4. 核心分发逻辑
for IP in $HOSTS; do
    # 过滤掉本机 IP
    if hostname -I | grep -q "$IP"; then continue; fi

    echo -n "[>] 正在尝试对接 $IP ... "
    
    # 解决红帽/Ubuntu 下 ssh-copy-id 的交互差异
    # StrictHostKeyChecking=no 跳过指纹确认
    # connect_timeout 防止脚本在死机上卡死
    export SSHPASS=$REMOTE_PASS
    sshpass -e ssh-copy-id -o "StrictHostKeyChecking=no" -o "ConnectTimeout=3" "$REMOTE_USER@$IP" &> /dev/null
    
    if [ $? -eq 0 ]; then
        echo "【成功】"
    else
        echo "【失败】(请检查密码或 SSH 设置)"
    fi
done

echo "---------------------------------------"
echo "[任务结束] 现已实现对上述成功主机的单向免密控制。"

范例: 实现基于key验证的脚本2

[root@centos8 ~]#cat ssh_key.sh
#!/bin/bash
IPLIST="
10.0.0.8
10.0.0.18
10.0.0.7
10.0.0.6
10.0.0.200"

rpm -q sshpass &> /dev/null || yum -y install sshpass
[ -f /root/.ssh/id_rsa ] || ssh-keygen -f /root/.ssh/id_rsa -P ''

export SSHPASS=123456

for IP in $IPLIST;do
	{ sshpass -e ssh-copy-id -o StrictHostKeyChecking=no $IP; } &
done
wait

ansible-doc

此工具用来显示模块帮助,相当于man

格式

ansible-doc [options] [module...]
-l, --list #列出可用模块
-s, --snippet #显示指定模块的playbook片段

范例: 查看帮助

[root@ansible ~]#ansible-doc --help

范例:

#列出所有模块
ansible-doc -l
#查看指定模块帮助用法
ansible-doc ping
#查看指定模块帮助用法
ansible-doc -s ping

范例: 查看指定的插件

[root@ansible ~]#ansible-doc -t connection -l
[root@ansible ~]#ansible-doc -t lookup -l

ansible

Ansible Ad-Hoc 介绍

Ansible Ad-Hoc 的执行方式的主要工具就是 ansible

特点: 一次性的执行,不会保存执行命令信息,只适合临时性或测试性的任务

ansible 命令用法

格式

ansible <host-pattern> [-m module_name] [-a args]

选项说明:

--version #显示版本
-m module #指定模块,默认为command
-v #详细过程 -vv -vvv更详细
--list-hosts #显示主机列表,可简写 --list
-C, --check #检查,并不执行
-T, --timeout=TIMEOUT #执行命令的超时时间,默认10s
-k, --ask-pass #提示输入ssh连接密码,默认Key验证
-u, --user=REMOTE_USER #执行远程执行的用户,默认root
-b, --become #代替旧版的sudo实现通过sudo机制实现提升权限
--become-user=USERNAME #指定sudo的runas用户,默认为root
-K, --ask-become-pass #提示输入sudo时的口令
-f FORKS, --forks FORKS #指定并发同时执行ansible任务的主机数
-i INVENTORY, --inventory INVENTORY #指定主机清单文件

范例:

#以wang用户执行ping存活检测
ansible all -m ping -u wang -k
#以wang sudo至root执行ping存活检测
ansible all -m ping -u wang -k -b
#以wang sudo至ayaka用户执行ping存活检测
ansible all -m ping -u wang -k -b --become-user=ayaka
#以wang sudo至root用户执行ls
ansible all -m command -u wang -a 'ls /root' -b --become-user=root -k -K

范例: 并发执行控制

#分别执行下面两条命令观察结果
[root@ansible ~]#ansible all -a 'sleep 5' -f1
[root@ansible ~]#ansible all -a 'sleep 5' -f10

范例: 使用普能用户进行远程管理

#在所有控制端和被控制端创建用户和密码
[root@rocky8 ~]#useradd wang
[root@rocky8 ~]#echo wang:123456 | chpasswd

#在所有被控制端对用户sudo授权
[root@rocky8 ~]#visudo
wang ALL=(ALL) NOPASSWD: ALL
[root@rocky8 ~]#visudo -c
/etc/sudoers: parsed OK

#实现从控制端到被控制端的基于key验证
[root@ansible ~]#su - wang
wang@ansible:~$ssh-keygen -f ~/.ssh/id_rsa -P ''
wang@ansible:~$$ssh-copy-id wang@'10.0.0.8'

#使用普通用户测试连接,默认连接权限不足失败
wang@ansible:~$ ansible 10.0.0.8 -m shell -a 'ls /root'
10.0.0.8 | FAILED | rc=2 >>
ls: cannot open directory '/root': Permission deniednon-zero return code

#使用普通用户通过-b选项连接实现sudo提权后连接成功
wang@ansible:~$ ansible 10.0.0.8 -m shell -a 'ls /root' -b --become-user root
10.0.0.8 | CHANGED | rc=0 >>
anaconda-ks.cfg

#修改配置文件指定sudo机制
[root@ansible ~]#vim /etc/ansible/ansible.cfg
#取消下面行前面的注释
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False

#再次测试
[root@ansible ~]#su - wang
wang@ansible:~$ ansible 10.0.0.8 -m shell -a 'ls /root'
10.0.0.8 | CHANGED | rc=0 >>
anaconda-ks.cfg

范例: 使用普通用户连接远程主机执行代替另一个用户身份执行操作

[root@centos8 ~]#useradd wang
[root@centos8 ~]#echo wang:123456 | chpasswd
#先在被控制端能过sudo对普通用户授权
[root@centos8 ~]#grep wang /etc/sudoers
wang ALL=(ALL) NOPASSWD: ALL

#以wang的用户连接用户,并利用sudo代表ayaka执行whoami命令
[root@ansible ~]#ansible 10.0.0.8 -m shell -a 'whoami' -u wang -k -b --become-user=ayaka
SSH password: #输入远程主机wang用户ssh连接密码
10.0.0.8 | CHANGED | rc=0 >>
ayaka

ansible的Host-pattern

用于匹配被控制的主机的列表

All :表示所有Inventory中的所有主机

范例

ansible all -m ping

*:通配符

ansible "*" -m ping
ansible 192.168.1.* -m ping
ansible "srvs" -m ping
ansible "10.0.0.6 10.0.0.7" -m ping

或关系

ansible "websrvs:appsrvs" -m ping
ansible "192.168.1.10:192.168.1.20" -m ping

逻辑与

#在websrvs组并且在dbsrvs组中的主机
ansible "websrvs:&dbsrvs" -m ping

逻辑非

#在所有主机,但不在websrvs组和dbsrvs组中的主机
#注意:此处为单引号
ansible 'all:!dbsrvs:!websrvs' -m ping

综合逻辑

ansible 'websrvs:dbsrvs:&appsrvs:!ftpsrvs' -m ping

正则表达式

ansible "websrvs:dbsrvs" -m ping
ansible "~(web|db).*\.ayaka\.com" -m ping

范例:

[root@kube-master1 ~]#ansible 'kube*:etcd:!10.0.0.101' -a reboot && reboot

范例:

[root@centos8 ~]#ansible all --list-hosts
hosts (3):
10.0.0.6
10.0.0.7
10.0.0.8
[root@centos8 ~]#ansible websrvs --list-hosts
hosts (3):
10.0.0.6
10.0.0.7
10.0.0.8
[root@centos8 ~]#ansible appsrvs --list-hosts
hosts (2):
10.0.0.7
10.0.0.8
[root@centos8 ~]#ansible "appsrvs:dbsrvs" --list-hosts
hosts (3):
10.0.0.7
10.0.0.8
10.0.0.6
[root@centos8 ~]#ansible "dbsrvs" --list-hosts
hosts (2):
10.0.0.6
10.0.0.7
[root@centos8 ~]#ansible appsrvs --list-hosts
hosts (2):
10.0.0.7
10.0.0.8
[root@centos8 ~]#ansible "appsrvs:dbsrvs" --list-hosts
hosts (3):
10.0.0.7
10.0.0.8
10.0.0.6
[root@centos8 ~]#ansible "appsrvs:&dbsrvs" --list-hosts
hosts (1):
10.0.0.7

#引用!号时,不要用双引号,而使用单引号
[root@centos8 ~]#ansible "appsrvs:!dbsrvs" --list-hosts
-bash: !dbsrvs: event not found
[root@centos8 ~]#ansible 'appsrvs:!dbsrvs' --list-hosts
hosts (1):
10.0.0.8

ansible 命令的执行过程

  1. 加载自己的配置文件,默认/etc/ansible/ansible.cfg
  2. 查找主机清单中对应的主机或主机组
  3. 加载自己对应的模块文件,如:command
  4. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
  5. 给文件+x执行
  6. 执行并返回结果
  7. 删除临时py文件,退出

ansible 命令的执行状态

[root@centos8 ~]#grep -A 14 '\[colors\]' /etc/ansible/ansible.cfg
[colors]
#highlight = white
#verbose = blue
#warn = bright purple
#error = red
#debug = dark gray
#deprecate = purple
#skip = cyan
#unreachable = red
#ok = green
#changed = yellow
#diff_add = green
#diff_remove = red
#diff_lines = cyan
  • 绿色:执行成功并且对目标主机不需要做改变的操作
  • 黄色:执行成功并且对目标主机做变更
  • 红色:执行失败

ansible-console

此工具可交互执行命令,支持tab,ansible 2.0+新增

提示符格式:

执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$

常用子命令:

  • 设置并发数: forks n 例如: forks 10
  • 切换组: cd 主机组 例如: cd web
  • 列出当前组主机列表: list
  • 列出所有的内置命令: ?或help

范例

[root@ansible ~]#ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
root@all (3)[f:5]$ ping
10.0.0.7 | SUCCESS => {

"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.6 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.8 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}

root@all (3)[f:5]$ list
10.0.0.8
10.0.0.7
10.0.0.6
root@all (3)[f:5]$ cd websrvs
root@websrvs (2)[f:5]$ list
10.0.0.7
10.0.0.8
root@websrvs (2)[f:5]$ forks 10
root@websrvs (2)[f:10]$ cd appsrvs
root@appsrvs (2)[f:5]$ yum name=httpd state=present
root@appsrvs (2)[f:5]$ service name=httpd state=started

ansible-playbook

此工具用于执行编写好的 playbook 任务

范例:

ansible-playbook hello.yml
cat hello.yml
---
#hello world yml file
- hosts: websrvs
    remote_user: root
    gather_facts: no
    
    tasks:
        - name: hello world
        command: /usr/bin/wall hello world

ansible-vault

此工具可以用于加密解密yml文件

格式:

ansible-vault [create|decrypt|edit|encrypt|rekey|view]

范例

ansible-vault encrypt hello.yml #加密
ansible-vault decrypt hello.yml #解密
ansible-vault view hello.yml #查看
ansible-vault edit hello.yml #编辑加密文件
ansible-vault rekey hello.yml #修改口令
ansible-vault create new.yml #创建新文件

#执行加密的playbook,交互式输入密码
chmod 600 hello.yml
ansible-playbook --ask-vault-pass hello.yml

#从pass.txt文件中读取密码
ansible-playbook --vault-password-file pass.txt hello.yml

#从配置文件中取得密码
#vi /etc/ansible/ansible.cfg
[defaults]
ault-password-file=pass.txt

#可以直接执行加密文件
ansible-playbook hello.yml

ansible-galaxy

Galaxy 是一个免费网站, 类似于github网站, 网站上发布了很多的共享的roles角色。

Ansible 提供了ansible-galaxy命令行工具连接 https://galaxy.ansible.com 网站下载相应的roles, 进行init(初始化、search( 查拘、install(安装、 remove(移除)等操作。

范例:

#搜索项目
[root@ansible ~]#ansible-galaxy search lamp
#列出所有已安装的galaxy
ansible-galaxy list
#安装galaxy,默认下载到~/.ansible/roles下
ansible-galaxy install geerlingguy.mysql
ansible-galaxy install geerlingguy.redis
#删除galaxy
ansible-galaxy remove geerlingguy.redis

Ansible常用模块

Command 模块

功能:在远程主机执行命令,此为默认模块,可忽略 -m 选项

注意:此命令不支持 $VARNAME < > | ; & 等,可能用shell模块实现

注意:此模块不具有幂等性

常见选项

chdir=dir #执行命令前,先切换至目录dir
creates=file #当file不存在时才会执行
removes=file #当file存在时才会执行

范例:

[root@ansible ~]#ansible websrvs -m command -a 'chdir=/etc cat centos-release'
10.0.0.7 | CHANGED | rc=0 >>
CentOS Linux release 7.7.1908 (Core)
10.0.0.8 | CHANGED | rc=0 >>
CentOS Linux release 8.1.1911 (Core)
[root@ansible ~]#ansible websrvs -m command -a 'chdir=/etc creates=/data/f1.txt cat centos-release'
10.0.0.7 | CHANGED | rc=0 >>
CentOS Linux release 7.7.1908 (Core)
10.0.0.8 | SUCCESS | rc=0 >>
skipped, since /data/f1.txt exists
[root@ansible ~]#ansible websrvs -m command -a 'chdir=/etc removes=/data/f1.txt cat centos-release'
10.0.0.7 | SUCCESS | rc=0 >>
skipped, since /data/f1.txt does not exist
10.0.0.8 | CHANGED | rc=0 >>
CentOS Linux release 8.1.1911 (Core)

ansible websrvs -m command -a 'service vsftpd start'
ansible websrvs -m command -a 'echo ayaka |passwd --stdin aika'
ansible websrvs -m command -a 'rm -rf /data/'
ansible websrvs -m command -a 'echo hello > /data/hello.log'
ansible websrvs -m command -a "echo $HOSTNAME"

Shell 模块

功能:和command相似,用shell执行命令,支持各种符号,比如:*,$, > , 相当于增强版的command模块

注意:此模块不具有幂等性,建议能不能就用此模块,最好使用专用模块

常见选项

chdir=dir #执行命令前,先切换至目录dir
creates=file #当file不存在时才会执行
removes=file #当file存在时才会执行

范例:

[root@ansible ~]#ansible websrvs -m shell -a "echo $HOSTNAME"
10.0.0.7 | CHANGED | rc=0 >>
ansible
10.0.0.8 | CHANGED | rc=0 >>
ansible
[root@ansible ~]#ansible websrvs -m shell -a 'echo $HOSTNAME   #'单引号 ' ':禁止本地 Shell 解析
10.0.0.7 | CHANGED | rc=0 >>
centos7.ayaka.com
10.0.0.8 | CHANGED | rc=0 >>
centos8.localdomain

[root@ansible ~]#ansible websrvs -m shell -a 'echo centos | passwd --stdin wang'
10.0.0.7 | CHANGED | rc=0 >>
Changing password for user wang.
passwd: all authentication tokens updated successfully.
10.0.0.8 | CHANGED | rc=0 >>
Changing password for user wang.
passwd: all authentication tokens updated successfully.

[root@ansible ~]#ansible websrvs -m shell -a 'ls -l /etc/shadow'
10.0.0.7 | CHANGED | rc=0 >>
---------- 1 root root 889 Mar 2 14:34 /etc/shadow
10.0.0.8 | CHANGED | rc=0 >>
---------- 1 root root 944 Mar 2 14:34 /etc/shadow

[root@ansible ~]#ansible websrvs -m shell -a 'echo hello > /data/hello.log'
10.0.0.7 | CHANGED | rc=0 >>
10.0.0.8 | CHANGED | rc=0 >>

[root@ansible ~]#ansible websrvs -m shell -a 'cat /data/hello.log'
10.0.0.7 | CHANGED | rc=0 >>
hello
10.0.0.8 | CHANGED | rc=0 >>
hello

Script 模块

功能:在远程主机上运行ansible服务器上的脚本(无需执行权限)

注意:此模块不具有幂等性

常见选项

chdir=dir #执行命令前,先切换至目录dir
cmd #指定ansible主机的命令
creates=file #当file不存在时才会执行
removes=file #当file存在时才会执行

范例:

ansible websrvs -m script -a /data/test.sh

Copy 模块

功能:复制ansible服务器主控端或远程的本机的文件到远程主机

注意: src=file 如果是没指明路径,则为当前目录或当前目录下的files目录下的file文件

常见选项

src #控制端的源文件路径
dest #被控端的文件路径
owner #属主
group #属组
mode #权限
backup #是否备份
validate #验证成功才会执行copy
remote_src #no是默认值,表示src文件在ansible主机,yes表示src文件在远程主机

范例:

#如目标存在,默认覆盖,此处指定先备
ansible websrvs -m copy -a "src=/root/test1.sh dest=/tmp/test2.sh owner=wang mode=600 backup=yes"

#指定内容,直接生成目标文件
ansible websrvs -m copy -a "content='wang 123456\nxiao 654321\n' dest=/etc/rsync.pas owner=root group=root mode=0600"

#复制/etc目录自身,注意/etc/后面没有/
ansible websrvs -m copy -a "src=/etc dest=/backup"

#复制/etc/下的文件,不包括/etc/目录自身,注意/etc/后面有/
ansible websrvs -m copy -a "src=/etc/ dest=/backup"


#复制/etc/suders,并校验语法
ansible websrvs -m copy -a "src=/etc/suders dest=/etc/sudoers.edit remote_src=yes validate=/usr/sbin/visudo -csf %s"

Get_url 模块

功能: 用于将文件从http、https或ftp下载到被管理机节点上

常用参数如下:

url #下载文件的URL,支持HTTP,HTTPS或FTP协议
dest #下载到目标路径(绝对路径),如果目标是一个目录,就用原文件名,如果目标设置了名称就用目标设置的名称
owner #指定属主
group #指定属组
mode #指定权限
force #如果yes,dest不是目录,将每次下载文件,如果内容改变替换文件。如果no,则只有在目标不存在时才会下载
checksum #对目标文件在下载后计算摘要,以确保其完整性
	#示例: checksum="sha256:D98291AC[...]B6DC7B97",
	checksum="sha256:http://example.com/path/sha256sum.txt"
url_username #用于HTTP基本认证的用户名。 对于允许空密码的站点,此参数可以不使用`url_password'
url_password #用于HTTP基本认证的密码。 如果未指定`url_username'参数,则不会使用`url_password'参数

validate_certs #如果“no”,SSL证书将不会被验证。 适用于自签名证书在私有网站上使用
timeout #URL请求的超时时间,秒为单位

范例: 下载并MD5验证

[root@ansible ~]#ansible websrvs -m get_url -a 'url=http://nginx.org/download/nginx-1.18.0.tar.gz dest=/usr/local/src/nginx.tar.gz checksum="md5:b2d33d24d89b8b1f87ff5d251aa27eb8"'

Fetch 模块

功能:从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录

常见选项

src #被控制端的源文件路径,只支持文件
dest #ansible控制端的目录路径

范例:

ansible websrvs -m fetch -a 'src=/root/test.sh dest=/data/scripts'

范例:

[root@ansible ~]#ansible all -m fetch -a 'src=/etc/redhat-release dest=/data/os'
[root@ansible ~]#tree /data/os/
/data/os/
├── 10.0.0.6
│ 	└── etc
│ 		└── redhat-release
├── 10.0.0.7
│ 	└── etc
│ 		└── redhat-release
└── 10.0.0.8
    └── etc
   	 └── redhat-release

File 模块

功能:设置文件属性,创建文件,目录和软链接等

常见选项

path #在被控端创建的路径
owner #属主
group #属组
mode #权限
state #状态
    =touch #创建文件
    =directory #创建目录
    =link #软链接
    =hard #硬链接
recurse #yes表示递归授权

范例:

#创建空文件
ansible all -m file -a 'path=/data/test.txt state=touch'
ansible all -m file -a 'path=/data/test.txt state=absent'
ansible all -m file -a "path=/root/test.sh owner=wang mode=755"
#创建目录
ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql"

#创建软链接
ansible all -m file -a 'src=/data/testfile path|dest|name=/data/testfile-link state=link'

#创建目录
ansible all -m file -a 'path=/data/testdir state=directory'

#递归修改目录属性,但不递归至子目录
ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql"

#递归修改目录及子目录的属性
ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql recurse=yes"

stat 模块

功能:检查文件或文件系统的状态

注意:对于Windows目标,请改用win_stat模块

常见选项

path #文件/对象的完整路径(必须)

常用的返回值判断:

exists: 判断是否存在
isuid: 调用用户的ID与所有者ID是否匹配

范例

[root@ansible ~]#ansible 127.0.0.1 -m stat -a 'path=/etc/passwd'
127.0.0.1 | SUCCESS => {
"changed": false,
"stat": {
"atime": 1614601466.7493012,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "8f7a9a996d24de98bf1eab4a047f8e89e9c708cf",
"ctime": 1614334259.4498665,
"dev": 2050,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 134691833,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0000",
"mtime": 1614334259.4498665,
"nlink": 1,
"path": "/etc/passwd",
"pw_name": "root",
"readable": true,
"rgrp": false,
"roth": false,
"rusr": false,
"size": 1030,
"uid": 0,
"version": "671641160",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": false,
"xgrp": false,
"xoth": false,
"xusr": false
}
}

案例:

- name: install | Check if file is already configured.
stat: path={{ nginx_file_path }}
connection: local
register: nginx_file_result
- name: install | Download nginx file
get_url: url={{ nginx_file_url }} dest={{ software_files_path }}
validate_certs=no
connection: local
when:,not. nginx_file_result.stat.exists

范例:

[root@ansible ansible]#cat stat.yml
---
- hosts: websrvs

    tasks:
    - name: check file
        stat: path=/data/mysql
        register: st
    - name: debug
    	debug:
    		msg: "/data/mysql is not exist"
    	when: not st.stat.exists
    	
[root@ansible ansible]#ansible-playbook stat.yml
PLAY [websrvs]
********************************************************************************
***************************************
TASK [Gathering Facts]
********************************************************************************
*******************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [check file]
********************************************************************************
************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [debug]
********************************************************************************
*****************************************
ok: [10.0.0.7] => {
"msg": "/data/mysql is not exist"

unarchive 模块

功能:解包解压缩

实现有两种用法:

  • 将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置remote_src=no,此为默认值,可省略

  • 将远程本主机上或非ansible的其它主机的某个压缩包解压缩到远程主机本机的指定路径下,需要设置remote_src=yes

常见参数:

remote_src #和copy功能一样且选项互斥,yes表示源文件在远程被控主机或其它非ansible的其它主机上,no表示文件在ansible主机上,默认值为no, 此选项代替copy选项
copy #默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,会在远程主机上寻找src源文件,此选项已废弃
src #源路径,可以是ansible主机上的路径,也可以是远程主机(被管理端或者第三方主机)上的路径,如果是远程主机上的路径,则需要设置remote_src=yes
dest #远程主机上的目标路径
mode #设置解压缩后的文件权限
creates=/path/file #当绝对路径/path/file不存在时才会执行

范例:

ansible all -m unarchive -a 'src=/data/foo.tgz dest=/var/lib/foo owner=wang group=bin'
ansible all -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777'
ansible all -m unarchive -a 'src=https://example.com/example.zip dest=/data opy=no'
ansible websrvs -m unarchive -a 'src=https://releases.ansible.com/ansible/ansible-2.1.6.0-0.1.rc1.tar.gz dest=/data/ owner=root remote_src=yes'
ansible websrvs -m unarchive -a 'src=http://nginx.org/download/nginx-1.18.0.tar.gz dest=/usr/local/src/ copy=no'

Archive 模块

功能:打包压缩保存在被管理节点

常见选项

path #压缩的文件或目录
dest #压缩后的文件
format #压缩格式,支持gz,bz2,xz,tar,zip

范例:

ansible websrvs -m archive -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2 owner=wang mode=0600'

Hostname 模块

功能:管理主机名

常见选项

name #修改后的主机名称

范例:

ansible node1 -m hostname -a "name=websrv"
ansible 10.0.0.18 -m hostname -a 'name=node18.wang.org'

Cron 模块

功能:计划任务

支持时间:minute,hour,day,month,weekday

常见选项

name #描述脚本的作用
minute #分钟
hour #小时
weekday #周
user #任务由哪个用户运行;默认root
job #任务

范例:

#备份数据库脚本
[root@centos8 ~]#cat /root/mysql_backup.sh
#!/bin/bash
mysqldump -A -F --single-transaction --master-data=2 -q -uroot |gzip > /data/mysql_`date +%F_%T`.sql.gz

#创建任务
ansible 10.0.0.8 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh'

ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate ntp.aliyun.com &>/dev/null' name=Synctime"
#禁用计划任务
ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=yes"

#启用计划任务
ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=no"

#删除任务
ansible websrvs -m cron -a "name='backup mysql' state=absent"
ansible websrvs -m cron -a 'state=absent name=Synctime'

Yum 和 Apt 模块

功能:管理软件包

yum 管理软件包,只支持RHEL,CentOS,fedora,不支持Ubuntu其它版本

apt 模块管理 Debian 相关版本的软件包

yum常见选项

name #软件包名称
state #状态
    =present #安装,此为默认值
    =absent #删除
    =latest #最新版
list #列出指定包
enablerepo #启用哪个仓库安装
disablerepo #不使用哪些仓库的包
exclude #排除指定的包
validate #是否检验,默认为yes

范例:

安装
[root@ansible ~]#ansible websrvs -m yum -a 'name=httpd state=present'


#安装zabbix agent rpm包
[root@ansible ~]#ansible websrvs -m yum -a 'name=https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/5.0/rhel/8/x86_64/zabbix-agent2-5.0.24-1.el8.x86_64.rpm state=present validate_certs=no'

#启用epel源进行安装
[root@ansible ~]#ansible websrvs -m yum -a 'name=nginx state=present enablerepo=epel'

#升级除kernel和foo开头以外的所有包
[root@ansible ~]#ansible websrvs -m yum -a 'name=* state=lastest exclude=kernel*,foo*'

#删除
[root@ansible ~]#ansible websrvs -m yum -a 'name=httpd state=absent'


[root@ansible ~]#ansible websrvs -m yum -a 'name=sl,cowsay'

范例:

[root@ansible ~]#ansible websrvs -m yum -a "name=https://mirror.tuna.tsinghua.edu.cn/zabbix/zabbix/5.2/rhel/7/x86_64/zabbix-agent-5.2.5-1.el7.x86_64.rpm" 

范例: Ubuntu 安装软件

[root@centos8 ~]#ansible 10.0.0.100 -m apt -a 'name=bb,sl,cowsay,cmatrix,oneko,hollywood,boxes,libaa-bin,x11-apps update_cache=yes'

[root@centos8 ~]#ansible websrvs -m apt -a 'name=rsync,psmisc state=absent'

范例: 查看包

[root@ansible ~]#ansible localhost -m yum -a "list=tree"
localhost | SUCCESS => {
"ansible_facts": {
"pkg_mgr": "dnf"
},
"changed": false,
"msg": "",
"results": [
{
"arch": "x86_64",
"epoch": "0",
"name": "tree",
"nevra": "0:tree-1.7.0-15.el8.x86_64",
"release": "15.el8",
"repo": "@System",
"version": "1.7.0",
"yumstate": "installed"
},
{
"arch": "x86_64",
"epoch": "0",
"name": "tree",
"nevra": "0:tree-1.7.0-15.el8.x86_64",
"release": "15.el8",
"repo": "BaseOS",
"version": "1.7.0",
"yumstate": "available"
}
]
}

yum_repository 模块

功能: 此模块实现yum的仓库配置管理

常见选项

name #仓库id
description #仓库描述名称,对应配置文件中的name=
baseurl #仓库的地址
gpgcheck #验证开启
gpgkey #仓库公钥路径

范例

ansible websrvs -m yum_repository -a 'name=ansible_nginx description="nginxrepo" baseurl="http://nginx.org/packages/centos/$releasever/$basearch/" gpgcheck=yes gpgkey="https://nginx.org/keys/nginx_signing.key"'

[root@rocky8 ~]#cat /etc/yum.repos.d/ansible_nginx.repo
[ansible_nginx]
baseurl = http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck = 1
gpgkey = https://nginx.org/keys/nginx_signing.key
name = nginx repo

范例:

- name: Add multiple repositories into the same file (1/2)
yum_repository:
name: epel
description: EPEL YUM repo
file: external_repos
baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
gpgcheck: no
- name: Add multiple repositories into the same file (2/2)
yum_repository:
name: rpmforge
description: RPMforge YUM repo
file: external_repos
baseurl: http://apt.sw.be/redhat/el7/en/$basearch/rpmforge
mirrorlist: http://mirrorlist.repoforge.org/el7/mirrors-rpmforge
enabled: no
- name: Remove repository from a specific repo file
yum_repository:
name: epel
file: external_repos
state: absent

范例: 创建和删除仓库

[root@ansible ~]#cat yum_repo.yml
- hosts: websrvs
    tasks:
        - name: Add multiple repositories into the same file
        	yum_repository:
                name: test
                description: EPEL YUM repo
                file: external_repos
                baseurl:
                https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
                gpgcheck: no
[root@ansible ~]#ansible-playbook yum_repo.yml
[root@web1 ~]#cat /etc/yum.repos.d/external_repos.repo
[test]
baseurl = https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
gpgcheck = 0
name = EPEL YUM repo

[root@ansible ~]#cat remove_yum_repo.yml
- hosts: websrvs
	tasks:
    - name: remove repo
        yum_repository:
            name: test
            file: external_repos
            state: absent
[root@ansible ~]#ansible-playbook remove_yum_repo.yml

范例: 常见仓库

- name: Add Base Yum Repository
yum_repository:
name: base
description: Base Aliyun Repository
baseurl: http://mirrors.aliyun.com/centos/$releasever/os/$basearch/
gpgcheck: yes
gpgkey: http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
- name: Add Epel Yum Repository
yum_repository:
name: epel
description: Epel Aliyun Repository
baseurl: http://mirrors.aliyun.com/epel/7/$basearch
gpgcheck: no
- name: Add Nginx Yum Repository
yum_repository:
name: nginx
description: Nginx Repository
baseurl: http://nginx.org/packages/centos/7/$basearch/
gpgcheck: no
- name: Add PHP Yum Repository
yum_repository:
name: php71w
description: php Repository
baseurl: http://us-east.repo.webtatic.com/yum/el7/x86_64/
gpgcheck: no
- name: Add Haproxy Yum Repository
yum_repository:
name: haproxy
description: haproxy repository
baseurl: https://repo.ius.io/archive/7/$basearch/
gpgcheck: yes
gpgkey: https://repo.ius.io/RPM-GPG-KEY-IUS-7

Service 模块

此模块和sytemd功能相似,选项很多相同

功能:管理服务

常见选项

name #服务名称
state #服务状态
=started #启动
=stopped #停止
=restarted #重启
=reloaded #重载
enabled #开启自启动
daemon_reload #加载新的配置文件,适用于systemd模块

范例:

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/^Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf"
ansible all -m service -a 'name=httpd state=restarted'

#重启动指定网卡服务
ansible all -m service -a 'name=network state=restarted args=eth0'

User 模块

功能:管理用户

常见选项

name #创建的名称
uid #指定uid
group #指定基本组
shell #登录shell类型默认/bin/bash
create_home #是否创建家目录
password #设定对应的密码,必须是加密后的字符串才行,否则不生效
system #yes表示系统用户
groups #附加组
append #追加附加组使用,yes表示增加新的附加组
state #absen删除
remove #yes表示删除用户时将家目录一起删除
generate_ssh_key #创建私钥
ssh_keyu_bits #私钥位数
ssh_key_file #私钥文件路径

范例:

#创建用户
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" shell=/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'

#生成123456加密的密码
ansible localhost -m debug -a "msg={{ '123456'| password_hash('sha512','salt')}}" 
localhost | SUCCESS => {
"msg": "$6$salt$MktMKPZJ6t59GfxcJU20DwcwQzfMvOlHFVZiOVD71w."
}

#用上面创建的密码创建用户
ansible websrvs -m user -a 'name=www group=www system=yes shell=/sbin/nlogin password="$6$salt$MktMKPZJ6t59GfxcJU20DwcwQzfMvOlHFVZiOVD71w."'

#创建用户test,并生成4096bit的私钥
ansible websrvs -m user -a 'name=test generate_ssh_key=yes ssh_key_bits=4096 ssh_key_file=.ssh/id_rsa'

Group 模块

功能:管理组

常见选项

name #指定组名称
gid #指定gid
state
=present #创建,默认
=absent #删除

范例:

#创建组
ansible websrvs -m group -a 'name=nginx gid=88 system=yes'
#删除组
ansible websrvs -m group -a 'name=nginx state=absent'

Lineinfile 模块

ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时,会存在问题,无法正常进行替换 。

ansible自身提供了两个模块:lineinfile模块和replace模块,可以方便的进行替换

一般在ansible当中去修改某个文件的单行进行替换的时候需要使用lineinfile模块

功能:相当于sed,主要用于修改一行的文件内容

常见选项

path #被控端文件的路径
regexp #正则匹配语法格式,表示被替换的内容
line #替换为的内容
state #absent表示删除
insertafter #插入到替换内容前面,如和regexp同时存在,只在没找到与regexp匹配时才使用
insertafter
insertbefore #插入到替换内容后面,如和regexp同时存在,只在没找到与regexp匹配时才使用
insertafter
backrefs #支持后面引用,yes和no
backup #修改前先备份
create #如果文件不存在,则创建,默认不存在会出错
mode #指定权限
owner #指定用户
group #指定组
#注意
regexp参数 :使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最后面被
匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被删除。

注意: 如果想进行多行匹配进行替换需要使用replace模块

范例:

#修改监听端口
ansible websrvs -m lineinfile -a "path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 8080'"

#修改SELinux
ansible all -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=disabled'"

#添加网关
ansible webservers -m lineinfile -a 'path=/etc/sysconfig/network-scripts/ifcfg-eth0 line="GATEWAY=10.0.0.254"'

#给主机增加一个网关,但需要增加到NAME=下面
ansible webservers -m lineinfile -a 'path=/etc/sysconfig/network-scripts/ifcfg-eth0 insertafter="^NAME=" line="GATEWAY=10.0.0.254"'
#效果如下
cat /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
NAME=eth0
GATEWAY=10.0.0.254

#给主机增加一个网关,但需要增加到NAME=上面
ansible webservers -m lineinfile -a 'path=/etc/sysconfig/network-scripts/ifcfg-eth0 insertbefore="^NAME=" line="GATEWAY=10.0.0.254"'
#效果如下
cat /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
GATEWAY=10.0.0.254
NAME=eth0

#删除网关
ansible webservers -m lineinfile -a 'path=/etc/sysconfig/network-scripts/ifcfg-eth0 regexp="^GATEWAY" state=absent'

#删除#开头的行
ansible all -m lineinfile -a 'dest=/etc/fstab state=absent regexp="^#"'

Replace 模块

该模块有点类似于sed命令,主要也是基于正则进行匹配和替换,建议使用

功能: 多行修改替换

常见选项

path #被控端文件的路径
regexp #正则匹配语法格式,表示被替换的内容
replace #替换为的内容
after #插入到替换内容前面,
before #插入到替换内容后面
backup #修改前先备份
mode #指定权限
owner #指定用户
group #指定组

范例:

ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"
ansible all -m replace -a "path=/etc/fstab regexp='^#(UUID.*)' replace='\1'"

SELinux 模块

功能: 该模块管理 SELInux 策略

常见选项

policy #指定SELINUXTYPE=targeted
state #指定SELINUX=disabled

范例

[root@ansible ~]#ansible 10.0.0.8 -m selinux -a 'state=disabled'
[WARNING]: SELinux state temporarily changed from 'enforcing' to 'permissive'.
State change will take effect next reboot.
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"configfile": "/etc/selinux/config",
"msg": "Config SELinux state changed from 'enforcing' to 'disabled'",
"policy": "targeted",
"reboot_required": true,
"state": "disabled"
}
[root@centos8 ~]#grep -v '#' /etc/selinux/config
SELINUX=disabled
SELINUXTYPE=targeted
[root@centos8 ~]#getenforce
Permissive

reboot 模块

功能: 重启

常见选项

msg #重启提示
pre_reboot_delay #重启前延迟时间的秒数
post_reboot_delay #重启后延迟时间的秒数后,再验证系统正常启动
reboot_timeout #重启后延迟时间再执行测试成功与否的命令
test_command #执行测试成功与否的命令

范例:

[root@ansible ~]#ansible websrvs -m reboot -a 'msg="host will be reboot"'

mount 模块

功能: 挂载和卸载文件系统

常见选项

src #源设备路径,或网络地址
path #挂载至本地哪个路径下
fstype #设备类型; nfs
opts #挂载的选项
state #挂载还是卸载
	=present #永久挂载,但没有立即生效
    =absent #卸载临时挂载,并删除永久挂载
    =mounted #临时挂载
    =unmounted #临时卸载

范例:

#修改fstab文件永久挂载,但不立即生效
mount websrvs -m mount -a 'src="UUID=b3e48f45-f933-4c8e-a700-22a159ec9077"path=/home fstype=xfs opts=noatime state=present'

#临时取消挂载
mount websrvs -m mount -a 'path=/home fstype=xfs opts=noatime state=unmounted'

#永久挂载,并立即生效
ansible websrvs -m mount -a 'src=10.0.0.8:/data/wordpress path=/var/www/html/wp-content/uploads opts="_netdev" state=mounted'

#永久卸载,并立即生效
ansible websrvs -m mount -a 'src=10.0.0.8:/data/wordpress path=/var/www/html/wp-content/uploads state=absent'

Setup 模块

功能: setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机较多,会影响执行速度

可以使用 gather_facts: no 来禁止 Ansible 收集 facts 信息

常见选项

filter #指定过滤条件

范例:

ansible all -m setup
ansible all -m setup -a "filter=ansible_nodename"
ansible all -m setup -a "filter=ansible_hostname"
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"
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_uptime_seconds"
ansible all -m setup -a "filter=ansible_processor*"
ansible all -m setup -a 'filter=ansible_env'

范例:

[root@ansible ~]#ansible all -m setup -a 'filter=ansible_python_version'
10.0.0.7 | SUCCESS => {
"ansible_facts": {
"ansible_python_version": "2.7.5",
"discovered_interpreter_python": "/usr/bin/python"
},"changed": false
}
10.0.0.6 | SUCCESS => {
"ansible_facts": {
"ansible_python_version": "2.6.6",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
10.0.0.8 | SUCCESS => {
"ansible_facts": {
"ansible_python_version": "3.6.8",
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false
}
[root@ansible ~]#

范例:取IP地址

#取所有IP
ansible 10.0.0.101 -m setup -a 'filter=ansible_all_ipv4_addresses'
10.0.0.101 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.0.1",
"192.168.0.2",
"192.168.64.238",
"192.168.13.36",
"10.0.0.101",
"172.16.1.0",
"172.17.0.1"
]
},
"changed": false
}
#取默认IP
ansible all -m setup -a 'filter="ansible_default_ipv4"'
10.0.0.101 | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "10.0.0.101",
"alias": "eth0",
"broadcast": "10.0.0.255",
"gateway": "10.0.0.2",
"interface": "eth0",
"macaddress": "00:0c:29:e8:c7:9b",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "10.0.0.0",
"type": "ether"
}
},
"changed": false
}

debug 模块

功能: 此模块可以用于输出信息,并且通过 msg 定制输出的信息内容,功能类似于echo命令

注意: msg后面的变量有时需要加 " " 引起来

常见选项

msg #指定命令输出的信息
var #指定变量名,和msg互斥
verbosity #详细度

范例: debug 模块默认输出Hello world

[root@ansible ~]#ansible 10.0.0.18 -m debug
10.0.0.18 | SUCCESS => {
"msg": "Hello world!"
}

[root@ansible ansible]#cat debug.yml
---
- hosts: websrvs
	tasks:
        - name: output Hello world
        debug:
        
        #默认没有指定msg,默认输出"Hello world!"
[root@ansible ansible]#ansible-playbook debug.yml
.....
TASK [output variables]
********************************************************************************
******************************
ok: [10.0.0.7] => {
"msg": "Hello world!"
}
ok: [10.0.0.8] => {
"msg": "Hello world!"
}
PLAY RECAP
********************************************************************************
*******************************************
10.0.0.7 : ok=2 changed=0 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=2 changed=0 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0

范例: 利用debug 模块输出变量

[root@centos8 ~]#cat debug.yaml
---
- hosts: websrvs
    tasks:
        - name: output variables
        debug:
        	msg: Host "{{ ansible_nodename }}" Ip "{{ ansible_default_ipv4.address}}"
        	
[root@centos8 ~]#ansible-playbook debug.yaml
PLAY [websrvs]
********************************************************************************
***************************************
TASK [Gathering Facts]
********************************************************************************
*******************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [output variables]
********************************************************************************
******************************
ok: [10.0.0.7] => {
"msg": "Host \"centos7.ayaka.com\" Ip \"10.0.0.7\""
}
ok: [10.0.0.8] => {
"msg": "Host \"centos8.ayaka.com\" Ip \"10.0.0.8\""
}
PLAY RECAP
********************************************************************************
*******************************************
10.0.0.7 : ok=2 changed=0 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=2 changed=0 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0

范例: 显示字符串特定字符

# cat debug.yml
- hosts: all
    gather_facts: no
    vars:
    	a: "12345"
    tasks:
    - debug:
        msg:
        - "{{a[0]}}"
        - "{{a[1]}}"
        - "{{a[2]}}"
        
#定义了一个字符串变量a,如果想要获取a字符串的第3个字符,则可以使用”a[2]”获取,索引从0开始,执行上例playbook,debug的输出信息如下:

TASK [debug] *************************
ok: [test1] => {
"msg": "1"
"msg": "2"
"msg": "3"
}

sysctl 模块

功能: 修改内核参数

常见选项

name #内核参数
value #指定值
state #是否保存在sysctl.conf文件中,默认present
sysctl_set #使用sysctl -w 验证值生效

范例:

ansible websrvs -m sysctl -a 'name=net.ipv4.ip_forward value=1 state=present'

范例: 内核参数优化

- name: Change Port Range
  sysctl:
    name: net.ipv4.ip_local_port_range
    value: '1024 65000'
    sysctl_set: yes
    state: present
    reload: yes

- name: Enable Forward
  sysctl:
    name: net.ipv4.ip_forward
    value: '1'
    sysctl_set: yes
    state: present
    reload: yes

- name: Enable tcp_reuse
  sysctl:
    name: net.ipv4.tcp_tw_reuse
    value: '1'
    sysctl_set: yes
    state: present
    reload: yes

- name: Change tcp tw_buckets
  sysctl:
    name: net.ipv4.tcp_max_tw_buckets
    value: '5000'
    sysctl_set: yes
    state: present
    reload: yes

- name: Change tcp_syncookies
  sysctl:
    name: net.ipv4.tcp_syncookies
    value: '1'
    sysctl_set: yes
    state: present
    reload: yes

- name: Change tcp max_syn_backlog
  sysctl:
    name: net.ipv4.tcp_max_syn_backlog
    value: '8192'
    sysctl_set: yes
    state: present
    reload: yes

- name: Change tcp Established Maxconn
  sysctl:
    name: net.core.somaxconn
    value: '32768'
    sysctl_set: yes
    state: present
    reload: yes

- name: Change tcp_syn_retries
  sysctl:
    name: net.ipv4.tcp_syn_retries
    value: '2'
    sysctl_set: yes
    state: present
    reload: yes

- name: Change net.ipv4.tcp_synack_retries
  sysctl:
    name: net.ipv4.tcp_synack_retries
    value: '2'
    sysctl_set: yes
    state: present
    reload: yes

pam_limits

功能: 管理资源限制

范例:

- name: Optimize System File Limits
  pam_limits:
    domain: "*"
    limit_type: "{{ item.limit_type }}"
    limit_item: "nofile"
    value: "{{ item.value }}"
    dest: "/etc/security/limits.conf"  # 明确指定目标文件
  loop:
    - { limit_type: 'soft', value: '100000' }
    - { limit_type: 'hard', value: '10000' }

apt_repository 模块

功能: 此模块实现apt的仓库配置管理

常见选项

repo #仓库信息
state #添加或删除
update_cache #是否apt update,默认yes
filename #仓库文件,默认放在/etc/apt/sources.list.d/file.list

范例:

ansible ubuntu-servers -m apt_repository -a 'repo="deb http://archive.canonical.com/ubuntu focal partner" filename=google-chrome'

[root@ubuntu2004 ~]#cat /etc/apt/sources.list.d/google-chrome.list
deb http://archive.canonical.com/ubuntu focal partner

apt_key 模块

功能: 添加和删除apt key

常见选项

url #key路径
state #添加或删除

范例: 生成ceph仓库配置

#先导入key,注意先后顺序
ansible ubuntu-servers -m apt_key -a 'url=https://download.ceph.com/keys/release.asc state=present'

#再生成apt配置,如果不导入key此步会出错
ansible ubuntu-servers -m apt_repository -a 'repo="deb http://mirror.tuna.tsinghua.edu.cn/ceph/debian-pacific focal main"
filename=ansible_ceph'

#验证结果
[root@ubuntu2004 ~]#cat /etc/apt/sources.list.d/ansible_ceph.list
deb http://mirror.tuna.tsinghua.edu.cn/ceph/debian-pacific focal main

其它模块

ansible 还提供了很多针对各种应用的模块,比如

nginx_status_info
nginx_status_facts
mysql_db #需要安装MySQL-python包
mysql_user #需要安装MySQL-python包
redis
mongodb*
postgresql*
haproxy
git

Playbook

playbook介绍

Playbook 组成

  • 一个 playbook(剧本)文件是一个YAML语言编写的文本文件
  • 通常一个playbook只包括一个play
  • 一个 play的主要包括两部分: 主机和tasks. 即实现在指定一组主机上执行一个tasks定义好的任务列表。
  • 一个tasks中可以有一个或多个task任务
  • 每一个Task本质上就是调用ansible的一个module
  • 在复杂场景中,一个playbook中也可以包括多个play,实现对多组不同的主机执行不同的任务

Playbook 与 Ad-Hoc 对比

  • Playbook是对多个 AD-Hoc 的一种编排组合的实现方式
  • Playbook能控制任务执行的先后顺序
  • Playbook可以持久保存到文件中从而方便多次调用运行,而Ad-Hoc只能临时运行。
  • Playbook适合复杂的重复性的任务,而Ad-Hoc适合做快速简单的一次性任务

Playbook 核心组件

官方文档

https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#playbook-keywords

一个playbook 中由多个组件组成,其中所用到的常见组件类型如下:

  • Hosts 执行的远程主机列表
  • Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典,一个完整的代码块功能需最少元素需包括 name 和 task,一个name只能包括一个task
  • Variables 内置变量或自定义变量在playbook中调用
  • Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
  • Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断

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:!dbsrvs #在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: ayaka
        sudo: yes #默认sudo为root
        sudo_user:wang #sudo为wang

task列表和action组件

play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task

task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致

每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。

如果未提供name,则action的结果将用于输出

task两种格式:

action: module arguments #示例: action: shell wall hello
module: arguments #建议使用 #示例: shell: wall hello

注意:shell和command模块后面跟命令,而非key=value

范例:

[root@ansible ansible]#cat hello.yml
---
- hosts: websrvs
  remote_user: root
  gather_facts: no
  
  tasks:
    - name: task1
      debug: msg="task1 running"
    - name: task2
      debug: msg="task2 running"
      
- hosts: appsrvs
  remote_user: root
  gather_facts: no
  
  tasks:
    - name: task3
	  debug: msg="task3 running"
    - name: task4
      debug: msg="task4 running"

范例:

[root@ansible ansible]#cat hello.yaml
- hosts: websrvs
  remote_user: root
  gather_facts: no #不收集系统信息,提高执行效率
  
  tasks:
    - name: test network connection
        ping:
    - name: excute command
        command: wall "hello world!"

范例:

---
- hosts: websrvs
  remote_user: root
  gather_facts: no
  tasks:
    - name: install httpd
	  yum: name=httpd
	- name: start httpd
	  service: name=httpd state=started enabled=yes

其它组件说明

某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务

还可以通过"tags"给task 打标签,可在ansible-playbook命令上使用-t指定进行调用

ShellScripts VS Playbook 案例

#SHELL脚本实现
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp/tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl enable --now httpd

#Playbook实现
---
- hosts: websrvs
  remote_user: root
  gather_facts: no
  tasks:
	- name: "安装Apache"
	  yum: name=httpd
	- name: "复制配置文件"
	  copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
	- name: "复制配置文件"
	  copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
	- name: "启动Apache,并设置开机启动"
	  service: name=httpd state=started enabled=yes

playbook 命令

格式

ansible-playbook <filename.yml> ... [options]

常见选项

--syntax,--syntax-check #语法检查,功能相当于bash -n
-C --check #模拟执行dry run ,只检测可能会发生的改变,但不真正执行操作
--list-hosts #列出运行任务的主机
--list-tags #列出tag
--list-tasks #列出task
--limit 主机列表 #只针对主机列表中的特定主机执行
-i INVENTORY, --inventory INVENTORY #指定主机清单文件,通常一个项对应一个主机清单文件
--start-at-task START_AT_TASK #从指定task开始执行,而非从头开始,START_AT_TASK为任务的name
-v -vv -vvv #显示过程

范例: 一个简单的 playbook

root@ansible ansible]#cat hello.yml
---
- hosts: websrvs
  tasks:
    - name: hello
	  command: echo "hello ansible"
[root@ansible ansible]#ansible-playbook hello.yml
[root@ansible ansible]#ansible-playbook -v hello.yml

范例: 检查和限制主机

ansible-playbook file.yml --check #只检测
ansible-playbook file.yml
ansible-playbook file.yml --limit websrvs

范例: 一个playbook 多个play

cat test_plays.yaml
---
- hosts: localhost
  remote_user: root
  gather_facts: no
  tasks:
	- name: play1
	  command: echo "play1"


- hosts: webservers
  remote_user: root
  gather_facts: no
  tasks:
	- name: play2
	  command: echo "play2"

Playbook 案例

利用 playbook 创建 mysql 用户

范例:mysql_user.yml

---
- hosts: dbsrvs
  remote_user: root
  gather_facts: no
  tasks:
	- {name: create group, group: name=mysql system=yes gid=306}
	- name: create user
	  user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 home=/data/mysql create_home=no

利用 playbook 安装和卸载 httpd

范例:install_httpd.yml

[root@centos8 ansible]#cat install_httpd.yml
---
- hosts: websrvs
  remote_user: root
  gather_facts: no
  tasks:
	- name: Instal1 httpd
  	  yum: name=httpd
	- name: Modify config list port
	  lineinfile:
	    path: /etc/httpd/conf/httpd.conf
	    regexp: '^Listen'
		line: 'Listen 8080'
    - name: Modify config data1
	  lineinfile:
		path: /etc/httpd/conf/httpd.conf
		regexp: '^DocumentRoot "/var/www/html"'
		line: 'DocumentRoot "/data/html"'
	- name: Modify config data2
	  lineinfile:
		path: /etc/httpd/conf/httpd.conf
		regexp: '^<Directory "/var/www/html">'
		line: '<Directory "/data/html">'
	- 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


ansible-playbook install_httpd.yml --limit 10.0.0.8

范例:remove_httpd.yml

---
- hosts: websrvs
  remote_user: root
  gather_facts: no
  tasks:
	- name: remove httpd package
	  yum: name=httpd state=absent
	- name: remove apache user
	  user: name=apache state=absent
	- name: remove config file
	  file: name=/etc/httpd state=absent
	- name: remove web html
	  file: name=/data/html/ state=absent

利用 playbook 安装 MySQL 5.6

范例:安装mysql-5.6.46-linux-glibc2.12

[root@ansible ~]#ls -l /data/ansible/files/mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
-rw-r--r-- 1 root root 403177622 Dec 4 13:05 /data/ansible/files/mysql-5.6.46-
linux-glibc2.12-x86_64.tar.gz
[root@ansible ~]#cat /data/ansible/files/my.cnf
[mysqld]
socket=/tmp/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
log-bin
pid-file=/data/mysql/mysqld.pid


[client]
port=3306
socket=/tmp/mysql.sock

[mysqld_safe]
log-error=/var/log/mysqld.log

[root@ansible ~]#cat /data/ansible/files/secure_mysql.sh
#!/bin/bash
/usr/local/mysql/bin/mysql_secure_installation <<EOF

y
ayaka
ayaka
y
y
y
y
EOF

[root@ansible ~]#tree /data/ansible/files/
/data/ansible/files/
├── my.cnf
├── mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
└── secure_mysql.sh

[root@ansible ~]#cat /data/ansible/install_mysql.yml
- hosts: dbsrvs
  remote_user: root
  gather_facts: no
  tasks:
	- name: install packages
	  yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long
	- name: create mysql group
	  group: name=mysql gid=306
	- name: create mysql user
	  user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql
 	- name: copy tar to remote host and file mode
	  unarchive: src=/data/ansible/files/mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/ owner=root group=root
	- name: create linkfile /usr/local/mysql
	  file: src=/usr/local/mysql-5.6.46-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
	- name: data dir
	  shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql
	  tags: data
	- name: config my.cnf
	  copy: src=/data/ansible/files/my.cnf dest=/etc/my.cnf
	- name: service script
	  shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
	- name: enable service
	  shell: /etc/init.d/mysqld start;chkconfig --add mysqld;chkconfig mysqld on
	  
	  tags: service
	- name: PATH variable
	  copy: content='export PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
	- name: secure script
	  script: /data/ansible/files/secure_mysql.sh
	  tags: script

忽略错误 ignore_errors

如果一个task出错,默认将不会继续执行后续的其它task

利用 ignore_errors: yes 可以忽略此task的错误,继续向下执行playbook其它task

[root@ansible ansible]#cat test_ignore.yml
---
- hosts: websrvs
  tasks:
	- name: error
	  command: /bin/false
	  ignore_errors: yes
	- name: continue
	  command: wall continue

Playbook中使用handlers和notify

handlers和notify

Handlers本质是task list ,类似于MySQL中的触发器触发的行为,其中的task与前述的task并没有本质上的不同,只有在关注的资源发生变化时,才会采取一定的操作。

Notify对应的action 在所有task都执行完才会最后被触发,这样可避免多个task多次改变发生时每次都触发执行指定的操作,Handlers仅在所有的变化发生完成后一次性地执行指定操作。

在notify中列出的操作称为handler,也即notify中调用handler中定义的操作

注意:

  • 如果多个task通知了相同的handlers, 此handlers仅会在所有task结束后运行一 次。
  • 只有notify对应的task发生改变了才会通知handlers, 没有改变则不会触发handlers
  • handlers 是在所有前面的tasks都成功执行才会执行,如果前面任何一个task失败,会导致handler跳过执行

案例:

[root@ansible ansible]#cat install_nginx.yml
---
#install nginx
#
- hosts: websrvs
  gather_facts: no
  tasks:
	- name: install package
	  yum: name=nginx

	- name: config file
	  copy:
	    src: nginx.conf
	    dest: /etc/nginx/nginx.conf
	  notify:
		- restart nginx
		- notify message
	  tags:
	  	- config
		- name: Web Content
	  copy:
		content: "App Version {{ ansible_eth0.ipv4.address.split('.')[-1]}}"
		dest: /usr/share/nginx/html/index.html
	- name: start service
		service: name=nginx state=started enabled=yes
  handlers:
	- name: restart nginx
	  service: name=nginx state=restarted
	- name: notify message
	  debug: msg="nginx is restarted"

案例:

- hosts: websrvs
  remote_user: root
  gather_facts: no
  tasks:
	- name: Install httpd
	  yum: name=httpd state=present
	- name: Install configure file
	  copy: src=files/httpd.conf dest=/etc/httpd/conf/
	  notify:
		- restart httpd
		- wall
	- name: ensure apache is running
	  service: name=httpd state=started enabled=yes
  handlers:
	- name: restart httpd
	  service: name=httpd state=restarted
	- name: wall
	  command: wall "The config file is changed"

案例

---
- hosts: websrvs
  remote_user: root
  gather_facts: no
  tasks:
	- name: add group nginx
	  user: name=nginx state=present
	- name: add user nginx
 	  user: name=nginx state=present group=nginx
	- name: Install Nginx
	  yum: name=nginx state=present
	- name: config
	  copy: src=/root/config.txt dest=/etc/nginx/nginx.conf
	  notify: ["Restart Nginx","Check Nginx Process"] #或者下面格式
		- Restart Nginx
        - Check Nginx Process
  handlers:
	- name: Restart Nginx
	  service: name=nginx state=restarted enabled=yes
	- name: Check Nginx process
	  shell: killall -0 nginx &> /tmp/nginx.log

范例: 部署haproxy

- hosts: haservers
  tasks:
    - name: Configure Haproxy Server
	  copy:
	    src: ./haproxy.cfg.j2
	    dest: /etc/haproxy/haproxy.cfg
	  notify: Restart Haproxy Server
	- name: Started Haproxy Server
	  systemd:
		name: haproxy
		state: started
  handlers:
	- name: Restart Haproxy Server
	  systemd:
		name: haproxy
		state: restarted

force_handlers

如果不论前面的task成功与否,都希望handlers能执行, 可以使用force_handlers: yes 强制执行handler

范例: 强制调用handlers

- hosts: websrvs
  force_handlers: yes #无论task中的任何一个task失败,仍强制调用handlers
  tasks:
	- name: config file
	  copy: src=nginx.conf dest=/etc/nginx/nginx.conf
	  notify: restart nginx
	- name: install package
	  yum: name=no_exist_package
  handlers:
	- name: restart nginx
	  service: name=nginx state=restarted

Playbook中使用tags组件

官方文档:

https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_tags.html

默认情况下, Ansible 在执行一个 playbook 时,会执行 playbook 中所有的任务

在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特定tags的task,而非整个playbook文件

可以一个task对应多个tag,也可以多个task对应同一个tag

还有另外3个特殊关键字用于标签, tagged, untagged 和 all,它们分别是仅运行已标记,只有未标记和所有任务。

tags 主要用于调试环境

范例: tag 标签

vim httpd.yml
---
# tags example
- hosts: websrvs
  remote_user: root
  gather_facts: no
  tasks:
	- name: Install httpd
	  yum: name=httpd state=present
	- name: Install configure file
	  copy: src=files/httpd.conf dest=/etc/httpd/conf/
	  tags: [ conf,file ] #写在一行
		- conf #写成多行
		- file
	- name: start httpd service
	  tags: service
	    service: name=httpd state=started enabled=yes

#列出标签
[root@ansible ~]#ansible-playbook --list-tags httpd.yml

#执行有指定标签的任务
[root@ansible ~]#ansible-playbook -t conf,service httpd.yml

#忽略执行指定标签的task
[root@ansible ~]#ansible-playbook --skip-tags conf httpd.yml

#忽略执行没有标签的任务,即只执行有标签的任务
[root@ansible ~]#ansible-playbook httpd.yml --skip-tags untagged

Playbook中使用变量

Playbook中同样也支持变量

变量名:仅能由字母、数字和下划线组成,且只能以字母开头

变量定义:

variable=value
variable: value

范例:

http_port=80
http_port: 80

变量调用方式:

通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效

变量来源:

  1. ansible 的 setup facts 远程主机的所有变量都可直接调用
  2. 通过命令行指定变量,优先级最高
ansible-playbook -e varname=value test.yml
  1. 在playbook文件中定义
vars:
  var1: value1
  var2: value2
  1. 在独立的变量YAML文件中定义
- hosts: all
  vars_files:
	- vars.yml
  1. 在主机清单文件中定义

主机(普通)变量:主机组中主机单独定义,优先级高于公共变量

组(公共)变量:针对主机组中所有主机定义统一变量

  1. 在项目中针对主机和主机组定义

在项目目录中创建 host_vars和group_vars目录

  1. 在role中定义

变量的优先级从高到低如下

-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名文件 -->主机清单中主机变量--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组变量

使用 setup 模块中变量

使用 facts 变量

本模块自动在playbook调用,生成的系统状态信息, 并将之存放在facts变量中

facts 包括的信息很多,如: 主机名,IP,CPU,内存,网卡等

facts 变量的实际使用场景案例

  • 通过facts变量获取被控端CPU的个数信息,从而生成不同的Nginx配置文件
  • 通过facts变量获取被控端内存大小信息,从而生成不同的memcached的配置文件
  • 通过facts变量获取被控端主机名称信息,从而生成不同的Zabbix配置文件
  • 通过facts变量获取被控端网卡信息,从而生成不同的主机名

案例:使用setup变量

ansible localhost -m setup -a 'filter="ansible_default_ipv4"'
10.0.0.101 | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "10.0.0.101",
"alias": "eth0",
"broadcast": "10.0.0.255",
"gateway": "10.0.0.2",
"interface": "eth0",
"macaddress": "00:0c:29:e8:c7:9b",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "10.0.0.0",
"type": "ether"
}
},
"changed": false
}

[root@centos8 ~]#ansible localhost -m setup -a "filter=ansible_nodename"
10.0.0.8 | SUCCESS => {
"ansible_facts": {
"ansible_nodename": "centos8.wang.org",
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false
}

范例:

---
#var1.yml
- hosts: all
  remote_user: root
  gather_facts: yes
  tasks:
	- name: create log file
  	  file: name=/data/{{ ansible_nodename }}.log state=touch owner=wang mode=600

[root@ansible ~]#ansible-playbook var.yml

范例: 显示 eth0 网卡的 IP 地址

[root@ansible ansible]#cat show_ip.yml
- hosts: websrvs
  tasks:
	- name: show eth0 ip address {{ ansible_facts["eth0"]["ipv4"]["address"] }}
    debug:
      msg: IP address {{ ansible_eth0.ipv4.address }}
      #msg: IP address {{ ansible_facts["eth0"]["ipv4"]["address"] }}
      #msg: IP address {{ ansible_facts.eth0.ipv4.address }}
      #msg: IP address {{ ansible_default_ipv4.address }}
      #msg: IP address {{ ansible_eth0.ipv4.address }}
      #msg: IP address {{ ansible_eth0.ipv4.address.split('.')[-1] }}#取IP中的最后一个数字
[root@ansible ansible]#ansible-playbook -v show_ip.yml

范例: 修改主机名形式为 web_IP

[root@centos8 ~]#cat hostname.yaml
- hosts: all
  tasks:
	- name: 打印facts变量的内容
	  debug: msg={{ ansible.default.ipv4.address }}
	- name: 用hostname模块将主机名修改为web_ip
	  hostname: name=web-{ ansible.default.ipv4.address }}
	#- name: 获取facts变量提取IP地址,以.结尾的最后一列,修改主机名为web-hostid
	  #hostname: name=web-{{ ansible.eth0.ipv4.address.split('.')[-1] }}

性能优化

每次执行playbook,默认会收集每个主机的所有facts变量,将会导致速度很慢,可以采用下面方法加速

方法1

关闭facts采集加速执行,此方法将导致无法使用facts变量

- hosts: all
  gather_facts: no
方法2

当使用 gather_facts: no 关闭 facts,确实能加速 Ansible 执行,但是有时候又需要使用 facts 中的内容,还希望执行的速度快,这时候可以设置facts 的缓存,将facts变量信息存在redis服务器中

[root@ansible ~]# cat /etc/ansible/ansible.cfg
[defaults]
# smart 表示默认收集 facts,但 facts 已有的情况下不会收集,即使用缓存 facts
# implicit 表示默认收集 facts,要禁止收集,必须使用 gather_facts: False
# explicit 则表示默认不收集,要显式收集,必须使用gather_facts: True

gathering = smart #在使用 facts 缓存时设置为smart
fact_caching_timeout = 86400 #缓存时长
fact_caching = redis #缓存存在redis中
fact_caching_connection = 10.0.0.100:6379:0 #0表示redis的0号数据库
#若redis设置了密码
fact_caching_connection = 10.0.0.100:6379:0:password

在playbook 命令行中定义变量

vim var2.yml
---
- hosts: websrvs
  remote_user: root
  tasks:
	- name: install package
	  yum: name={{ pkname }} state=present
[root@ansible ~]#ansible-playbook -e pkname=httpd var2.yml

范例:

#也可以将多个变量放在一个文件中
[root@ansible ~]#cat vars
pkname1: memcached
pkname2: vsftpd
[root@ansible ~]#vim var2.yml
---
- hosts: websrvs
  remote_user: root
  tasks:
	- name: install package {{ pkname1 }
	  yum: name={{ pkname1 }} state=present
	- name: install package {{ pkname2 }
	  yum: name={{ pkname2 }} state=present
[root@ansible ~]#ansible-playbook -e pkname1=memcached -e pkname2=httpd var5.yml
[root@ansible ~]#ansible-playbook -e '@vars' var2.yml

在playbook文件中定义变量

此方式定义的是私有变量,即只能在当前playbook中使用,不能被其它Playbook共用

范例:

[root@ansible ~]#vim var3.yml
---
- hosts: websrvs
  remote_user: root
  vars:
    username: user1
    groupname: group1
  tasks:
	- name: create group {{ groupname }}
	  group: name={{ groupname }} state=present
	- name: create user {{ username }}
	  user: name={{ username }} group={{ groupname }} state=present

[root@ansible ~]#ansible-playbook -e "username=user2 groupname=group2" var3.yml

范例:变量的相互调用

[root@ansible ~]#cat var4.yaml
---
- hosts: websrvs
  remote_user: root
  vars:
	collect_info: "/data/test/{{ansible_default_ipv4['address']}}/"
  tasks:
  - name: create IP directory
	file: name="{{collect_info}}" state=directory



#执行结果
tree /data/test/
/data/test/
└── 10.0.0.102
1 directory, 0 files

使用专用的公共的变量文件

可以在一个独立的playbook文件中定义公共变量,在其它的playbook文件中可以引用变量文件中的变量

此方式比playbook中定义的变量优化级高

vim vars.yml
---
# variables file
package_name: mariadb-server
service_name: mariadb

vim var5.yml
---
#install package and start service
- hosts: dbsrvs
  remote_user: root
  vars_files:
	- vars.yml
  tasks:
	- name: install package
  	  yum: name={{ package_name }}
	  tags: install
	- name: start service
	  service: name={{ service_name }} state=started enabled=yes

在主机清单中定义主机和主机组的变量

所有项目的主机变量

在inventory 主机清单文件中为指定的主机定义变量以便于在playbook中使用

范例:

[websrvs]
www1.wang.org http_port=80 maxRequestsPerChild=808
www2.wang.org http_port=8080 maxRequestsPerChild=909

所有项目的组(公共)变量

在inventory 主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变是同名,优先级低于主机变量

案例案例

范例:

[websrvs:vars]
http_port=80
ntp_server=ntp.wang.org
nfs_server=nfs.wang.org
[all:vars]
# --------- Main Variables ---------------
# Cluster container-runtime supported: docker, containerd
CONTAINER_RUNTIME="docker"
# Network plugins supported: calico, flannel, kube-router, cilium, kube-ovn
CLUSTER_NETWORK="calico"
# Service proxy mode of kube-proxy: 'iptables' or 'ipvs'
PROXY_MODE="ipvs"
# K8S Service CIDR, not overlap with node(host) networking
SERVICE_CIDR="192.168.0.0/16"
# Cluster CIDR (Pod CIDR), not overlap with node(host) networking
CLUSTER_CIDR="172.16.0.0/16"
# NodePort Range
NODE_PORT_RANGE="20000-60000"
# Cluster DNS Domain
CLUSTER_DNS_DOMAIN="magedu.local."

针对当前项目的主机和主机组的变量

上面的方式是针对所有项目都有效,而官方更建议的方式是使用ansible特定项目的主机变量和组变量生产建议在每个项目对应的目录中创建额外的两个变量目录,分别是host_vars和group_vars

  • host_vars下面的文件名和主机清单主机名一致,针对单个主机进行变量定义
    • 格式:host_vars/hostname
  • group_vars下面的文件名和主机清单中组名一致, 针对单个组进行变量定义
    • 格式: gorup_vars/groupname
  • group_vars/all文件内定义的变量对所有组都有效

范例: 特定项目的主机和组变量

[root@ansible ansible]#pwd
/data/ansible
[root@ansible ansible]#mkdir host_vars
[root@ansible ansible]#mkdir group_vars

[root@ansible ansible]#cat host_vars/10.0.0.8
id: 2
[root@ansible ansible]#cat host_vars/10.0.0.7
id: 1
[root@ansible ansible]#cat group_vars/websrvs
name: web
[root@ansible ansible]#cat group_vars/all
domain: wang.org


[root@ansible ansible]#tree host_vars/ group_vars/
host_vars/
├── 10.0.0.7
└── 10.0.0.8
group_vars/
├── all
└── websrvs

[root@ansible ansible]#cat test.yml
- hosts: websrvs
  tasks:
	- name: get variable
	  command: echo "{{name}}{{id}}.{{domain}}"
	  register: result
	- name: print variable
	  debug:
	  msg: "{{result.stdout}}"
	  
[root@ansible ansible]#ansible-playbook test.yml
PLAY [websrvs]
********************************************************************************
***************************************
TASK [Gathering Facts]
********************************************************************************
*******************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [get variable]
********************************************************************************
**********************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [print variable]
********************************************************************************
********************************
ok: [10.0.0.7] => {
"msg": "web1.wang.org"
}
ok: [10.0.0.8] => {
"msg": "web2.wang.org"
}
PLAY RECAP
********************************************************************************
*******************************************
10.0.0.7 : ok=3 changed=1 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=3 changed=1 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0

register 注册变量

在playbook中可以使用register将捕获命令的输出保存在临时变量中,方便后续调用此变量,比如可以使用debug模块进行显示输出

范例: 利用debug 模块输出变量

[root@centos8 ~]#cat register1.yml
- hosts: dbsrvs
  tasks:
	- name: get variable
	  shell: hostname
	  register: name
	- name: "print variable"
	  debug:
	  msg: "{{ name }}" #输出register注册的name变量的全部信息,注意变量要加" "引起来
#msg: "{{ name.cmd }}" #显示命令
#msg: "{{ name.rc }}" #显示命令成功与否
#msg: "{{ name.stdout }}" #显示命令的输出结果为字符串形式,所有结果都放在一行里显示,适合于结果是单行输出
#msg: "{{ name.stdout_lines }}" #显示命令的输出结果为列表形式,逐行标准输出,适用于多行显示
#msg: "{{ name['stdout_lines'] }}" #显示命令的执行结果为列表形式,和效果上面相同
#msg: "{{ name.stdout_lines[0] }}" #显示命令的输出结果的列表中的第一个元素
#说明第一个 task 中,使用了 register 注册变量名为 name ;当 shell 模块执行完毕后,会将数据放到该变量中。第二给 task 中,使用了 debug 模块,并从变量name中获取数据。

[root@centos8 ~]#ansible-playbook register1.yml
PLAY [dbsrvs]
********************************************************************************
****************************************
TASK [Gathering Facts]
********************************************************************************
*******************************
ok: [10.0.0.7]
ok: [10.0.0.18]
TASK [get variable]
********************************************************************************
**********************************
changed: [10.0.0.7]
changed: [10.0.0.18]
TASK [print variable]
********************************************************************************
********************************
ok: [10.0.0.7] => {
"msg": {
"changed": true,
"cmd": "hostname",
"delta": "0:00:00.003054",
"end": "2021-01-27 20:30:39.261396",
"failed": false,
"rc": 0,
"start": "2021-01-27 20:30:39.258342",
"stderr": "",
"stderr_lines": [],
"stdout": "centos7.ayaka.com",
"stdout_lines": [
"centos7.ayaka.com"
]
}
}

迭代 loop (with_items)

对迭代项的引用,固定内置变量名为"item"

要在task中使用with_items给定要迭代的元素列表

注意: ansible2.5版本后,可以用loop代替with_items

列表元素格式:

- 字符串
- 字典
# cat install_packages.yml
- hosts: webservers
  tasks:
	- name: Installed Httpd Php-fpm Package
	  yum: name={{ pack }} state=latest
	  vars:
	    pack:
		  - httpd
		  - php-fpm
#方法2
# cat install_packages2.yml
- hosts: webservers
  tasks:
	- name: Installed Httpd Php-fpm Package
	  yum:
	    name={{ item }}
	    state=latest
	  loop:
		- httpd
	-	 php-fpm

迭代嵌套子变量

在迭代中,还可以嵌套子变量,关联多个变量在一起使用

范例:

- name: Create two hard links
  file:
    src: '/tmp/{{ item.src }}'
	dest: '{{ item.dest }}'
    state: hard
  loop:
	- { src: x, dest: y }
	- { src: m, dest: n }

Roles 角色

角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结
构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即
可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便
捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进
程等场景中
运维复杂的场景:建议使用 roles,代码复用度高
roles:多个角色的集合目录, 可以将多个的role,分别放至roles目录下的独立子目录中,如下示例

roles/
    mysql/
    nginx/
    tomcat/
    redis/

默认roles存放路径

/root/.ansible/roles
/usr/share/ansible/roles
/etc/ansible/roles

Ansible Roles目录编排

roles目录结构:

playbook1.yml
playbook2.yml
roles/
    project1/
        tasks/
        files/
        vars/
        templates/
        handlers/
        default/
        meta/
    project2/
        tasks/
        files/
        vars/
        templates/
        handlers/
        default/
        meta/

Roles各目录作用

roles/project/ :项目名称,有以下子目录

  • files/ :存放由copy或script模块等调用的文件
  • templates/:template模块查找所需要模板文件的目录
  • tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
  • handlers/:至少应该包含一个名为main.yml的文件;此目录下的其它的文件需要在此文件中通过include进行包含
  • vars/:定义变量,至少应该包含一个名为main.yml的文件;此目录下的其它的变量文件需要在此文件中通过include进行包含,也可以通过项目目录中的group_vars/all定义变量,从而实现角色通用代码和项目数据的分离
  • meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
  • default/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低

创建 role

创建role的步骤

1 创建role的目录结构.在以roles命名的目录下分别创建以各角色名称命名的目录,如mysql等,在每个角
色命名的目录中分别创建相关的目录和文件,比如tasks、files、handlers、templates和vars等目录;
用不到的目录可以创建为空目录,也可以不创建
2 编写和准备指定role的功能文件,包括: tasks,templates,vars等相关文件
3 编写playbook文件调用上面定义的role,应用到指定的主机

针对大型项目使用Roles进行编排
范例: 利用 ansible-galaxy 创建角色目录的结构

#创建初始化目录结构
[root@ansible roles]#ansible-galaxy role init test_role
- Role test_role was created successfully
[root@ansible roles]#tree test_role/
test_role/
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
8 directories, 8 files

范例:roles的目录结构

nginx-role.yml
roles/
└── nginx
├── files
│ └── nginx.conf
├── tasks
│ ├── groupadd.yml
│ ├── install.yml
│ ├── main.yml
│ ├── restart.yml
│ └── useradd.yml
└── vars
└── main.yml

Playbook 调用角色

调用角色方法1:

---
- hosts: websrvs
  remote_user: root
  roles:
	- mysql
	- memcached
	- nginx

调用角色方法2:
键role用于指定角色名称,后续的k/v用于传递变量给角色

---
- hosts: all
  remote_user: root
  roles:
	- role: mysql
  	  username: mysql
	- { role: nginx, username: nginx }

Roles 中 Tags 使用

[root@ansible ~]#vi app-role.yml
---
#可以有多个play
- hosts: lbserver
  roles:
	- role: haproxy
	- role: keepalived
	
- hosts: appsrvs
  remote_user: root
  roles:
	- { role: nginx ,tags: [ 'nginx', 'web' ] ,when:ansible_distribution_major_version == "6" }
	- { role: httpd ,tags: [ 'httpd', 'web' ] }
	- { role: mysql ,tags: [ 'mysql', 'db' ] }
	- role: mariadb
	  tags:
		- mariadb
		- db
  tags: app #play的tag
  
  
[root@ansible ~]#ansible-playbook --tags="nginx,mysql" app-role.yml

评论