Ansible自动化运维_ansible

1.Ansible 介绍和架构

1.1 Ansible 发展历史

作者:Michael DeHaan( Cobbler 与 Func 作者) ansible 的名称来自科幻小说《安德的游戏》中跨 越时空的即时通信工具,使用它可以在相距数光年的距离,远程实时控制前线的舰队战斗。 2012-03-09,发布0.0.1版,2015-10-17,Red Hat宣布1.5亿美元收购 ,IBM收购了红帽

官网:https://www.ansible.com/
官方文档:https://docs.ansible.com/

1.2 Ansible特性

Ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、chef、func、 fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。 Ansible是基于 paramiko 开发的,并且基于模块化工作,本身没有批量部署的能力。真正具有批量部署 的是Ansible所运行的模块,Ansible只是提供一种框架。Ansible不需要在远程主机上安装 client/agents,因为它们是基于ssh来和远程主机通讯的。Ansible目前已经已经被红帽官方收购,是自动化运维工具中大家认可度最高的,并且上手容易,学习简单。是每位运维工程师必须掌握的技能之 一

  • 部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作
  • Ansible自动化工具基于python语言
  • Ansible自动化管理基于SSH远程连接协议
  • 模块化:调用特定的模块完成特定任务,支持自定义模块,可使用任何编程语言写模块
  • 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
  • 支持playbook编排任务,YAML格式,编排任务,支持丰富的数据结构
  • 较强大的多层解决方案 role

1.3 Ansible架构


Ansible自动化运维_ansible_02

  • INVENTORY:Ansible管理主机的清单/etc/anaible/hosts
  • MODULES:Ansible执行命令的功能模块,多数为内置核心模块,也可自定义
  • PLUGINS:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用
  • API:供第三方程序调用的应用程序编程接口
  • USER 普通用户,即SYSTEM ADMINISTRATOR
  • PLAYBOOKS:任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执 行,通常是JSON格式的YML文件
  • CMDB(配置管理数据库)API 调用
  • PUBLIC/PRIVATE CLOUD API调用
  • USER-> Ansible Playbook -> Ansibil

1.4 注意事项

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

2.Ansible安装

2.1 基于EPEL源安装

实验环境:Centos 7

# 安装epel源 
[root@web ~]# yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
# 查看系统中是否安装源
[root@web ~]# rpm -qa | grep epel
epel-release-7-14.noarch
[root@web ~]# yum info ansible  #查看ansible包信息
[root@web ~]# yum -y install ansible
[root@web ~]# ansible --version # 查看ansible版本信息

2.2 Redhat 8安装报错信息

Ansible自动化运维_配置文件_03

# 报错信息:
没有提供ansible-5.4.0-3.el8.noarch所需的(ansible core>=2.12.2,ansible core<2.13)
(尝试添加“–skip break”以跳过可卸载的包,或添加“–nobest”以不仅使用最佳候选包)
# 解决办法:
更换yum源
配置yum源使用Centos-stream.repo
上传到 /etc/yum.repos.d/目录

2.3 安装Ansible出现依赖关系

# 解决办法:
1.清除所有的yum源
[root@ansible-master ~]# cd /etc/yum.repos.d/
[root@ansible-master yum.repos.d]# rm -rf *

2.重新拉取阿里镜像源
[root@ansible-master ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

3.安装epel源,使用rpm包的方式
[root@ansible-master ~]# rpm -Uvh http://mirrors.ustc.edu.cn/epel/epel-release-latest-7.noarch.rpm

4.清除yum
[root@ansible-master ~]# yum clean all

5.重新建立缓存
[root@ansible-master ~]# yum makecache 

6.重新下载Ansible软件包
[root@ansible-master ~]# yum -y install ansible

3.Ansible相关文件

3.1 Ansible主配置文件

Ansible的主配置文件:/etc/ansible/ansible.cfg,其中配置文件中大部分配置被注释,使用默认配置

[root@localhost~]#vim /etc/ansible/ansible.cfg
[defaults]
$ansible主机清单列表文件:定义ansible管理主机IP地址
#inventory = /etc/ansible/hosts
$库文件存放目录
#library        = /usr/share/my_modules/
$ansible管理远程主机时,生成ansible临时文件路径
#remote_tmp = ~/.ansible/tmp
$ansible管理端本地临时文件
#local_tmp = ~/.ansible/tmp
$ansible管理并发数
#forks = 5
$设置默认执行ansible命令的用户
#sudo_user = root
$每次执行ansible命令需要输入远程主机sudo用户密码
#ask_sudo_pass = True
$默认连接的端口号
#remote_port    = 22
$检查对应服务器的host_key,建议取消注释 
#host_key_checking = False
$日志文件
#log_path = /var/log/ansible.log

配置如下

[root@localhost ~ ]# egrep -v '^$|^#' /etc/ansible/ansible.cfg
[defaults]
host_key_checking = False
log_path = /var/log/ansible.log

Ansible常用参数详解:

[defaults]          #通用默认配置
inventory      = /etc/ansible/hosts     #被控制端IP或者DNS列表
library        = /usr/share/my_modules/     ##默认搜寻模块的位置
remote_tmp     = ~/.ansible/tmp            #远程执行临时文件
local_tmp      = ~/.ansible/tmp
plugin_filters_cfg = /etc/ansible/plugin_filters.yml
forks          = 5      ##并行线程数
poll_interval  = 15     ##回频率或轮询间隔时间
sudo_user      = root       ##sudo远程执行用户名
ask_sudo_pass = True        ##使用sudo,是否需要输入密码
ask_pass      = True        ##是否需要输入密码
transport      = smart      ##通信机制
remote_port    = 22         ##远程SSH端口
module_lang    = C          ##模块和系统之间通信的语言
module_set_locale = False
gathering = implicit        ##控制默认facts收集(远程系统变量)
gather_subset = all
gather_timeout = 10
roles_path    = /etc/ansible/roles      ##使用playbook搜索Ansible roles
host_key_checking = False       ##是否检查远程主机密钥
sudo_exe = sudo         ##sudo远程执行命令
sudo_flags = -H -S -n       ##传递sudo之外的参数
timeout = 10            ##SSH超时时间
remote_user = root      ##远程登录用户名
log_path = /var/log/ansible.log     ##日志文件存放路径
module_name = command       ##Ansible命令默认执行的模块
executable = /bin/sh        ##执行的shell环境,用户shell模块
hash_behaviour = replace    ##特定的优先级覆盖变量
jinja2_extensions = jinja2.ext.do,jinja2.ext.i18    ##允许开启jinja2扩展模块
private_key_file = /path/to/file    ##私钥文件存储位置
display_skipped_hosts = True        ##显示跳过任何任务的状态
system_warnings = True      ##禁用系统运行Ansible潜在问题警告
deprecation_warnings = True     ##PlayBook输出禁用“不建议使用”警告
command_warnings = False    ##command模块Ansible默认发出警告
nocolor = 1         ##输出带上颜色区别,0表示开启,1表示关闭
pipelining = False      ##开启pipe SSH通道优化

[accelerate]        ##accelerate缓存加速
accelerate_port = 5099      ##加速连接端口5099
accelerate_timeout = 30     ##命令执行超过时间,单位为s
accelerate_connect_timeout = 5.0    ##上一个活动连接的时间,单位为min
accelerate_daemon_timeout = 30      ##允许多个私钥被加载到daemon
accelerate_multi_key = yes      ##任何客户端想要连接daemon都要开启这个选项

Ansible配置文件优先级

Ansible的配置文件优先级遵循一定的规则,以下是配置文件的优先级顺序:

  1. 执行ansible命令的当前目录中是否存在 ansible.cfg 文件
  2. 当前用户的家目录下是否存在 .ansible.cfg 文件
  3. /etc/ansible/ansible.cfg默认配置文件

在运行Ansible命令时,命令将会按照以上顺序查找配置文件,优先使用高优先级的配置文件中的设置。如果当前目录下存在ansible.cfg 文件,则优先使用该文件中的配置,忽略其他低优先级的配置文件。如果当前目录下不存在 ansible.cfg 文件,但当前用户的家目录下存在 .ansible.cfg 文件,则使用该配置文件中的设置。如果以上两个路径下的配置文件都不存在,则使用默认的 /etc/ansible/ansible.cfg 配置文件中的设置。

此外,还可以通过环境变量来设置Ansible的配置,例如设置 ANSIBLE_CONFIG 环境变量来指定配置文件的路径。使用环境变量可以覆盖其他配置文件中的设置,具有最高的优先级。

3.2 Ansible 主机清单 inventory

Ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file主机清单文件找那个定义管理目标主机信息(IP地址,SSH端口,SSH密码);默认的inventory file为/etc/ansible/hosts

3.2.1 指明地址

直接指明主机地址或主机名(需要在/etc/hosts解析)

[root@ansible-master ~]# vim /etc/hosts
[root@ansible-master ~]# tail -n 3 /etc/hosts
192.168.80.132 ansible-master
192.168.80.147 ansible-apache
192.168.80.151 ansible-mysql
3.2.2 地址分组

把管理相同主机分为一组,统一进行管理
示例

[组名]
IP: [SSH_PORT]

例如:
[root@ansible-master ~]# vim /etc/ansible/hosts 
[root@ansible-master ~]# egrep -v '^$|^#' /etc/ansible/hosts 
[Apache]  #把主机分组整合,便于执行相同操作
192.168.80.147:22 # 默认端口号为22,可以省略不写
[MySQL]
192.168.80.151
[root@ansible-master ~]#
3.2.3 通配符

利用通配符配置多台连续主机IP地址

[websrvs]
www[1:100].example.com
[dbsrvs]
db-[a:f].example.com
[appsrvs]
10.0.0.[1:100]
3.2.4 主机变量

你可以为主机定义变量,这些变量可以在 playbook、任务或模块中使用。在主机清单中,你可以使用缩进的方式定义变量,如下所示:

[kps_server]
server1 ansible_host=119.96.231.32 ansible_user=root ansible_ssh_port=9022 ansible_ssh_pass=Gizakps@1289 ansible_python_interpreter=/usr/bin/python
server2 ansible_host=36.111.203.105 ansible_user=root ansible_ssh_port=9022 ansible_ssh_pass=Gizakps@1289 ansible_python_interpreter=/usr/bin/python
3.2.5 主机元数据和条件语句

主机元数据和条件语句来进一步定制化你的主机清单。例如,你可以使用条件语句来根据主机的操作系统或其他条件来应用不同的配置或变量

[webservers]  
web1.example.com ansible_os_family=Debian web_server_port=80 web_server_proto=http  
web2.example.com ansible_os_family=RedHat web_server_port=80 web_server_proto=https
3.2.6 自定义清单文件路径

使用自定义的清单文件路径而不是默认路径,可以使用 -i 参数指定路径。例如:ansible -i /path/to/inventory ...这将告诉 Ansible 在指定的路径下查找清单文件。确保指定的路径是正确的,并且清单文件具有正确的格式和语法

3.3 Ansible相关工具

工具命令

说明

ansible

主程序,临时命令执行工具

ansible-doc

查看配置文档,模块功能查看工具,相当于man

ansible-playbook

定制自动化任务,编排剧本工具,相当于脚本

ansible-pull

远程执行命令的工具

ansible-vault

文件加密工具

ansible-console

基于Console界面与用户交互的执行工具

ansible-galaxy

下载/上传优秀代码或Roles模块的官网平台

3.3.1 Ansible

主程序,临时命令执行工具

# 语法:ansible <host-pattern> [option] [-m module_name] [-a args]
#host-pattern 从主机清单文件中匹配指定管理的主机
#optional ansible参数
#module_name ansible管理模块
#args 复杂模块需要指定模块的参数

参数

说明

ansible --version

显示ansible版本信息

ansible -v

显示执行命令详细过程,-vv -vvv -vvvv -vvvvv 更加详细

ansible --list | --list-hosts

显示主机列表

ansible -k

ansible默认基于ssh秘钥验证,ansible -k 以密码口令验证,只允许输入一次

ansible -C

检查,并不执行

ansible -T <10>

执行命令的超时时间,默认10s

ansible -u

执行远程执行的用户

ansible -b

执行sudo

ansible --become-user=

指定sudo的runas用户,默认为root

ansible -K

提示输入sudo时的口令

1.查看主机清单

[root@ansible-master ~]# ansible all --list-hosts  # 查看所有的主机清单
  hosts (2):
    192.168.80.147
    192.168.80.151
[root@ansible-master ~]# ansible MySQL --list-hosts # 查看组名为MySQL的主机清单
  hosts (1):
    192.168.80.151
[root@ansible-master ~]# ansible Apache --list-hosts
  hosts (2):
    192.168.80.147
    192.168.80.151
[root@ansible-master ~]# ansible '*' --list-hosts  # 支持通配符
  hosts (2):
    192.168.80.147
    192.168.80.151
[root@ansible-master ~]# ansible 192.168.80.* --list-hosts
  hosts (2):
    192.168.80.151
    192.168.80.147
[root@ansible-master ~]# ansible 'Apache:MySQL' --list-hosts # 逻辑或:匹配多个主机清单并集
  hosts (2):
    192.168.80.147
    192.168.80.151
[root@ansible-master ~]# ansible 'Apache:&MySQL' --list-hosts # 逻辑与:匹配多个主机清单交集
  hosts (1):
    192.168.80.151
[root@ansible-master ~]# ansible 'Apache:!MySQL' --list-hosts # 逻辑非:匹配第一个主机清单与其他主机清单中独有的主机
  hosts (1):
    192.168.80.147
[root@ansible-master ~]#

2.以用户root的身份进行连接

[root@ansible-master ~]# ansible MySQL -u root -k -m command -a 'ls /root'
SSH password: 
192.168.80.151 | CHANGED | rc=0 >>
anaconda-ks.cfg
ecshop
ecshop-4.1.12.zip
ecshop.zip
LOIC-1.0.8-binary.zip
PikachuSQL布尔盲注.txt
充值系统.zip
[root@ansible-master ~]#

3.支持正则表达式

[root@ansible-master ~]# ansible "~(MySQL|Apache)" -m ping
192.168.80.147 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.80.151 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
[root@ansible-master ~]#

Ansible命令执行过程

  1. 加载自己的配置文件,默认 /etc/ansible/ansible.cfg
  2. 查找对应的主机配置文件,找到要执行的主机或者组
  3. 加载自己对应的模块文件,如 command
  4. 通过ansible将模块或命令生成对应的临时py文件(python脚本), 并将该文件传输至远程服务器
  5. 对应执行用户的家目录的 .ansible/tmp/XXX/XXX.PY 文件
  6. 给文件 +x 执行权限
  7. 执行并返回结果
  8. 删除临时py文件, exit 0 退出

Ansible执行状态

  • 绿色:执行成功并且不需要做改变的操作
  • 黄色:执行成功并且对主机做变更
  • 红色:执行失败
  • 紫色:警告信息(忠告|建议)
  • 蓝色: 显示Ansible命令执行的过程
可以通过修改配置文件来修改Ansible默认状态
……
[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
……
3.3.2 Ansible-doc

查看配置文档,模块功能查看工具,相当于man帮助

# 语法:ansible-doc [option][module....]

# ansible-doc -l :查看ansible模块列表,支持vim的搜索操作

# ansible-doc -s :查看ansible模块的简要说明
1.列出所有的模块
[root@ansible-master ~]# ansible-doc -l 
[root@ansible-master ~]# ansible-doc -l | wc -l  # 查看所有模块的个数
3387
2.查看指定模块的帮助用法
[root@ansible-master ~]# ansible-doc ping
3.查看指定模块的简要的说明
[root@ansible-master ~]# ansible-doc -s ping
3.3.3 Ansible-vault

ansible-vault命令:用于加密解密yml文件

[root@ansible-master ~]# ansible-vault create new.yml  #创建新的加密文件
New Vault password:  # 输入加密密码
Confirm New Vault password:  # 确认加密密码
[root@ansible-master ~]# ansible-vault view new.yml  # 查看文件
Vault password:  # 输入加密的密码
hello yml
hello world
hello ansible

[root@ansible-master ~]# cat new.yml #查看加密后的文件,会发现加密
$ANSIBLE_VAULT;1.1;AES256
64366534373361376439313037313637343237643337376262633531643631343731336262303538
3034616530343063313239333037316565323934613265320a326433656264386461663338316633
33363931623334346162363034666632646539343966393661623532383332623935393132616166
6532643165343333620a646432396630343365613633386635353835313832623438396533383334
66623638343633626564313637623763326136383864363636313837366434353361306330656231
6465323563343435316263353262353036353562313863626534
[root@ansible-master ~]# ansible-vault decrypt new.yml  #解密加密的文件
Vault password: 
Decryption successful
[root@ansible-master ~]# cat new.yml  # 查看文件
hello yml
hello world
hello ansible

[root@ansible-master ~]# ansible-vault encrypt new.yml  # 加密文件
New Vault password: 
Confirm New Vault password: 
Encryption successful
[root@ansible-master ~]# ansible-vault edit new.yml   # 编辑加密文件 
Vault password:  
[root@ansible-master ~]# ansible-vault rekey new.yml  # 修改加密文件的密码
Vault password: 
New Vault password: 
Confirm New Vault password: 
Rekey successful
[root@ansible-master ~]#
3.3.4 Ansible-console

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

提示符格式

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

常用子命令

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

示例:

[root@ansible-master ~]# ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
# 切换管理主机组
root@all (2)[f:5]$ cd Apache
# 并发数
root@Apache (2)[f:5]$ forks 10
# 查看组的主机列表
root@Apache (2)[f:10]$ list
192.168.80.147
192.168.80.151
# 执行模块
root@Apache (2)[f:10]$ ping
192.168.80.151 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
192.168.80.147 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
root@Apache (2)[f:10]$
3.3.5 Ansible-galaxy

ansible-galaxy命令:会连接 https://galaxy.ansible.com 下载相应的roles剧本

#列出所有已安装的galaxy
ansible-galaxy list
#安装galaxy
ansible-galaxy install geerlingguy.mysql
ansible-galaxy install geerlingguy.redis
#删除galaxy
ansible-galaxy remove geerlingguy.redis

4.如何双机互信

4.1 生成密钥

[root@ansible-master ~]# ssh-keygen

4.2 发送密钥

[root@ansible-master ~]# ssh-copy-id -i 192.168.80.147
……
root@192.168.80.147's password:  # 目标主机的密码
……

[root@ansible-master ~]# ssh-copy-id -i 192.168.80.151
……
root@192.168.80.151's password: # 目标主机的密码
……
[root@ansible-master ~]#

4.3 验证密钥

[root@ansible-master ~]# ssh ansible-mysql
Last login: Sun Oct 30 22:14:29 2022 from master
[root@ansible-mysql ~]# exit
登出
Connection to ansible-mysql closed.
[root@ansible-master ~]# ssh ansible-apache 
Last login: Sun Oct 30 22:14:37 2022 from master
[root@ansible-apache ~]# exit
登出
Connection to ansible-apache closed.
[root@ansible-master ~]#

5.Ansible常用模块

5.1 command模块

command模块:通过command模块实现在远程主机上执行命令,是ansible默认模块,可以忽略 ansible -m 选项

注意:command模块不支持一些符号: $ > >> << < | ; &&

模块子命令

说明

cmd

在远程主机上执行的命令

chdir

远程切换目录

creates

指定文件若存在,则不执行cmd

removes

指定文件若存在,则执行cmd,但是creates优先级高于removes

[root@ansible-master ~]# ansible all -a 'cat /etc/redhat-release'  # 在远程主机上查看系统版本
192.168.80.151 | CHANGED | rc=0 >> 
CentOS Linux release 7.9.2009 (Core)
192.168.80.147 | CHANGED | rc=0 >>
CentOS Linux release 7.9.2009 (Core)
[root@ansible-master ~]# ansible MySQL -a 'date'   # 在远程组上查看系统时间
192.168.80.151 | CHANGED | rc=0 >>
2022年 10月 31日 星期一 10:29:57 CST
[root@ansible-master ~]# ansible 192.168.80.147 -a 'chdir=/etc cat hostname'  # 切换文件目录,查看文件
192.168.80.147 | CHANGED | rc=0 >>
ansible-apache
[root@ansible-master ~]# ansible ansible-apache -a 'creates=/etc/hostname hostname'  # 尝试使用主机名代替IP地址,发现警告
[WARNING]: Could not match supplied host pattern, ignoring: ansible-apache
[WARNING]: No hosts matched, nothing to do
[root@ansible-master ~]# ansible 192.168.80.147 -a 'creates=/etc/hostname hostname'  # 文件若存在,则不执行cmd
192.168.80.147 | SUCCESS | rc=0 >>
skipped, since /etc/hostname exists
[root@ansible-master ~]# ansible 192.168.80.147 -a 'removes=/etc/hostname hostname' # 文件存在,则执行cmd
192.168.80.147 | CHANGED | rc=0 >>
ansible-apache
[root@ansible-master ~]#

尝试使用管道符

[root@ansible-master ~]# ansible MySQL -a 'echo 1 > 1.txt'
192.168.80.151 | CHANGED | rc=0 >>
1 > 1.txt
[root@ansible-master ~]# ansible MySQL -a 'cat 1.txt'
192.168.80.151 | FAILED | rc=1 >>
cat: 1.txt: 没有那个文件或目录non-zero return code
[root@ansible-master ~]# ansible MySQL -a 'ip a | grep ens33'
192.168.80.151 | FAILED | rc=255 >>
Command "|" is unknown, try "ip address help".non-zero return code
[root@ansible-master ~]# 

# 发现command不支持管道符

5.2 shell模块

command和shell模块的区别

  • command模块的命令不启动shell,直接通过ssh执行命令
  • command不支持bash的特性,如管道和重定向等功能
  • 所有需要调用shell的功能都无法使用
  • 不可以使用shell模块执行交互命令,如vim,top等
  • 退出SSH后所有状态失效

模块子命令

说明

cmd

在远程主机上执行的命令

chdir

远程切换目录

creates

指定文件若存在,则不执行cmd

removes

指定文件若存在,则执行cmd,默认creates的优先级高于removes

executable

指定要在远程主机上使用的shell程序。默认值为"/bin/sh"

free_form

指定要在远程主机上运行的shell命令字符串

stdin

将标准输入传递给远程主机的shell命令

warn

指定是否在命令执行时打印警告信息。可以是yes或no。默认值为yes

执行command不能执行的命令

[root@ansible-master ~]# ansible MySQL -m shell -a 'ip a | grep ens33'
192.168.80.151 | CHANGED | rc=0 >>
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.80.151/24 brd 192.168.80.255 scope global noprefixroute dynamic ens33
[root@ansible-master ~]# ansible MySQL -m shell -a 'echo 1 > 1.txt'
192.168.80.151 | CHANGED | rc=0 >>

[root@ansible-master ~]# ansible MySQL -a 'cat 1.txt'
192.168.80.151 | CHANGED | rc=0 >>
1
[root@ansible-master ~]#

从环境变量中输出主机名

[root@ansible-master ~]# ansible 192.168.80.147 -m shell -a 'echo $HOSTNAME'
192.168.80.147 | CHANGED | rc=0 >>
ansible-apache

创建新用户,并且给他更改密码

[root@ansible-master ~]# ansible 192.168.80.147 -a 'useradd demo'
192.168.80.147 | CHANGED | rc=0 >>

[root@ansible-master ~]# ansible 192.168.80.147 -m shell -a 'echo 123456 | passwd --stdin demo'
192.168.80.147 | CHANGED | rc=0 >>
更改用户 demo 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@ansible-master ~]#

其他案例:

[root@ansible-master ~]# ansible all -m shell -a 'cat /etc/passwd | wc -l' #查看目标主机用户个数
192.168.80.151 | CHANGED | rc=0 >>
22
192.168.80.147 | CHANGED | rc=0 >>
23
[root@servera ansible]# ansible client1 -m shell -a "ps | wc -l"
client1 | CHANGED | rc=0 >>
6
[root@ansible-master ~]# ansible MySQL -m shell -a 'who' # 查看有多少个用户登录目标组/主机
192.168.80.151 | CHANGED | rc=0 >>
root     pts/0        2022-10-31 09:40 (192.168.80.1)
root     pts/1        2022-10-31 10:53 (master)
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/tmp echo "hello ansibel"> 1.txt' # 在目标主机的/tmp目录下创建1.txt
192.168.80.151 | CHANGED | rc=0 >>

[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/tmp cat 1.txt'
192.168.80.151 | CHANGED | rc=0 >>
hello ansibel

验证creates

[root@servera ansible]# ansible client1 -m shell -a "ssh-keygen -f ~/.ssh/id_rsa  -N '' creates=~/.ssh/id_rsa"    #目标主机中没有~/.ssh/id_rsa私钥文件,则创建私钥文件

[root@servera ansible]# ansible client1 -m shell -a "ssh-keygen -f ~/.ssh/id_rsa  -N '' creates=~/.ssh/id_rsa"  #由于上面已经创建了一个私钥文件,所以这里的创建就跳过(skip跳过)
client1 | SUCCESS | rc=0 >>
skipped, since /root/.ssh/id_rsa exists

验证removes

第一步:在client1上安装unzip软件
[root@servera ansible]# ansible client1 -m command -a "yum -y install unzip"
第二步:在宿主机上准备一个压缩软件,通过xftp远程传输到client1(192.168.80.134)上
第三步:在clien1上使用命令scp  Ansible.zip  192.168.80.137:/root命令将Ansible.zip远程传输到client2主机上
第四步:在控制端检验
[root@servera ansible]# ansible client1 -m command -a "ls"
client1 | CHANGED | rc=0 >>
1.txt
anaconda-ks.cfg
Ansible.zip
[root@servera ansible]# ansible client2 -m command -a "ls"
client2 | CHANGED | rc=0 >>
anaconda-ks.cfg
Ansible.zip
[root@servera ansible]# 
第五步:在控制端输入命令
[root@servera ansible]# ansible client1,client2 -m shell -a "unzip  ~/Ansible.zip removes=/bin/unzip"
client2 | SUCCESS | rc=0 >>
skipped, since /bin/unzip does not exist
#因为client2中没有unzip软件,所以不执行这个命令
[WARNING]: Consider using the unarchive module rather than running 'unzip'.  If
you need to use command because unarchive is insufficient you can add 'warn:
false' to this command task or set 'command_warnings=False' in ansible.cfg to
get rid of this message.
client1 | CHANGED | rc=0 >>
Archive:  /root/Ansible.zip
  inflating: Ansible.txt             
[root@servera ansible]# ansible client1 -m command -a "ls"
client1 | CHANGED | rc=0 >>
1.txt
anaconda-ks.cfg
Ansible.txt
Ansible.zip
[root@servera ansible]# ansible client1 -m command -a "cat ~/Ansible.txt"
client1 | CHANGED | rc=0 >>
这是一个测试一个Ansible运维测试removes关键字的文件
[root@servera ansible]#

5.3 script模块

如果想要给客户端执行比较复杂的命令,则可以再本地写脚本,再拷贝到客户端并执行脚本。脚本不是shell脚本(如python,perl脚本等),可以没有-x权限

根据实验学习Script模块:

  1. 我想在客户端批量下载httpd软件包,并启动软件包,设置开机自启并且关闭防火墙
  2. 我想测试网络是否连通,使用ping -c 2 www.baidu.com这条命令测试一下
实验要求1:
# 1.编写一个启动脚本
[root@ansible-master ~]# vim start.sh 
[root@ansible-master ~]# cat start.sh 
#!/bin/bash
yum -y install httpd
systemctl restart httpd
systemctl enable httpd
systemctl stop firewalld.service
# 2.使用命令ansible  客户机  -m  script -a "./start.sh" #表示给客户机运行这个脚本里面的内容
[root@ansible-master ~]# ansible all -m script -a './start.sh'
# 3.验证结果
[root@ansible-master ~]# ansible all -m shell  -a 'systemctl status httpd'  # 查看服务是否起来
实验要求2:
[root@ansible-master ~]# vim network.sh
[root@ansible-master ~]# cat network.sh 
#!/bin/bash
ping -c 1 www.baidu.com
[root@ansible-master ~]# ansible all -m script -a './network.sh'

5.4 file模块

file模块可以创建文件,目录,链接;修改权限与属性等

特性:幂等性,任意次执行所产生的影响均与一次执行的影响相同

模块子命令

说明

path

指定操作的文件

owner

定义文件/目录的属主

group

定义文件/目录的属组

mode

定义文件/目录的权限

recurse

默认为yes:递归地设置目录内容上的指定文件属性。这只使用于“state”设置为“directory”时;no:递归创建目录时,只修改最后一级目录,其他目录则为远端主机默认权限

src

被链接的源文件路径,只应用于state=link的情况

dest

被链接到的路径,只应用于state=link的情况

state

directory:如果目录不存在,就创建目录 file:即使文件不存在,也不会被创建 link:创建软链接 hard:创建硬链接 touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新 其最后修改时间 absent:删除目录、文件或者取消链接文件

在目的主机上指定目录tmp创建文件,文件名为example.txt

# 第一种方法:使用Command创建
[root@ansible-master ~]# ansible MySQL -a 'chdir=/tmp/ touch example.txt'
# 第二种方法:使用file模块创建
[root@ansible-master ~]# ansible 192.168.80.154 -m file -a 'path=/tmp/example.txt state=touch'

在目标主机上指定目录tmp下创建一个目录,目录名称为Ansible

# 1.利用Command模块创建
[root@ansible-master ~]# ansible MySQL -a 'chdir=/tmp/ mkdir Ansible'

# 2.利用file模块创建
[root@ansible-master ~]# ansible 192.168.80.154 -m file -a 'path=/tmp/Ansible state=directory' # 创建目录
[root@ansible-master ~]# ansible 192.168.80.154 -m shell -a  "chdir=/tmp/ ls -la|grep Ansible"
192.168.80.154 | CHANGED | rc=0 >>
drwxr-xr-x   2 root root    6 10月 31 21:01 Ansible
[root@ansible-master ~]#

修改目标主机的文件或目录权限

# 第一种方法:Command模块
[root@ansible-master ~]# ansible MySQL -a 'chdir=/tmp/ chown apache:apache example.txt'  #修改所属主组
[root@ansible-master ~]# ansible MySQL -a 'chdir=/tmp/ chmod 755 example.txt'  #修改文件权限
[root@ansible-master ~]# ansible MySQL -m shell -a  "chdir=/tmp/ ls -ll|grep example.txt" # 查看文件权限
192.168.80.155 | CHANGED | rc=0 >>
-rwxr-xr-x 1 apache apache  0 10月 31 20:51 example.txt

# 第二种方法:file模块
[root@ansible-master ~]# ansible 192.168.80.154 -m file -a 'path=/tmp/example.txt owner=apache group=apache mode=755'
[root@ansible-master ~]# ansible 192.168.80.154 -m shell -a  "chdir=/tmp/ ls -ll|grep example.txt"
192.168.80.154 | CHANGED | rc=0 >>
-rwxr-xr-x 1 apache apache  0 10月 31 20:55 example.txt
[root@ansible-master ~]#

删除目标主机上的example.txt文件

# 第一种方法:command模块
[root@ansible-master ~]# ansible MySQL -a 'chdir=/tmp/ rm -rf example.txt'
[root@ansible-master ~]# ansible MySQL -m shell -a  "chdir=/tmp/ ls -ll|grep example.txt"
192.168.80.155 | FAILED | rc=1 >>
non-zero return code
[root@ansible-master ~]# 

# 第二种方法:file模块
[root@ansible-master ~]# ansible 192.168.80.154 -m file -a 'path=/tmp/example.txt state=absent'
[root@ansible-master ~]# ansible 192.168.80.154 -m shell -a  "chdir=/tmp/ ls -ll|grep example.txt"
192.168.80.154 | FAILED | rc=1 >>
non-zero return code
[root@ansible-master ~]#

删除目标主机的Ansible目录

# 第一种方法:command模块
[root@ansible-master ~]# ansible MySQL -a 'chdir=/tmp/ rm -rf Ansible'
192.168.80.155 | CHANGED | rc=0 >>

[root@ansible-master ~]# ansible MySQL -m shell -a  "chdir=/tmp/ ls -al|grep Ansible"
192.168.80.155 | FAILED | rc=1 >>
non-zero return code
[root@ansible-master ~]# 

# 第二种方法:file模块
[root@ansible-master ~]# ansible 192.168.80.154 -m file -a 'path=/tmp/Ansible state=absent'
192.168.80.154 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "path": "/tmp/Ansible", 
    "state": "absent"
}
[root@ansible-master ~]# ansible 192.168.80.154 -m shell -a  "chdir=/tmp/ ls -al|grep Ansible"
192.168.80.154 | FAILED | rc=1 >>
non-zero return code
[root@ansible-master ~]#

给目标主机的/etc/hosts文件创建一个链接文件/tmp/hosts

# 第一种方式:command模块
[root@ansible-master ~]# ansible MySQL -a 'ln -s /etc/hosts /tmp/hosts'
192.168.80.155 | CHANGED | rc=0 >>

[root@ansible-master ~]# ansible MySQL -m shell -a  "chdir=/tmp/ ls -al| grep hosts"
192.168.80.155 | CHANGED | rc=0 >>
lrwxrwxrwx   1 root root  10 10月 31 21:27 hosts -> /etc/hosts
[root@ansible-master ~]# 

# 第二种方式:file模块
[root@ansible-master ~]# ansible 192.168.80.154 -m file -a 'src=/etc/hosts path=/tmp/hosts state=link'
[root@ansible-master ~]# ansible 192.168.80.154 -m shell -a  "chdir=/tmp/ ls -al| grep hosts"
192.168.80.154 | CHANGED | rc=0 >>
lrwxrwxrwx   1 root root   10 10月 31 21:29 hosts -> /etc/hosts
[root@ansible-master ~]#

5.5 copy模块

copy模块:从Ansible服务器主控端复制文件到远程主机

模块子命令

说明

src

被复制到远程主机的本地文件,可以是绝对路径也可以是相对路径。如果路径是一个目录,则会递归复制,用法类似于“rsync”

dest

拷贝远端主机路径,指定目录不存在,自动递归创建;不支持文件重命名

content

用于替换“src”,可以直接修改远端文件内容,会覆盖源文件内容

backup=yes

默认为no,直接覆盖远端主机的源文件;yes:拷贝内容和远端主机上文件不一致,自动备份源文件

owner

修改拷贝到远程主机上的文件属主

group

修改拷贝到远程主机上的文件属组

mode

修改拷贝到远程主机上所有文件和目录权限

directory_mode

递归修改拷贝到远端主机上所有目录(包括子目录)权限

remote_src

默认为no,表示从本地拷贝远程主机;yes:在被管理端查找src数据进行被管理端本地移动

force

如果no,传输数据不会覆盖原有数据文件;yes:强制覆盖原文件

注意:

#copy模块的src指定目录没有/,将把整个目录以及目录下数据复制
ansible 10.0.0.7 -m copy -a "src=/etc dest=/tmp"
#copy模块的src指定目录有/,只把目录下数据进行复制
ansible 10.0.0.7 -m copy -a "src=/etc/ dest=/tmp"

向远程主机拷贝本机数据文件,默认覆盖远端主机文件

[root@ansible-master ~]# ansible MySQL -m copy -a 'src=/etc/hosts dest=/tmp/hosts'
[root@ansible-master ~]# ansible MySQL -m shell -a 'cat /tmp/hosts'

拷贝本机文件,并修改文件权限

[root@ansible-master ~]# ansible MySQL -m copy -a 'src=/etc/hosts dest=/tmp/ owner=apache 
[root@ansible-master ~]# ansible MySQL -m shell -a 'ls -ld /tmp/hosts'
192.168.80.155 | CHANGED | rc=0 >>
-rwxr-xr-x 1 apache apache 247 10月 31 21:40 /tmp/hosts
[root@ansible-master ~]#

直接修改远端主机上的文件,会覆盖原文件内容

[root@ansible-master ~]# ansible MySQL -m copy -a 'content="demo" dest=/tmp/hosts'
[root@ansible-master ~]# ansible MySQL -m shell -a 'cat /tmp/hosts'
192.168.80.155 | CHANGED | rc=0 >>
demo
[root@ansible-master ~]#

拷贝文件,远端主机上源文件自动备份

[root@ansible-master ~]# ansible MySQL -m copy -a 'backup=yes content="demo demo demo demo" dest=/tmp/hosts'
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/tmp/ ls -l'
192.168.80.155 | CHANGED | rc=0 >>
总用量 8
drwx------ 2 root   root   41 10月 31 21:48 ansible_command_payload_ejAGK7
-rwxr-xr-x 1 apache apache 19 10月 31 21:48 hosts
-rwxr-xr-x 1 apache apache 14 10月 31 21:45 hosts.64391.2022-10-31@21:48:01~
[root@ansible-master ~]#

拷贝/etc/目录到远端主机/tmp,递归修改权限

[root@ansible-master ~]# ansible MySQL -m copy -a 'src=/etc/ dest=/tmp/ directory_mode=666'

把远程主机上/tmp/hosts拷贝到/opt目录下

[root@ansible-master ~]# ansible MySQL -m copy -a 'remote_src=yes src=/tmp/hostname 
[root@ansible-master ~]# ansible MySQL -a 'ls /opt'

5.6 fetch模块

与copy类似,但是作用相反

可以将其他主机的文件拷贝到本地,目前不支持拷贝目录

模块子命令

说明

src

指定远端主机文件

dest

拷贝Ansible管理端上目录路径

[root@servera ansible]# ansible client1 -m fetch -a "src=/etc/hostname dest=/tmp/"

5.7 unarchive模块

unarchive模块功能:解压打包文件

实现有俩种方式

  • copy=yes:将ansible管理端的压缩文件拷贝到远端主机上进行解压到指定目录
  • copy=no:将远程主机上压缩文件进行解压到指定目录下

模块子命令

说明

src

指定压缩文件路径,copy=yes:指的时Ansible主机上的压缩文件。copy=no:指的是远程主机上的压缩文件

dest

解压到远程主机上的路径

mode

指定解压文件目录权限

remote_src

和copy子命令相反,即:remote_src=yes,将远程主机上的压缩文件解压,remote_src=no,Ansible管理主机上的压缩文件

owner

递归设置属主

group

递归设置属组

mode

递归设置权限

format

指定归档文件的格式。如果未指定该参数,则会自动检测格式。支持的格式包括"zip"、“tar”、“gztar”和"bztar”

exclude

指定要从归档文件中排除的文件或目录的列表

extra_opts

strip-components N 解压文件时去除N层级目录

Ansible管理端的压缩文件拷贝到远端主机上进行解压到指定目录

#ansible管理端的压缩文件拷贝到远端主机上进行解压到指定目录
ansible 10.0.0.7 -m unarchive -a "src=/root/etc.tar.gz dest=/opt/ owner=demo
group=bin mode=777"
ansible 10.0.0.7 -m unarchive -a "src=/root/etc.tar.xz dest=/opt/"
#将远程主机上压缩文件进行解压到指定目录下
ansible 10.0.0.7 -m copy -a "src=/root/etc.tar.xz dest=/tmp"
ansible 10.0.0.7 -m unarchive -a "src=/tmp/etc.tar.xz dest=/tmp copy=no"
#远程主机可以被管理主机或者其他主机
ansible all -m unarchive -a 'src=https://example.com/example.zip dest=/data
copy=no'

5.8 archive模块

archive模块:将远程主机上文件目录进行压缩打包

模块子命令

说明

path

指定远程主机压缩的文件目录

dest

指定远程主机上报错压缩包路径

format

指定压缩格式: 支持bz2,gz,tra,xz,zip

owner

指定属主

group

指定属组

mode

指定权限

remove

yes|no,默认为no,在打包/压缩后,不删除源文件

压缩目标主机上的日志文件

[root@ansible-master ~]# ansible MySQL -m archive -a "path=/var/log/ dest=/tmp/log.tar.gz"

5.9 hostname模块

永久设置远程主机的主机名,一般针对单独主机设置

[root@ansible-master ~ ]#ansible MySQL -m hostname -a 'name=centos7.antest.com'

5.10 cron模块

批量设置远程主机的计划任务

模块子命令

说明

minute

每分钟

huor

每小时

day

每天

month

每月

week

每周几

job

执行的计划任务命令

name

计划任务注释信息

disabled

根据完整的计划任务设置是否启用该计划,yes:开启,no:禁止

state=absent

根据name删除计划任务

设置计划:

[root@ansible-master ~]# ansible MySQL -m cron -a "minute=*/5 hour=2 name='sync time' job='/usr/sbin/ntpdate ntp.aliyun.cm&>/dev/null'"

启用计划任务:

[root@ansible-master ~]# ansible MySQL -m cron -a "minute=*/5 hour=2 name='sync time' job='/usr/sbin/ntpdate ntp.aliyun.cm&>/dev/null' disabled=yes"

禁用计划任务:

[root@ansible-master ~]# ansible MySQL -m cron -a "minute=*/5 hour=2 name='sync time' job='/usr/sbin/ntpdate ntp.aliyun.cm&>/dev/null' disabled=no"

删除计划任务:

[root@ansible-master ~]# ansible MySQL -m cron -a "name='sync time' state=absent"

5.11 lineinfile | replace 模块

在修改单个文件的单行内容时可以使用lineinfile模块

在修改单个文件的单个关键词时可以使用replace关键字

模块子命令

说明

path/dest

目标文件绝对路径+文件名,必须参数

line

替换/插入的内容

regexp

待匹配内容

insertbefore

匹配行前面插入

insertafter

匹配行后面插入

state

参数值为absent为删除,默认为persent

backup

yes|no,是否在修改文件之前对文件进行备份。

create

yes|no,当要操作的文件并不存在时,是否创建对应的文件

backrefs

backrefs=no时,如果没有匹配,则添加一行line。如果匹配了,则把匹配内容替换为line backrefs=yes时,如果没有匹配,则文件保持不变。如果匹配了,则把匹配内容替换为line

1.默认添加到文件结尾

[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/root/ echo 12345 > Ansible.txt'
[root@ansible-master ~]# ansible MySQL -m lineinfile -a 'path=~/Ansible.txt line="hello world!"' 
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/root/ cat Ansible.txt'

2.验证幂等原则,多次执行一样的语句,实际上执行的效果是一样的,不会重复执行

[root@ansible-master ~]# ansible MySQL -m lineinfile -a 'path=~/Ansible.txt line="hello world!"' 
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/root/ cat Ansible.txt'

3.添加到指定位置

# 在hello后面添加内容
[root@ansible-master ~]# ansible MySQL -m lineinfile -a 'path=~/Ansible.txt line="httpd is apache" insertafter="hello"'  
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/root/ cat Ansible.txt'
# 在hello前面添加内容
[root@ansible-master ~]# ansible MySQL -m lineinfile -a 'path=~/Ansible.txt line="mysql is mariadb" insertbefore="hello"' 
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/root/ cat Ansible.txt'

4.修改文件内容,匹配内容存在

[root@ansible-master ~]# ansible MySQL -m lineinfile -a 'path=/etc/selinux/config regexp="^SELINUX=" line="SELINUX=disabled" '
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/etc/selinux cat config'

5.修改文件内容,匹配内容不存在

# 匹配内容不存在,则添加到文件最后
[root@ansible-master ~]# ansible MySQL -m lineinfile -a 'path=~/Ansible.txt regexp="Hello" line="lineinfile module2"'
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/root/ cat Ansible.txt'

6.修改文件内容,匹配内容存在多行

[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/root/ cat Ansible.txt'
# 匹配多行,仅替换最后一行
[root@ansible-master ~]# ansible MySQL -m lineinfile -a 'path=~/Ansible.txt regexp="lineinfile module2" line="123456"'
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/root/ cat Ansible.txt'

7.修改文件内容,镜匹配到的内容全部替换 <replace模块>

[root@ansible-master ~]# ansible MySQL -m replace -a 'path=~/Ansible.txt regexp="lineinfile module2" replace="Apache+Mariadb"'
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/root/ cat Ansible.txt'

5.12 user模块

user模块可以实现linux系统账户管理

模块子命令

说明

name

用户名

uid

用户UID

group

指定用户属于哪个用户组

groups

用户组列表

commit

用户说明信息

shell

用户的shell类型

system

yes:创建系统用户

create_home

no:不创建家目录

non_unique

yes:允许UID相同

remove

no:只删除用户,不删除用户数据(家目录和邮件);yes:删除用户及家目录等数据

1.在目标主机上创建系统用户nginx

[root@ansible-master ~]# ansible MySQL -m user -a 'name=nginx comment=nginx uid=88 groups="root,daemon" shell=/sbin/nologin system=yes create_home=no home=/data/nginx non_unique=yes'
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/etc/ cat passwd | grep nginx'

2.在目标主机上给用户nginx设置密码

#因为计算机读取密码不是通过明文,而是读取一系列的密文。所以设置密码不能直接设置,需要经过hash加密算法进行加密才行。通过hash的sha512算法进行加密
[root@ansible-master ~]# ansible MySQL -m user -a 'name=nginx password={{"centos" |password_hash("sha512")}}'
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/etc/ cat shadow | grep nginx'
192.168.80.155 | CHANGED | rc=0 >>
nginx:$6$FYG6DrbbImc3gIHm$01O0XPiNJkQlRBMBRytEjRWA7JtzJrnJz39ss4KXHOEA7LUcrYBRkprJjcjLL15jrLe1xyaNslixdDlb7w.fv0:19297::::::
[root@ansible-master ~]#

3.删除用户nginx

[root@ansible-master ~]# ansible MySQL -m user -a 'name=nginx remove=yes state=absent'
192.168.80.155 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "force": false, 
    "name": "nginx", 
    "remove": true, 
    "state": "absent", 
    "stderr": "userdel: nginx 邮件池 (/var/spool/mail/nginx) 未找到\n", 
    "stderr_lines": [
        "userdel: nginx 邮件池 (/var/spool/mail/nginx) 未找到"
    ]
}
[root@ansible-master ~]# ansible MySQL -m shell -a 'chdir=/etc/ cat passwd | grep nginx'
192.168.80.155 | FAILED | rc=1 >>
non-zero return code
[root@ansible-master ~]#

5.13 group模块

创建和管理用户组

模块子命令

说明

name

用户组名

gid

用户组id

non_unique

yes:允许用户组id相同

system

yes:创建系统组

state

state=absent 删除用户组

1.创建用户组

[root@ansible-master ~]# ansible MySQL -m group -a 'name=group gid=1010'

[root@ansible-master ~]# ansible MySQL -m group -a 'name=group gid=1011 non_unique=yes system=yes'

2.删除用户组

[root@ansible-master ~]# ansible MySQL -m group -a 'name=group state=absent'

[root@ansible-master ~]#

5.14 yum-repository模块

使用yum-repository模块可以创建或修改yum源文件

模块子命令

说明

name

用于指定要操作的唯一仓库ID

baseurl

设置yum仓库的baseurl

description

设置仓库的注释信息

file

设置仓库的配置文件名称,即".repo"配置文件的文件名前缀

enabled

设置是否激活对应的yum源,默认为yes,表示启用对应的yum源

gpgcheck

设置是否开启rpm包验证功能,默认值为no,表示不启用包验证

gpgcakey参数

当pgpcheck参数设置为yes,需要使用此参数指定验证包所需的公钥

state

默认值为persent,当值为absent时,表示删除对应的yum源

1.新建一个yum源文件

[root@ansible-master ~]# ansible MySQL -m yum_repository -a "name=mybase description=hello baseurl=file:///mnt/mybase gpgcheck=0"
[root@ansible-master ~]# ansible MySQL -m command -a "ls /etc/yum.repos.d/"
……
mybase.repo
[root@ansible-master ~]# ansible MySQL -m command -a "cat /etc/yum.repos.d/mybase.repo"

2.使用yum_repository模块修改yum源配置文件

[root@ansible-master ~]# ansible MySQL -m yum_repository -a "name=mybase description=Ansible baseurl=file:///mnt/mybase gpgcheck=1"
[root@ansible-master ~]# ansible MySQL -m command -a "cat /etc/yum.repos.d/mybase.repo"

3.使用yum_repository模块删除yum源文件mybase

[root@ansible-master ~]# ansible MySQL -m yum_repository -a "name=mybase state=absent"
[root@ansible-master ~]# ansible MySQL -m command -a "ls /etc/yum.repos.d/"
[root@ansible-master ~]# v

5.15 yum模块

使用yum模块可以安装,卸载,升级软件包

模块子命令

说明

state=present

安装

state=absent

卸载

state=latest

升级

enablerepo

指定要启用的仓库。可以是仓库名称、通配符、逗号分隔的多个仓库等

disablerepo

指定要禁用的仓库。可以是仓库名称、通配符、逗号分隔的多个仓库等

installroot

指定要安装软件包的根目录。可以是绝对路径或相对路径

disable_gpg_check

指定是否禁用软件包的GPG检查。默认值为false

exclude

指定要排除的软件包。可以是软件包名称、通配符、逗号分隔的多个软件包等

update_cache

指定是否在安装软件包之前更新缓存。默认值为true

validate_certs

指定是否验证SSL证书。默认值为true

在目标主机上安装unzip软件包

[root@ansible-master ~]# ansible all -m yum -a 'name=unzip state=present'

在目标主机上更新unzip软件包

[root@ansible-master ~]# ansible all -m yum -a 'name=unzip state=latest'

在目标主机上卸载unzip软件包

[root@ansible-master ~]# ansible MySQL -m yum -a 'name=unzip state=absent'

5.16 service模块

service模块为服务管理模块(启动,关闭,重启服务,重新加载等)

模块子命令

说明

name

服务名

state

state=started 启动服务 state=stopped停止服务 state=restarted重启服务 state=reloaded 重新加载服务配置

enabled

yes:设置开机启动,默认为no

daemon_reload

在启用或禁用服务时,是否应该运行systemd的daemon-reload命令。可以是yes或no。默认值为no

pattern

指定用于查找进程的模式。可以是正则表达式或通配符

sleep

在重新启动服务之前等待的秒数。默认值为0

arguments

指定传递给服务的附加参数

force

在停止服务时,是否强制终止进程。可以是yes或no。默认值为no

启动目标主机的Apache服务

[root@ansible-master ~]# ansible MySQL -m service -a 'name=httpd state=started'

停止目标主机的Apache服务

[root@ansible-master ~]# ansible MySQL -m service -a 'name=httpd state=stopped'

实战演练:在client2上使用yum-repository模块配置yum仓库,使用yum模块安装ftp服务的软件包(vsftpd),并设置为自启动(cat 文件1 >> 文件2 把文件1的内容重定向到文件2 )

#1.第一步:使用Ansible对client2原有的yum仓库redhat.repo进行备份。
[root@servera ansible]# ansible client2 -m command -a "cp /etc/yum.repos.d/redhat.repo /etc/yum.repos.d/redhat.repo.bak"
[root@servera ansible]# ansible client2 -m command -a "ls /etc/yum.repos.d/"

#第二步:使用Ansible对client2原有的yum仓库redhat.repo进行删除操作
[root@servera ansible]# ansible client2 -m command -a "rm -rf  /etc/yum.repos.d/redhat.repo"
[root@servera ansible]# ansible client2 -m command -a "ls /etc/yum.repos.d/"

#第三步:使用Ansible中的yum-repository模块进行yum仓库的配置
[root@servera ansible]#  ansible client2 -m yum_repository -a "name=AppStream description=AppStream baseurl=file:///mnt/AppStream gpgcheck=0"
[root@servera ansible]#  ansible client2 -m yum_repository -a "name=BaseOS description=BaseOS baseurl=file:///mnt/BaseOS gpgcheck=0"

#第四步:使用Ansible中的shell模块进行yum源的合成
[root@servera ansible]# ansible client2 -m command -a "cat /etc/yum.repos.d/AppStream.repo"
[root@servera ansible]# ansible client2 -m shell -a "cat /etc/yum.repos.d/AppStream.repo >> /etc/yum.repos.d/redhat.repo"
[root@servera ansible]# ansible client2 -m command -a "cat /etc/yum.repos.d/BaseOS.repo"
[root@servera ansible]# ansible client2 -m shell -a "cat /etc/yum.repos.d/BaseOS.repo >> /etc/yum.repos.d/redhat.repo"
[root@servera ansible]# ansible client2 -m command -a "cat /etc/yum.repos.d/redhat.repo"

#第五步:使用Ansible中的command模块进行镜像的挂载和列出仓库
[root@servera ansible]# ansible client2 -m command -a "mount /dev/sr0 /mnt"

#第六步:使用Ansible中的yum模块进行软件包的安装
[root@servera ansible]# ansible client2 -m yum -a "name=vsftpd state=present"

#第七步:使用Ansible中的service模块对刚安装的vsftpd软件进行启停操作
#启动vsftpd软件
[root@servera ansible]# ansible client2 -m service -a "name=vsftpd state=started"
#停止vsftpd软件
[root@servera ansible]# ansible client2 -m service -a "name=vsftpd state=stopted"

5.17 setup模块

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

模块子命令

说明

filter

过滤setup收集信息,支持通配符

ansible_all_ipv4_addresses:仅显示ipv4的信息。
ansible_devices:仅显示磁盘设备信息。
ansible_distribution:显示是什么系统,例:centos,suse等。
ansible_distribution_major_version:显示是系统主版本。
ansible_distribution_version:仅显示系统版本。
ansible_machine:显示系统类型,例:32位,还是64位。
ansible_eth0:仅显示eth0的信息。
ansible_hostname:仅显示主机名。
ansible_kernel:仅显示内核版本。
ansible_lvm:显示lvm相关信息。
ansible_memtotal_mb:显示系统总内存。
ansible_memfree_mb:显示可用系统内存。
ansible_memory_mb:详细显示内存情况。
ansible_swaptotal_mb:显示总的swap内存。
ansible_swapfree_mb:显示swap内存的可用内存。
ansible_mounts:显示系统磁盘挂载情况。
ansible_processor:显示cpu个数(具体显示每个cpu的型号)。
ansible_processor_vcpus:显示cpu个数(只显示总的个数)。

查看目标主机的完整主机名

[root@ansible-master ~]# ansible all -m setup -a 'filter=ansible_nodename'

查看目标主机的主机名前面一部分

[root@ansible-master ~]# ansible all -m setup -a 'filter=ansible_hostname'

查看目标主机的主机名后面一部分

[root@ansible-master ~]# ansible all -m setup -a 'filter=ansible_domian'

查看目标主机的总内存

[root@ansible-master ~]# ansible all -m setup -a 'filter=ansible_memtotal_mb'

查看内存使用情况

[root@ansible-master ~]# ansible all -m setup -a 'filter=ansible_memfree_mb'

查看主机操作系统家族

[root@ansible-master ~]# ansible all -m setup -a "filter=ansible_os_family"

查看系统主版本

[root@ansible-master ~]# ansible all -m setup -a  "filter=ansible_distribution_major_version"

查看系统版本

[root@ansible-master ~]# ansible all -m setup -a "filter=ansible_distribution_version"

查看CPU核心数

[root@ansible-master ~]# ansible all -m setup -a "filter=ansible_processor_vcpus"

5.18 lv模块

创建,删除卷组(VG),修改卷组大小

模块子命令

说明

state=persent

创建

state=absent

删除

[root@servera ansible]# ansible client1 -m yum -a "name=lvm2"
#在client1主机上下载lvm逻辑卷管理器软件包
#因为linux一般自带lvm逻辑卷管理器,这里由于幂等性所以changed=flase
client1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,   
    "msg": "Nothing to do",
    "rc": 0,
    "results": []
}
[root@servera ansible]# ansible client1 -m lvg-a "vg=myvg pvs=/dev/cdn1"
#创建名称为myvg的卷组,该卷组由/dev/vdb1组成
[root@servera ansible]# ansible client1 -m lvg-a "vg=myvg pvs=/dev/vdb1,/dev/vdb2"\
#修改卷组大小。

5.19 firewalld模块

使用firewalld模块可以配置防火墙策略
[root@servera ansible]# vim ~/ansible/firewall.yml
[root@servera ansible]# cat ~/ansible/firewall.yml 
---
- hosts: client1   
  tasks: 
      - name: install firewalld.
        yum:
            name: firewalld
            state: present
      - name: run firewalld.     #运行防火墙服务
        service:
                name: firewalld  #服务名称
                state: started  #开启服务
                enabled: yes   #设置服务为开机自启
      - name: set firewalld rule.#设置防火墙策略
        firewalld:   
                port: 80/tcp    #设置TCP协议的80端口允许访问
                service:https  #设置https服务允许通过防火墙
                permanent: yes  #规则为永久生效
                immediate: yes  #规则立即生效 
                state: enabled  #开机自启
[root@servera ansible]# ansible-playbook firewall.yml

5.20 template模块

主要功能:

  1. copy模块可以将一个文件拷贝给远程主机,但是如果希望每个拷贝的文件内容都不一样呢?
  2. 如何给所有web主机拷贝index.html内容是各自的IP地址?
  3. Ansible可以利用Jinja2模块引擎读取变量
  4. 之前在playbook中调用变量,也是Jinja2的功能
  5. Jinja2模块的表达式包含在分割符"{{}}"内

Jinja2语言:

网站:介绍 — Jinja2 中文手册 2.8 documentation (ainoob.cn)

实例:给webserver主机拷贝首页,每个主机内容不同
[root@servera ansible]# mkdir ~/ansible/template  //创建一个模板
[root@servera ansible]# vim ~/ansible/template/index.html //创建首页网页
[root@servera ansible]# cat ~/ansible/template/index.html
Welcome to {{ansible_hostname}} to {{ansible_ens160.ipv4.address}}. //网页内容
#模板文件中调用变量不需要双引号 
[root@servera ansible]# vim ~/ansible/template.yml
[root@servera ansible]# cat ~/ansible/template.yml
---
- hosts: webserver
  tasks:
         - name: use template copy index.html to webserver.
           template:
                   src: ~/ansible/template/index.html
                   dest: /var/www/html/index.html
[root@servera ansible]# ansible-playbook template.yml 
[root@servera ansible]# vim ~/ansible/template/source.j2
[root@servera ansible]# cat ~/ansible/template/source.j2 
{{welcome}}{{iname}}...

[root@servera ansible]# vim ~/ansible/template_2.yml
[root@servera ansible]# cat ~/ansible/template_2.yml 
---
- hosts: webserver
  vars: 
        welcome: "hello"
        iname: 'jack'
  tasks:
        - name: use template copy a file to remote host.
          template:
                  src: ~/ansible/template/source.j2
                  dest: /tmp/
[root@servera ansible]# ansible-playbook template_2.yml

5.21 get_url模块

主要功能:

  1. 下载目标文件到被控端本地

主要参数:

参数

说明

url

资源在互联网上的具体Url地址

dest

文件下载位置的绝对路径

mode

文件下载后赋予的权限

checksum

对下载的文件进行校验

timeout

URL请求的超市时间,默认10s

# 下载百度首页到远端主机的指定目录下,并赋予755权限
[root@localhost playbook]# ansible server1 -m get_url -a "url=https://www.baidu.com/index.php dest=/root/ mode=755"

6.Ansible 之 sudo提权

6.1 sudo概述:

1.基本概念:

sudo ,全程superuser or another do,意思是:以超级管理员或其他人的身份执行命令

2.基本流程:

管理员首先需要先授权(修改/etc/sudoers文件),普通用户以sudo的形式执行命令,可以通过sudo -l查看授权情况

3.修改/etc/sudoers的方法:

  • visudo (带语法检查,默认没有颜色提示)
  • vim /etc/sudoers (不带语法检查,默认有颜色提示)

4.授权格式如下:

用户或组  主机列表=(提权身份) [nopasswd]:命令列表
#命令需要写绝对路径

6.2 Sudo的授权

[root@servera ~]# vim /etc/sudoers
......
root   ALL=(ALL)  ALL
%whell ALL=(ALL)  ALL  
#%whell可以是组,也可以是用户,用户的话不需要百分号。 括号里面的all表示授权给目标用户或组可以以任何身份执行命令。后面的ALL是代表任何命令,all也可以改为单个命令,但是命令需要写绝对路径。
6.2.1 Sudo授权实验
# 1.在主机上创建一个用户marry,密码设置为centos
[root@ansible-mysql ~]# useradd marry
[root@ansible-mysql ~]# echo marry | passwd --stdin marry
[root@ansible-mysql ~]# 

# 2.切换到marry用户,尝试启停Apache服务
[marry@ansible-mysql ~]$ systemctl stop httpd
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to manage system services or units.
Authenticating as: root
Password: 
polkit-agent-helper-1: pam_authenticate failed: Authentication failure
==== AUTHENTICATION FAILED ===
Failed to stop httpd.service: Access denied
See system logs and 'systemctl status httpd.service' for details.
[marry@ansible-mysql ~]$ 
# 表示没有权限
# 3.如果在控制端上无法输入任何东西,输入reset,完全刷新终端屏幕就可以了

# 4.设置sudo提权
[root@ansible-mysql ~]# visudo 
[root@ansible-mysql ~]# tail -n 30 /etc/sudoers
……
root    ALL=(ALL)       ALL
marry   ALL=(root)      /usr/bin/systemctl  #表示marry可以对主机进行服务的启停
       # /usr/bin/systemctl  表示systemctl的绝对路径
……

# 5.使用sudo命令来进行服务的启停
[marry@ansible-mysql root]$ sudo systemctl restart httpd
……
[sudo]marry 的密码:centos
……
[marry@ansible-mysql root]$ sudo systemctl status httpd

#6.通过sudo -l  查询授权情况
6.2.2. Ansible的sudo提权
# 1.使用Ansible对目标主机远程创建系统用户
[root@ansible-master ~]# ansible MySQL -m user -a "name=alice password={{'centos'|password_hash('sha512')}}"
# 2.在所有被管理主机配置sudo,让alice可以管理系统用户
[root@servera ansible]# ansible MySQL -m lineinfile -a "path=/etc/sudoers line='alice   ALL=(root)      /usr/bin/systemctl
' insertafter='root	ALL=(ALL) 	ALL'"  #添加一行信息在/etc/sudoers中的‘root    ALL=(ALL)       ALL’的后一行,no password:设置为alice使用sudo命令不用输入密码
# 3.验证
[alice@ansible-mysql ~]$ sudo systemctl restart httpd
[alice@ansible-mysql ~]$ sudo systemctl status httpd 
[alice@ansible-mysql ~]$ sudo -l
# 4.设置所有被管理主机的sudo配置文件,让alice可以执行任何命令
[root@servera ansible]# ansible all-m lineinfile -a "path=/etc/sudoers line='alice  ALL=(ALL) NOPASSWD:ALL'"
# 5.验证
# 可以使用普通用户更改root用户的密码,所以这种配置及其不安全
[alice@ansible-mysql ~]$ sudo passwd

7.Ansible Playbook基础

7.1 Playbook概述

Ansible ad-hoc 可以通过命令行形式远程管理其他主机

适合执行一些临时性简单任务

Ansible Playbook中文名称叫剧本

  • 将经常需要执行的任务写入一个文件(剧本)
  • 剧本中可以包含多个用户
  • 剧本写后,我们随时调用剧本,执行相关的任务命令
  • playbook剧本要按照YAML格式编写
  • 适合执行周期性经常执行的复杂任务

7.2 YAML是什么

7.2.1 YAML语言介绍

YAML不是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,一种专门用来写配置文件的语言。可用于如: Java,C/C++, Ruby, Python, Perl, C#, PHP等

YAML 是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 格式方便。YAML 语言的设计目标,就是方便人类读写。它实质上是一种通用的数据串行化格式

7.2.2 YAML基本语法规则
  1. 大小写敏感
  2. 使用缩进表示层级关系
  3. 缩进时不允许使用Tab键,只允许使用空格。
  4. 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  5. # 表示注释,从这个字符一直到行尾,都会被解析器忽略。
7.2.3 YAML 支持的数据结构
  1. 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  2. 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  3. 纯量(scalars):单个的、不可再分的值
7.2.4 YAML语言特性
  • YAML的可读性好
  • YAML和脚本语言的交互性好
  • YAML使用实现语言的数据类型
  • YAML有一个一致的信息模型
  • YAML易于实现
  • YAML可以基于流来处理
  • YAML表达能力强,扩展性好
7.2.5 YAML语言简介
  • 在单一文件第一行,用连续三个 - 号开始,还有选择性的三个点号...表示文件的结尾
  • 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
  • 使用#号注释代码
  • 缩进必须是统一的,空格不能与Tab混用
  • 缩进的级别也必须是一致的,同样的缩进表示同样的级别,程序判断配置的级别是通过缩进结合换行来实现的。
  • YAML文件内容是区分大小写的,key/value的值均需大小写敏感
  • 多个key/value可同行写也可以换行写,同行使用,分割
  • v可以是字符串也可以是另一个列表
  • 一个完整的代码块功能需最少包括元素name和task
  • 一个name只能包括一个task
  • YAML文件扩展名通常为yml或yaml

YAML的语法和其它高阶语言类似,并且可以简单表达清单,散列值,标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用-来代表,Map里的键值对用:分割

7.2.6 YAML数据结构样例

List列表

# 列表由多个元素组成,每个元素放在不同行,且元素前均使用'-'打头,或者将所有元素用[]括起来放在同一行

# 不同行,行以-开头,后面有一个空格
- Apple
- Orange
- Strawberry
- Mango

# 同一行
[Apple,Orange,Strawberry,Mango]

Dictionary字典

# 字典由多个key与value构成,key与value之间用": ",所有key/value可以放在同一行,或者每个k/v分别放在不同行

# 不同行
# An employee record
name: Example Developer
job: Developer
skill: Elite

# 同一行,也可以将key:value放置于{}中表示,用逗号分割多个k/v
{name: "Example Developer",job: "Developer",skill: "Elite"}

常见的数据结构:Ubuntu的网络配置结构

root@hehao-virtual-machine:~# cat /etc/netplan/01-network-manager-all.yaml 
network:
        version: 2
        ethernets:
                ens33:
                        #addresses: [192.168.80.146/24]
                        # gateway4: 192.168.80.2
                        dhcp4: yes
                        #nameservers:
                        # addresses: [8.8.8.8,114.114.114.114]
7.2.7 三种常见的数据结构
  • XML:Extensible Markup Language,可扩展标记语言,可用于数据交换和配置
  • JSON:JavaScript Object Notation,JavaScript对象标记法,主要用来数据交换或配置,不支持注释
  • YAML:YAML Ain`t MarkUP Language ,YAML不是一种标记语言,只要用来配置,大小写敏感,不支持Tab

可以使用工具互相转换,参考网站:

https://www.json2yaml.com

在线JSON转yaml,yaml转JSON-BeJSON.com

7.2.3 PlayBook核心元素

一个palybook中由一个列表组成,列表的元素类型如下:

  • Hosts:执行的远程主机列表
  • Tasks:任务集,由多个task的元素组成的列表实现,每个task是一个字典
  • Variables:内置变量或自定义变量在playbook中调用
  • Templates:模板,可替换模板文件中的变量并实现一些简单逻辑的文件
  • Handlers 和 notify结合使用,由特点条件出发的操作,满足条件方才执行,否则不执行
  • tags标签:指定某条件任务执行,用于选择运行playbook中的部分代码。Ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其却似hi没有发生变化的时间依然会非常的长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片段
  • 一个完整的代码块功能最少元素需包括name和task
  • 一个name只能包括一个task
[root@servera ansible]# vim ~/ansible/example1.yml
---
- hosts: all
  tasks: 
        - name: This is my first playbook
          ping:  #调用ping模块
        - name: This is shell command
          shell: touch ~/shell.txt #调用shell模块,新建文件shell.txt
[root@servera ansible]# ansible-playbook example1.yml   
#运行playbook直接ansible-playbook 剧本名

Ansible自动化运维_运维_04

hosts由一个或多个组或主机组成,逗号分隔.tasks由一个或多个任务组成,多个任务按顺序执行.可以使用-f选项自定义并发量,并发量意思是一次运行多少台主机一个playbook中可以有多个play

[root@servera ansible]# vim ~/ansible/example1.yml 
---
- hosts: client1  #第一台主机需要运行的任务
  tasks:
        - name: This is my first playbook!
          ping:
        - name: This is my command module!
          command: touch ~/Ansible-palybook.txt
        - name: This is my shell module!
          shell: echo Hello Ansible-playbook > Ansible-paly.txt
- hosts: client2 #第二台主机需要运行的任务
  tasks:
        - name: This is my second playbook!
          ping:  
        - name: This is my command module!
          command: touch ~/Ansible-playbook.txt
  [root@servera ansible]# ansible-playbook example1.yml
1.hosts组件

Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户执行任务。hosts用于要指定任务的主机,需事先定义在主机清单中

/etc/ansible/ansible.hosts

---
- hosts: client1
2.remote_user组件

remote_user:可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时,使用sudo_user指定sudo时切换的用户

---
- hosts: client1
  remote_user: root
  tasks:
  	- name: test connection
  	  ping:
  	  remote_user: marry
  	  sudo: yes      #默认sudo为root
  	  sudo_user: wang #sudo为wang
3.task列表和action组件

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

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

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

task两种格式:

  • action:模块名 参数
  • 模块名:参数 <建议使用>

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

---
- hosts: client1
  remote_user: root
  tasks:
    - name: install httpd
      yum: name=httpd
    - name: start httpd
      service: name=httpd state=started enabled=yes
4.其它组件

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

任务可以通过"tags"打标签,可在Ansible-playbook命令上使用-t指定进行调用

5.ShellScript VS Playbook案例

Shell脚本方式

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

Playbook实现

---
- hosts: client1
  remote_user: root
  tasks:
    - name: "安装Apache"
      yum: name=httpd
    - name: "复制配置文件"
      copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/httpd.conf
    - name: "复制配置文件"
      copy: src=/tmp/vhost.conf dest=/etc/httpd/conf.d/
    - name: "启动Apache,并设置开机自启动"
      service: name=httpd state=started enabled=yes

7.2.4 playbook命令

  • 列出yaml文件支持的主机列表
ansible-playbook --list-hosts hello.yml
  • 列出yaml文件支持的任务列表
ansible-playbook --list-tasks hello.yml

格式:

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

常见选项:

-c --check  # 检测目标yaml文件是否符合标准,不真正执行操作
--list-hosts  #只列出运行任务的主机
--list-tags   #列出tag
--list-tasks  #列出task
--limit  主机列表  #只针对主机列表中的主机执行
-v -vv -vvv  #显示过程

7.2.5 初步使用Playbook

1.利用palybook创建mysql用户
---
- hosts: Apache 
  remote_user: root

  tasks:
    - name: create group
      group: name=mysql system=yes gid=306
    - name: create user
      user: name=mysql shell=/sbin/nologin group=mysql uid=306 home=/data/mysql create_home=no

Ansible自动化运维_自动化_05

`如果遇见这种报错:即代表远端主机有一个进程(PID为627)正在使用用户"mysql",停止相关进程即可
2.利用playbook安装nginx

默认的centos的yum仓库是默认没有Nginx的,需要额外安装nginx的rpm包

[root@ansible-apache ~]# rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

---
- hosts: Apache
  remote_user: root
  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: web page
   	 copy: src=files/index.html dest=/usr/share/nginx/html/index.html
   - name: Start Nginx
   	 service: name=nginx state=started enabled=yes

7.2.6 Playbook中使用handlers和notify

Handlers本质是task list,类似于MySQL中的触发器触发的行为,其中task与前述的task并没有本质上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而notify对应的action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作,在notify中列出地操作称为handler,即notify中调用handler中定义的操作

使用Ansible下载httpd服务,并更改端口

---
#install httpd
- hosts: Apache
  remote_user: root
  gather_facts: no
  
  tasks:
   - name: Install httpd
     yum: name=httpd state=present
   - 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: start service
     service: name=httpd state=started enabled=yes

使用触发器,只有更改了端口,才会重启服务

---
- hosts: Apache
  remote_user: root
  gather_facts: no

  tasks:
   - name: Install httpd
     yum: name=httpd state=present
   - name: modify config
     lineinfile: path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 8888'
     notify: restart httpd
   - name: mkdir website dir
     file: path=/data/html state=directory
   - name: start service
     service: name=httpd state=started enabled=yes

  handlers:
   - name: restart httpd
     service: name=httpd state=restarted

7.2.7 Playbook中使用tags组件

tags组件就是打标签。tags可以和一个play(就是很多个task)或者一个task进行捆绑。然后,ansible-playbook提供了“–skip-tags”和“–tags” 来指明是跳过特定的tags还是执行特定的tags。

[root@ansible-maseter ~]# vim install_httpd.yml 
---
- hosts: Apache
  remote_user: root
  gather_facts: no

  tasks:
   - name: Install httpd
     yum: name=httpd state=present
   - name: modify config
     lineinfile: path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 8888'
     notify: restart httpd
     tags: conf
   - name: mkdir website dir
     file: path=/data/html state=directory
   - name: start service
     service: name=httpd state=started enabled=yes
[root@ansible-maseter ~]# ansible-playbook -t conf install_httpd.yml  # 指定tags,运

PLAY [Apache] ***********************************************************************************************************************************

TASK [modify config] ****************************************************************************************************************************
ok: [192.168.80.167]

PLAY RECAP **************************************************************************************************************************************
192.168.80.167             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@ansible-maseter ~]#

7.2.8 Playbook中使用变量

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

变量定义

variable = value

示例

http_port=80

变量调用方式:

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

变量来源:

  • Ansible的setup facts远程主机的所有变量都可以直接调用
  • 通过命令行指定变量,优先级最高

ansible-playbook -e varname=value

  • 在Playbook文件中定义

vars: - var1: value1 - var2: value2

  • 在独立的变量YAML文件中定义

- hosts: all vars_files: - vars.yml

  • 在/etc/ansible/hosts中定义

主机(普通)变量:主机组中单独定义,优先级高于公共变量 组(公共)变量:针对主机组中所有主机定义统一变量

  • 在role中定义
1.使用setup模块中变量

本模块自动在playbook调用,不需要Ansible命令调用

使用setup变量

[root@ansible-maseter ~]# ansible Apache -m setup -a 'filter="ansible_default_ipv4"'  # 查看目标主机的网卡信息

创建变量文件

[root@ansible-maseter ~]# vim var1.yml  #调用内置变量
[root@ansible-maseter ~]# cat var1.yml 
---
#var1.yml
- hosts: Apache
  remote_user: root
  gather_facts: yes
 
  tasks:
   - name: create  log file
     file: name=/data/{{ansible_nodename}}.log state=touch owner=mr-he mode=6000
[root@ansible-maseter ~]# ansible-playbook var1.yml
[root@ansible-maseter ~]# ansible  Apache -a 'ls -l /data'
2.在playbook命令行中定义变量

示例:

[root@ansible-maseter ~]# vim var2.yml 
[root@ansible-maseter ~]# cat var2.yml 
---
- hosts: Apache
  remote_user: root
  tasks:
   - name: install package
     yum: name={{ pkname }} state=present

[root@ansible-maseter ~]# ansible-playbook -e pkname=httpd var2.yml  
[root@ansible-maseter ~]#
3.在playbook文件中定义变量

示例1:

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

[root@ansible-maseter ~]# ansible-playbook -e "username=user2 group=group2" var3.yml   # 命令行优先级高于yaml文件优先级
[root@ansible-maseter ~]#

示例2:

[root@ansible-maseter ~]# vim var4.yml
[root@ansible-maseter ~]# cat var4.yml 
---
 - hosts: Apache
   remote_user: root
   vars:
     collect_info: "/data/test/{{ ansible_default_ipv4['address'] }}/"
   
   tasks:
    - name: create IP directory
      file: name="{{ collect_info }}" state=directory
[root@ansible-maseter ~]# ansible-playbook var4.yml 
[root@ansible-maseter ~]# ansible Apache -m shell -a 'ls /data/test/'
192.168.80.167 | CHANGED | rc=0 >>
192.168.80.167
[root@ansible-maseter ~]#
4.使用变量文件

可以在一个独立的playbook文件中定义变量,在另一个playbook文件中应用变量文件中的变量,比playbook中定义变量的优先级高

定义变量文件:

[root@ansible-maseter ~]# vim var.yml
[root@ansible-maseter ~]# cat var.yml 
---
# variables file
package_name: mariadb-server
service_name: mariadb

[root@ansible-maseter ~]# vim var5.yml
[root@ansible-maseter ~]# cat var5.yml 
---
#install package and start service
- hosts: Apache
  remote_user: root
  vars_files:
     - /root/var.yml  # 定义变量文件路径
   
  tasks: 
   - name: install package
     yum: name={{ package_name }}
     tags: install
   - name: start service
     service: name={{ service_name }} state=started enabled=yes
[root@ansible-maseter ~]# ansible-playbook var5.yml
5.主机清单文件中定义变量

主机变量

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

示例:

[Apache]
192.168.80.167 hname=www1 domain=learn.io

组(公共)变量

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

示例:

[Apache:vars]
mark="-"
domain=learn.org

示例:

[root@ansible-maseter ~]# vim /etc/ansible/hosts 
[root@ansible-maseter ~]# cat /etc/ansible/hosts 
[Apache]
192.168.80.167 hname=www1 domain=learn.io

[Apache:vars]
mark="-"
domain=learn.org
[root@ansible-maseter ~]# ansible Apache -m hostname -a 'name={{hname}}{{ mark }}{{ domain }}'

#命令行指定变量,优先级高于文件
[root@ansible-maseter ~]# ansible Apache -e domain=magedu.cn -m hostname -a 'name={{hname}}{{ mark }}{{ domain }}'

7.2.9 playbook使用when

when语句,可以实现条件测试。如果需要根据变量,facts或此前任务的执行结果来作为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式为:

示例:只有当系统版本为RedHat的才立即关机

---
- hosts: Apache
  remote_user: root
  tasks:
   - name: "shutdown RedHat flavored systems"
     command: /sbin/shutdown -h now
     when: ansible_os_familly == "RedHat"

示例:

---
- hosts: Apache
  remote_user: root
  tasks:
   - name: add group nginx
     tags: user
     group: name=nginx state=present
   - name: add user nginx
     user: name=nginx state=present group=nginx
   - name: Install Nginx
     yum: name=nginx state=present
   - name: restart Nginx
     service: name=nginx state=restarted
     when: absible_distribution_major_version="6"  # 只有当内核版本为6的才执行这个name

7.2.10 playbook使用迭代with_items

迭代:当有需要重复性执行的任务时,可以使用迭代机制

对迭代项的引用,固定变量名为“items”

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

列表元素格式:

  • 字符串
  • 字典

示例:

---
- hosts: Apache
  remote_user: root
  
  tasks:
  - name: add several users
    user: name={{ item }} state=present groups=wheel
    with_items:
     - testuser1
     - testuser2
     # 上面的语句功能等同于下面的语句
  - name: add several users     
    user: name=testuser1 state=present groups=wheel
  - name: add several users      
    user: name=testuser2 state=present groups=wheel

示例:卸载MySQL

---
#remove mariadb-server
- hosts: Apache
  remote_user: root
  
  tasks:
   - name: stop service
     shell: /etc/init.d/mysqld stop # 停止mysql服务
   - name: deletc files and directory
     file: path={{item}} state=absent
     with_items:
     - /usr/local/mysql
     - /usr/local/mariadb-10.2.2.27-linux-x86_64
     - /etc/init.d/mysqld
     
   - name: delete user
     user: name=mysql state=absent remove=yes

示例:下载Nginx,MySQL,Apache服务器,并添加相关的用户和组

---
 - hosts: Apache
   remote_user: root
   
   tasks:
    - name: Install Service
      yum: name={{ item }} state=present
    - name: add some groups
      group: name={{ item }} state=present
      with_items:
      - nginx
      - mysql
      - apache
    - name: add some users
      user: name={{item.name}} group={{ item.group }} state=present
      with_items:
      - { name:'nginx',group:'nginx'}
      - { name:'mysql',group:'mysql'}
      - { name:'apache',group:'apache'}

7.2.11 管理节点过多导致的超时问题解决办法

默认情况下,Ansible将尝试并行管理palybook中所有的机器。对于滚动更新用例,可以使用serial关键字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数占总数的比例

---
- hosts: Apache
  serial:2 #每次只同时处理2个主机
  gather_facts: False
  
  tasks:
   - name: task one
     command: hostname
   - name: task two
     command: hostname

示例:

- name: test serail
  hosts: all
  serial: "20%" #每次只同时处理20%的主机

7.2.12 Ansible-playbook 执行慢原因排查

Ansible自动化运维_运维_06

可能出现的原因有:

1.基于ssh,是否ssh连接客户端,网络延迟大

# 如果连接内网服务器,建议修改如下参数:
vim  /etc/ssh/sshd_config
GSSAPIAuthentication no
UseDNS no

2.是否ansible服务器资源不足或负载较高

# 使用w/top/uptime 查询是否机器负载太高,如果负载太高,等待有关进程执行完毕

3.是否执行时,有部分主机报错,执行失败

4.是否playbook执行的yml问题

5.是否ansible本身配置问题

# 1.可以修改forks 并行数,默认为5

实际主要问题在执行playbook后,第一步特别慢(GATHERING FACTS)。原因是由于Ansible默认对远程主机执行任何一个playbook之前,都会先通过setup模块获取facts。它是从远程主机上自动收集的变量。包括主机名、内核版本、网卡、IP、环境变量等等信息,用于ansible后续的其他操作,所以特别费时间,通常如果不需要facts需要对其配置进行关闭。如果需要就必须的开启了,(例如:你要获取远程主机的系统版本,然后判断安装什么版本的包) . 也可以配置redis缓存facts,避免频繁读取facts

`facts 关闭方法:
vim ~/ansible.cfg
[defaults]
~
gathering = explicit 
~
#smart 表示默认收集 facts,但 facts 已有的情况下不会收集,即使用缓存 facts
#implicit 表示默认收集 facts,要禁止收集,必须使用 gather_facts: False
#explicit 则表示默认不收集,要显式收集,必须使用 gather_facts: Ture

使用Redis配置facts缓存

[defaults]
inventory = /root/Ansible/playbook/hosts
forks = 5
check_host_keys = False
host_key_checking = False
host_key_auto_add = False
host_key_file = /root/.ssh/known_hosts
log_path = /data/log/ansible/ansible.log
command_warnings=False
gathering = smart
fact_caching_timeout = 86400 
fact_caching = redis
fact_caching_connection = 127.0.0.1:6379:0:kdlrdsha2019  # Redis服务器:Redis端口:Redis库:Redis密码

[privilege_escalation]
become=False

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r
scp_if_ssh = True

8.Playbook应用案例

8.1 Playbook应用案例之用户

#编写playbook创建系统账户,账号属性,设置密码

[root@servera ansible]# vim ~/ansible/example2.yml   #编写yaml文件
[root@servera ansible]# cat ~/ansible/example2.yml   #查看yaml文件
---
- hosts: client1           #给主机client1添加用户
  tasks:
     - name: Add group is daemon
       group:  #调用group模块
          name: daemon    #创建名为daemon的组
          gid:  1010      #daemon的组ID为1010
     - name: Add user is john
       user: #调用user模块
          name: john  #创建名为john的组
          uid: 1010   #john的组ID为1010
          groups: daemon,root    #设置附加组为daemon和root
          shell: /bin/bash      #设置用户的登录shell,/bin/bash允许登录,/sbin/nologin
          password: "{{'123456'|password_hash('sha512')}}"  #设置密码为123456,加密方法为hash加密法中的sha512算法

[root@servera ansible]# ansible-playbook example2.yml 

PLAY [client1] *****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [client1]

TASK [Add group is daemon] *****************************************************
ok: [client1]

TASK [Add user is john] ********************************************************
changed: [client1]

PLAY RECAP *********************************************************************
client1                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@servera ansible]# 


#编写playbook删除系统用户
[root@servera ansible]# vim ~/ansible/example3.yml   #编写删除用户的playbook
[root@servera ansible]# cat ~/ansible/example3.yml 
---
- hosts: client1  #指定client1主机
  tasks:
      - name: Remove the user john
        user: #指定user模块
             name: john  #指定要删除的用户
             state: absent #指定状态为删除
[root@servera ansible]# ansible-playbook example3.yml 

PLAY [client1] *****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [client1]

TASK [Remove the user john] ****************************************************
changed: [client1]

PLAY RECAP *********************************************************************
client1                    : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@servera ansible]#

8.2 Playbook应用案例之逻辑卷管理

#使用vdb创建卷组和逻辑卷(手动添加虚拟磁盘)
[root@servera ansible]# vim ~/ansible/example3.yml   #编写删除用户的playbook
[root@servera ansible]# cat ~/ansible/example3.yml 
---
- hosts: client1  #指定client1主机
  tasks:
      - name: Create a new primary partition with a size of 1GIB
        parted: #指定parted模块  物理卷管理模板
             device:/dev/sdb  #指定磁盘
             number:1 #创建一个分区,编号为1
             state: present #指定状态为创建,absent为删除
             part_end:1GiB  #指定磁盘大小,大小计算方式:这个分区的part_end减去上个分区的part_end
             device:/dev/sdb  #指定磁盘
             number:2 #创建一个分区,编号为2
             state: present #指定状态为创建,absent为删除
             part_start:1GiB #指定磁盘大小
             part_end:1GiB  #指定磁盘大小,大小计算方式:这个分区的part_end减去上个分区的part_end 
                            #或者part_end  - part_start
      - name: Create a volume group on top of /dev/sdb1
        lvg:   #指定lvg模块   #卷组管理模板
             vg:my_vg   #指定卷组名称
             pvs: /dev/sdb1  #指定卷组所在分区
      - name: create a logical volume os 512m
        lvol:   #指定lvol模块   #逻辑卷管理模板
             vg:my_vg   #继承上面的卷组名称
             lv:mv_lv   #指定逻辑卷的名称
             size:512m  #指定逻辑卷的大小
         
[root@servera ansible]# ansible-playbook example3.yml 

PLAY [client1] *****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [client1]

TASK [Remove the user john] ****************************************************
changed: [client1]

PLAY RECAP *********************************************************************
client1                    : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@servera ansible]#

8.3 Playbook应用案例之应用管理

#安装软件,升级软件,安装组包
[root@servera ansible]# vim ~/ansible/example4.yml
[root@servera ansible]# cat ~/ansible/example4.yml 
---
- hosts: client1   #目标主机
  tasks: 
    - name: Install a list of packages
      yum:
          name:
             - httpd  //apache服务软件包
             - mariadb  //数据库服务软件包
             - bind   //DNS服务软件包
     - name:Install the 'Development tools' package group  //下载这个组包
       yum:
           name:"@Development tools"
     - name: update software  #更新软件
       yum:
           name:'*' //通配符,代表所有的软件名称
           state:latest
[root@servera ansible]# 
[root@servera ansible]# ansible-playbook example4.yml 

PLAY [client1] *****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [client1]

TASK [Install a list of packages] **********************************************
changed: [client1]

PLAY RECAP *********************************************************************
client1                    : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

8.4 特殊模块

8.4.1 setup模块

ansible_facts用于采集被管理设备的系统信息

所有收集的信息都被保存在变量中

每次执行playbook默认第一个任务就是Gathering Facts

使用setup模块可以查看收集到的facts信息

[root@servera ansible]# ansible client1 -m setup
client1 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.80.134"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::9097:50f2:5b80:23d7",
            "fe80::b950:228b:b37e:876e"
        ],
        "ansible_apparmor": {
            "status": "disabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "07/22/2020",
        "ansible_bios_version": "6.00",
        "ansible_cmdline": {
            "BOOT_IMAGE": "(hd0,msdos1)/vmlinuz-4.18.0-80.el8.x86_64",
            "crashkernel": "auto",
            "quiet": true,
            "rd.lvm.lv": "rhel/swap",
            "resume": "/dev/mapper/rhel-swap",
            "rhgb": true,
            "ro": true,
            "root": "/dev/mapper/rhel-root"
        },
        ......省略以下部分
8.4.2 debug模块

debug模块可以显示变量的值,可以辅助排错

debug模块有两个参数,var和msg(引用变量需要{{}})

[root@servera ansible]# vim ~/ansible/example5.yml
[root@servera ansible]# cat ~/ansible/example5.yml 
---
- hosts: client1
  tasks:
       - debug:  #获取目标主机client1的IP地址
               var: ansible_all_ipv4_addresses
       - debug:  #获取目标主机client1的主机名
               msg: "主机名是:{{ansible_hostname}}"

       - debug:  #获取目标主机client1的逻辑卷大小
               var: ansible_devices.vda.partitions.vda1.size
       - debug:  #获取目标主机client1的总内存大小
               msg: "总内存大小:{{ansible_memtotal_mb}}"

[root@servera ansible]# vim ~/ansible/example6.yml
[root@servera ansible]# cat ~/ansible/example6.yml 
---
- hosts: client1
  tasks:
       - name: This is ping module!
         ping:


[root@servera ansible]# ansible-playbook example6.yml 
[root@servera ansible]# ansible-playbook example5.yml

9.Ansible自定义变量

在Ansible中支持十几种定义变量的方式

例如(根据优先级排序)

9.1 Inventory变量

[root@servera ~]# cd ansible/
[root@servera ansible]# vim ~/ansible/hosts #在主机清单配置文件中定义变量
[root@servera ansible]# cat ~/ansible/hosts 
[webserver]
client1 myvar1="hello world" myvar2="content" #在client1主机上定义两个变量myvar1,myvar2
[database]
client2
[cluster:children]
webserver
databasei
[webserver:vars]
name="jacob"
[root@servera ansible]# vim ~/ansible/inventory_var.yml  #编写playbook
[root@servera ansible]# cat ~/ansible/inventory_var.yml 
---
- hosts: client1             #目标主机:client1
  tasks:
      - name: create a file with var.  #任务名称
        shell: echo {{myvar1}} > /tmp/{{myvar2}}  #任务脚本
- hosts: webserver           #目标组:webserver
  tasks:
      - name: create a user with var.  #任务名称
        user:
             name: "{{name}}"       #创建一个名为jacob用户

[root@servera ansible]# ansible-playbook inventory_var.yml   #运行playbook

9.2 Host Facts变量

Host  Facts变量(直接调用ansible收集的系统信息)
[root@servera ansible]# vim ~/ansible/facts_var.yml
[root@servera ansible]# cat ~/ansible/facts_var.yml 
---
- hosts: client1
  tasks:
       - name: Use facts info.
         copy: 
              content: "{{ansible_hostname}}:{{ansible_bios_version}}"
              dest: /tmp/facts.txt
[root@servera ansible]# ansible-playbook facts_var.yml

9.3 Register 变量

Register 语句可以将某个命令的执行结果保存到变量中
[root@servera ansible]# vim ~/ansible/register.yml
[root@servera ansible]# cat ~/ansible/register.yml 
---
- hosts: client1
  tasks:
       - name: save shell result to a variable.
         shell: hostname
         register: myvar
       - name: print the variable's through debug
         debug: 
            msg: "{{myvar}}"

[root@servera ansible]# ansible-playbook register.yml 

通过“.”还可以提取部分数据
[root@servera ansible]# vim ~/ansible/register.yml
[root@servera ansible]# cat ~/ansible/register.yml 
---
- hosts: client1
  tasks:
       - name: save shell result to a variable.
         shell: hostname
         register: myvar
       - name: print the variable's through debug
         debug: 
            msg: "{{ myvar.stdout }}"

[root@servera ansible]# ansible-playbook register.yml

9.4 Playbook 变量

playbooks变量(使用vars关键词可以在playbook内定义变量)
[root@servera ansible]# vim ~/ansible/playbook_var.yml
[root@servera ansible]# cat ~/ansible/playbook_var.yml 
---
- hosts: client1
  vars:
          iname: heal
          ipass: '123456'   #密码为字符串,需要用引号引起来
  tasks:
       - name: Use variables create user.
         user:
                 name: "{{iname}}"
                 password: "{{ipass | password_hash('sha512')}}"
[root@servera ansible]# ansible-playbook playbook_var.yml 


playbook提示变量(根据提示输入变量的值)
[root@servera ansible]# vim ~/ansible/prompt_var.yml
[root@servera ansible]# cat ~/ansible/prompt_var.yml
---
- hosts: client1
  vars_prompt:
          - name: iname
            prompt: "请输入用户名"   
            private: no             #显示用户名
          - name: ipasswd
            prompt: "请输入密码"
            private: yes            #不显示密码
  tasks: 
         - name: Create a user
           user: 
               name: "{{iname}}"
               password: "{{ ipasswd | password_hash('sha512')}}"
[root@servera ansible]# ansible-playbook prompt_var.yml  


单独定义个变量文件,在playbook中用vars_files调用该文件
[root@servera ansible]# vim ~/ansible/variables.yml
[root@servera ansible]# cat ~/ansible/variables.yml 
---
iname: cloud
ipass: '123456'
[root@servera ansible]# vim ~/ansible/file_var.yml
[root@servera ansible]# cat ~/ansible/file_var.yml 
---
- hosts: client1
  vars_files: variables.yml
  tasks:
      - name: create user.
        user:
           name: "{{iname}}"
           passwoed: "{{ipass|password_hash('sha512')}}"
[root@servera ansible]# ansible-playbook file_var.yml 


执行ansible—playbook命令时使用-e参数定义变量
[root@servera ansible]# vim ~/ansible/command_var.yml
[root@servera ansible]# cat ~/ansible/command_var.yml 
---
- hosts: client1
  tasks:
        - name: create user
          user:
                  name: "{{iname}}"
                  password: "{{ipass | password_hash('sha512')}}"

[root@servera ansible]# ansible-playbook command_var.yml -e iname="blue" -e ipass="123456"