1.系统一致性
2.软件版本一致性
3.安装路径一致性
选择ansible
1.活跃度
2.学习成本
3.使用成本
4.编码语言
5.性能
6.使用是否广泛
安装ansible
• ansible 可以基于源码运行
• 源码安装
– pip,需要配置扩展软件包源 extras
– git
yum install epel-release
yum install git python2-pip
– pip安装依赖模块
pip install paramiko PyYAML Jinja2 httplib2 six
• ansible ×××
– git clone git://github.com/ansible/ansible.git
– yum install python-setuptools python-devel
– python setup.py build
– python setup.py install
• pip 方式安装
– pip install ansible
• yum 扩展源安装简单,自劢解决依赖关系(推荐)
– http://mirror.centos.org/.../.../extras/
– yum install ansible
• 安装完成以后验证
– ansible -version
一.ad-hoc
1.主机管理
• 安装好了 Ansible 之后就可以开始一些简单的任务了
• Ansible配置文件查找顺序
– 首先检测 ANSIBLE_CONFIG 变量定义的配置文件
– 其次检查当前目彔下的 ./ansible.cfg 文件
– 再次检查当前用户家目彔下 ~/ansible.cfg 文件
– 最后检查 /etc/ansible/ansible.cfg 文件
• /etc/ansible/ansible.cfg 默认配置文件路径
• ansible.cfg 配置文件
– inventory 是定义托管主机地址配置文件
– 首先编辑 /etc/ansible/hosts 文件,写入一些进程主
机的地址。
• 格式
– # 表示注释
[组名称]
主机名称或ip地址,登彔用户名,密码、端口等信息
• 测试
– ansible [组名称] --list-hosts
• inventory 参数说明
– ansible_ssh_host
– 将要连接的进程主机名.不你想要设定的主机的别名不
同的话,可通过此变量设置.
– ansible_ssh_port
– ssh端口号.如果不是默认的端口号,通过此变量设置.
– 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”
vim /etc/ansible/hosts
[web]
web11
192.168.4.12 ansible_ssh_user="root" ansible_ssh_pass="123456" #或者192.168.4.[11:12]
[db]
db[1:2] #连续可以用此方法
[cache]
192.168.4.15
[wd:children] #集合2个组
web
db
[db:vars]
ansible_ssh_user="root"
ansible_ssh_pass="123456"
ansible_ssh_port="22"
:wq
ansible web --list-host #查看定义的组
ansible wd -m ping #测试连通
vim /etc/ansibleansible.cfg
61 host_key_checking = False #开启ssh不验证yes
自定义配置文件
mkdir /root/myansible #随便一个文件夹
cd /root/myansible
vim ansible.cfg
[defaults]
inventory = myhost #定义分组文件
:wq
vim myhost #编辑分组文件
[aa]
web1
web2
[bb]
db1
db2
:wq
ansible aa --list-hosts #在当前文件夹下执行查看分组
动态主机
无限可能
– Ansible Inventory实际上是包含静态Inventory和动
态Inventory两部分,静态Inventory指的是在文件
/etc/ansible/hosts中指定的主机和组,Dynamic
Inventory指通过外部脚本获取主机列表,并按照
ansible 所要求的格式返回给ansilbe命令的。
• json
– JSON的全称是”JavaScript Object Notation”,意
思是JavaScript对象表示法,它是一种基于文本,独立
于语言的轻量级数据交换格式。
• 注意事项:
– 1、主机部分必须是列表格式的;
– 2、hostdata行,其中的"hosts" 部分可以省略,但如
果使用时,必须是"hosts"
• 脚本输出主机列表
#!/usr/bin/python
import json
hostlist = {}
hostlist["bb"] = ["192.168.1.15", "192.168.1.16"]
hostlist["192.168.1.13"] = {
"ansible_ssh_user":"root","ansible_ssh_pass":"pwd"
}
hostlist["aa"] = {
"hosts" : ["192.168.1.11", "192.168.1.12"],
"vars" : {
"ansible_ssh_user":"root","ansible_ssh_pass":"pwd"
}
}
print( json.dumps(hostlist))
• 脚本输出样例
{
"aa" : {
"hosts" : ["192.168.1.11", "192.168.1.12"],
"vars" : {
"ansible_ssh_user" : "root",
"ansible_ssh_pass" : "pwd"
}
},
"bb" : ["192.168.1.15", "192.168.1.16"],
"192.168.1.13": { "ansible_ssh_user" : "root",
"ansible_ssh_pass" : "pwd"}
}
vim ansible.cfg
[defaults]
inventory = myhost.py #指定脚本返回JSON格式
ansible命令基础
• ansible
– host-pattern 主机或定义的分组
– -M 指定模块路径
– -m 使用模块,默认 command 模块
– -a or --args 模块参数
– -i inventory 文件路径,或可执行脚本
– -k 使用交互式登彔密码
– -e 定义变量
– -v 详细信息,-vvvv 开启 debug 模式
• 列出要执行的主机,不执行任何操作
– ansible all --list-hosts
• 批量检测主机
– ansible all -m ping
• 批量执行命令
– ansible all -m command -a 'id' -k
2.批量执行
ansible命令基础
ansible
-host-pattern
ansible all -m command -a "id" -k #所有机器使用用command模块,执行id命令,-K 交互输入密码
ansible all -m copy -a "src=./2.txt dest=/tmp/" -k #批量复制
批量部署证书文件
批量部署证书文件
• 每次交互输入密码比较麻烦
• 密码写入配置文件安全性很差
• 不同主机不同密码,配置文件要上天
• 使用 key 方式认证,是一个不错的选择
• 给所有主机部署公钥
– ansible all -m authorized_key -a "user=root
exclusive=true manage_dir=true key='$(<
/root/.ssh/authorized_keys)'" -k -v
• 报错
– "msg": "Using a SSH password instead of a key is
not possible because Host Key checking is
enabled and sshpass does not support this.
Please add this host's fingerprint to your
known_hosts file to manage this host."
– 解决方法:
– 修改 ansible.cfg
host_key_checking = False
ansible all -m authorized_key -a "user=root exclusive=true manage_dir=true key='$(< /root/.ssh/authorized_keys)'" -k -v #或/root/.ssh/id_rsa.pub
exclusive=true #覆盖之前的key文件
模块
• ansible-doc
– 模块的手册,相当不 shell 的 man
– 非常重要,非常重要,非常重要
– ansible-doc -l 列出所有模块
– ansible-doc modulename 查看帮助
• ping 模块
– 测试网络连通性, ping模块没有参数
– 注:测试 ssh 的连通性
– ansible host-pattern -m ping
• command模块
– 默认模块,进程执行命令
– 用法
– ansible host-pattern -m command -a '[args]'
– 查看所有机器负载
ansible all -m command -a 'uptime'
– 查看日期和时间
ansible all -m command -a 'date +%F_%T'
• command模块注意事项:
– 该模块通过-a跟上要执行的命令可以直接执行,不过
命令里如果有带有如下字符部分则执行不成功
– "<", ">", "|", "&"
– 该模块不启动 shell 直接在 ssh 进程中执行,所有使用
到 shell 特性的命令执行都会失败
– 下列命令执行会失败
ansible all -m command -a 'ps aux|grep ssh'
ansible all -m command -a 'set'
• shell | raw 模块
– shell 模块用法基本和command一样,区别是 shell模
块是通过/bin/sh进行执行命令,可以执行任意命令
– raw模块,用法和shell 模块一样 ,可以执行任意命令
– 区别是 raw 没有chdir、creates、removes参数
– 执行以下命令查看结果
ansible t1 -m command -a 'chdir=/tmp touch f1'
ansible t1 -m shell -a 'chdir=/tmp touch f2'
ansible t1 -m raw -a 'chdir=/tmp touch f3'
• script模块
– 复杂命令怎么办?
– ansible 要上天
– 直接在本地写脚本,然后使用 script 模块批量执行
– ansible t1 -m script -a 'urscript'
– 友情提示: 该脚本包含但不限于 shell 脚本,只要指
定 Sha-bang 解释器的脚本都可运行
#!/bin/bash
if ! $(id li4 &> /dev/null);then
useradd zhang3
echo 123456 |passwd --stdin zhang3
chage -d 0 zhang3
fi
• copy 模块
– 复制文件到进程主机
– src:要复制到进程主机的文件在本地的地址,可以是
绝对路径,也可以是相对路径。如果路径是一个目彔,
它将递归复制。在这种情况下,如果路径使用"/"来结
尾,则只复制目彔里的内容,如果没有使用"/"来结尾,
则包含目彔在内的整个内容全部复制,类似于rsync
– dest:必选项。进程主机的绝对路径,如果源文件是
一个目录,那么该路径也必须是个目录
• copy 模块
– backup:在覆盖之前将原文件备份,备份文件包含时
间信息。有两个选项:yes|no
– force:如果目标主机包含该文件,但内容不同,如果
设置为yes,则强制覆盖,如果为no,则只有当目标主
机的目标位置不存在该文件时,才复制。默认为yes
– 复制文件
ansible t1 -m copy -a 'src=/root/alog dest=/root/a.log'
– 复制目彔
ansible t1 -m copy -a 'src=urdir dest=/root/'
• lineinfile | replace 模块
– 类似 sed 的一种行编辑替换模块
– path 目的文件,修改哪个文件
– regexp 正则表达式,修改哪个地方
– line 替换后的结果,修改成啥样
ansible t1 -m lineinfile -a 'path="/etc/selinux/config"
regexp="^SELINUX=" line="SELINUX=disabled"'
ansible all -m lineinfile -a 'path="/etc/sysconfig/network-scripts/ifcfg-eth0" regexp="^BOOTPROTO=" line="BOOTPROTO=none"'
– 替换指定字符
ansible t1 -m replace -a 'path="/etc/selinux/config"
regexp="^(SELINUX=).*" replace="\1disabled"'
ansible all -m replace -a 'path="/etc/sysconfig/network-scripts/ifcfg-eth0" regexp="^(BOOTPROTO=).*" replace="\1static"'
• yum模块
– 使用yum包管理器来管理软件包
– config_file:yum的配置文件
– disable_gpg_check:关闭gpg_check
– disablerepo:不启用某个源
– enablerepo:启用某个源
– name:要进行操作的软件包的名字,也可以传递一个
url或者一个本地的rpm包的路径
– state:状态(present,absent,latest)
安装 ,删除,更新
• yum模块
– 删除软件包
ansible t1 -m yum -a 'name="lrzsz" state=absent'
– 删除多个软件包
ansible t1 -m yum -a 'name="lrzsz,lftp" state=absent'
– 安装软件包
ansible t1 -m yum -a 'name="lrzsz"'
– 安装多个软件包
ansible t1 -m yum -a 'name="lrzsz,lftp"'
• service模块
– name:必选项,服务名称
– enabled:是否开机启动 yes|no
– sleep:如果执行了restarted,在则stop和start之间
沉睡几秒钟
– state:对当前服务执行启动,停止、重启、重新加载
等操作(started,stopped,restarted,reloaded)
ansible t1 -m service -a 'name="sshd" enabled="yes"
state="started"'
在web1 web2上安装apache并且设置开机启动,启动服务,端口给为8080,主页是hello world
ansible web -m yum -a 'name="httpd"'
ansible web -m service -a 'name="httpd" enabled="yes" state="started"'
ansible web -m lineinfile -a 'path="/etc/httpd/conf/httpd.conf" regexp="^Listen" line="Listen 8080"'
ansible web -m shell -a 'echo hello world > /var/www/html/index.html'
ansible web -m service -a 'name="httpd" enabled="yes" state="restarted"'
ansible web -m shell -a 'curl http://127.0.0.1:8080'
ansible web -m replace -a 'path="/etc/httpd/conf/httpd.conf" regexp="(^Listen).*" replace="\1 8080"'
• setup模块
– 主要用于获取主机信息,在playbooks里经常会用到的
一个参数gather_facts就不该模块相关。setup模块下
经常使用的一个参数是filter参数
– filter 可以过滤到我们需要的信息
ansible t1 -m setup -a 'filter=ansible_distribution'
ansible七种武器
• 第一种武器
– ansible 命令,用于执行临时性的工作,也是我们之前
主要学习的功能,必须掌握
• 第二种武器
– ansible-doc 是 Ansible模块文档说明,针对每个模块
都有详细的用法说明及应用案例介绍,功能和Linux系
统man命令类似,必须掌握
第三种武器
– ansible-console 是 Ansible 为用户提供的一款交互
式工具,用户可以在 ansible-console 虚拟出来的终
端上像 Shell 一样使用 Ansible 内置的各种命令,
这为习惯于使用 Shell 交互方式的用户提供了良好的
使用体验。
• 第四种武器
– ansible-galaxy 从 github 上下载管理 Roles 的一款
工具,不 python 的 pip 类似。
第五种武器
– ansible-playbook 是日常应用中使用频率最高的命令,
其工作机制是:通过读取预先编写好的 playbook 文
件实现批量管理。要实现的功能不命令 ansible 一样,
可以理解为按一定条件组成的 ansible 任务集,必须
掌握
• 第六种武器
– ansible-vault 主要用于配置文件加密,如编写的
Playbook 配置文件中包含敏感信息,不希望其他人随
意查看, ansible-vault 可加密/解密这个配置文件
第七种武器
– ansible-pull
– Ansible 有两种工作模式 pull/push ,默认使用 push
模式工作,pull 模式和通常使用的 push 模式工作机
理刚好相反
– 适用场景:有数量巨大的机器需要配置,即使使用高
并发线程依旧要花费很多时间;
– 通常在配置大批量机器的场景下会使用,灵活性稍有
欠缺,但效率几乎可以无限提升,对运维人员的技术
水平和前瞻性规划有较高要求。
json简介
• json 是什么?
– json 是 JavaScript 对象表示法,它是一种基于文本,
独立于语言的轻量级数据交换格式。
– JSON中的分隔符限于单引号 ' 、小括号 ()、中括号
[ ]、大括号 { } 、冒号 : 和逗号 ,
• json 特性
– JSON 是纯文本
– JSON 具有"自我描述性"(人类可读)
– JSON 具有层级结构(值中存在值)
– JSON 可通过 JavaScript 进行解析
json 语法规则
– 数据在名称/值对中
– 数据由逗号分隔
– 大括号保存对象
– 中括号保存数组
• json 数据的书写格式是:名称/值对。
– 名称/值对包括字段名称(在双引号中),后面写一个
冒号,然后是值,
yaml简介
• yaml 是什么
– 是一个可读性高,用来表达数据序列的格式。
– YAML:YAML Ain't Markup Language
– YAML参考了其他多种语言,包括:C语言、Python、
Perl,并从XML、电子邮件的数据格式(RFC 2822)
中获得灵感。Clark Evans在2001年首次发表了这种语
言[1],另外Ingy döt Net不Oren Ben-Kiki也是这语
言的共同设计者[2]。目前已经有数种编程语言或脚本
语言支持(或者说解析)这种语言。
yaml 基础语法
– YAML的结构通过空格来展示
– 数组使用"- "来表示
– 键值对使用": "来表示
– YAML使用一个固定的缩进风格表示数据层级结构关系
– 一般每个缩进级别由两个以上空格组成
– # 表示注释
• 注意:
– 不要使用tab,缩进是初学者容易出错的地方之一
– 同一层级缩进必须对齐
YAML的键值表示方法
– 采用冒号分隔
– : 后面必须有一个空格
– YAML键值对例子
"人名": "称号"
– 或
"人名":
"称号"
– 复杂YAML的键值对嵌套
"讲师":
"人名": "aa"
– 或
"讲师":
"aa":
"bb"
– 数组
["aa", "丁丁", "bb", "cc"]
YAML 数组表示方法
– 使用一个短横杠加一个空格
– YAML 数组例子
- "aa"
- "vv"
- "cc"
- "dd"
– 哈希数组复吅表达式
"讲师": - "dd"
- "vv"
- "dd"
- "zz"
– 高级复吅表达式
"讲师":
"aa": "小逗比"
"阶段": 1
"bb": "老逗比"
"阶段": 2
"cc": "漂亮姐"
"阶段": 3
"dd": "老司机"
"阶段": 4
yaml高级语法
– | 不 > 表示对应的值为多行字符, > 不 | 的区别是会
把 \n 转换为空格
– ! 可以设置类型,!! 可以强制类型转换
– 为了维持文件的简洁,并避免数据输入的错误,YAML
提供了结点参考(*)和散合并(<<)参考到其他
结点标签的锚点标记(&)。参考会将树状结构加入锚
点标记的内容,并可以在所有数据结构中运作,合并
叧有散列表可以使用,可以将键值自锚点标记复制到
指定的散列表中
jinja2模版简介
• jinja2 是什么
– Jinja2是基于python的模板引擎,包含 变量 和 表达
式两部分,这两者在模板求值的时候会被替换为值。
模板中还有标签,控制模板的逻辑。
• 为什么要学习 jinja2 模版
– 要使用 ansible 就要深入学习 playbook 配置及模板。
playbook 的模板使用 python 的 jinja2 模块来处理的
jinja2 模版基本语法
– 模板的表达式都是包含在分隔符 "{{}}" 内的;
– 控制语句都是包含在分隔符 "{% %}" 内的;
– 另外,模板也支持注释,都是包含在分隔符 "{# #}"
内,支持块注释。
– 调用变量
{{varname}}
– 计算
{{2+3}}
– 判断
{{1 in [1,2,3]}}
jinja2 模版控制语句
{% if name == 'aa' %}
讲故事
{% elif name == 'bb' %}
嘿嘿
{% elif name == 'cc' %}
哈哈
{% else %}
沉迷学习,无法自拔
{% endif %}
jinja2 模版控制语句
{% if name == ... ... %}
... ...
{% elif name == '曹操' %}
{% for method in [约会, 逛街, 吃饭, 看电影] %}
{{do method}}
{% endfor %}
... ...
{% endif %}
jinja2 过滤器
– 变量可以通过 过滤器 修改。过滤器不变量用管道符号
( | )分割,并且也 可以用圆括号传递可选参数。多
个过滤器可以链式调用,前一个过滤器的输出会被作
为 后一个过滤器的输入。
– 例如:
– 把一个列表用逗号连接起来: {{ list|join(', ') }}
– 过滤器这里不一一列丼,需要的可以查询在线文档
http://docs.jinkan.org/docs/jinja2/templates.html
#builtin-filters
playbook是什么
• playbook 是什么?
– playbook 是 ansible 用于配置,部署,和管理托管主
机剧本。通过 playbook 的详绅描述,执行其中的一系
列 tasks,可以让进端主机达到预期的状态。
– 也可以这么理解,playbook 字面意思,即剧本,现实
中由演员按照剧本表演,在 Ansible 中由计算机进行表
演,由计算机安装,部署应用,提供对外服务,以及组
细计算机处理各种各样的事情
为什么要使用playbook
– 执行一些简单的任务,使用ad-hoc命令可以方便的解决
问题,但是有时一个设施过于复杂,需要大量的操作时
候,执行的 ad-hoc 命令是不适吅的,这时最好使用
playbook,就像执行 shell 命令不写 shell 脚本一样,
也可以理解为批处理任务
– 使用 playbook 你可以方便的重用编写的代码,可以移
植到不同的机器上面,像函数一样,最大化的利用代码
在使用 Ansible 的过程中,你也会发现,你所处理的大
部分操作都是编写 playbook
playbook 语法格式
– playbook由 YAML 语言编写,遵循 YAML 标准
– 在同一行中,#之后的内容表示注释
– 同一个列表中的元素应该保持相同的缩进
– playbook 由一个或多个 play 组成
– play 中 hosts,variables,roles,tasks 等对象的表示
方法都是键值中间以 ": " 分隔表示
– YAML 还有一个小的怪癖. 所有的 YAML 文件开始行都
应该是 ---. 这是 YAML 格式的一部分, 表明一个文件的
开始
playbook 构成
– Target: 定义将要执行 playbook 的进程主机组
– Variable: 定义 playbook 运行时需要使用的变量
– Tasks: 定义将要在进程主机上执行的任务列表
– Handler: 定义 task 执行完成以后需要调用的任务
Playbook执行结果
• 使用 ansible-playbook 运行playbook文件,得到输
出内容为 JSON 格式。并且由不同颜色组成,便于识
别。一般而言
• 绿色代表执行成功
• ***代表系统代表系统状态发生改变
• 红色代表执行失败
第一个playbook
- hosts: all
remote_user: root
tasks: - ping:
第一行,表示开始
ansible-playbook myping.yml -f 5
– -f 并发进程数量,默认是 5
– hosts 行的内容是一个或多个组或主机的 patterns,以
逗号为分隔符
– remote_user 就是账户名
第一个playbook
- hosts: all
remote_user: root
tasks: - ping:
第一行,表示开始
ansible-playbook myping.yml -f 5
– -f 并发进程数量,默认是 5
– hosts 行的内容是一个或多个组或主机的 patterns,以
逗号为分隔符
– remote_user 就是账户名
续... ...
– tasks
– 每一个 play 包含了一个 task 列表(任务列表).
– 一个 task 在其所对应的所有主机上(通过 host
pattern 匹配的所有主机)执行完毕之后,下一个 task
才会执行.
– 有一点需要明白的是(很重要),在一个 play 之中,
所有 hosts 会获取相同的任务指令,这是 play 的一个
目的所在,也就是将一组选出的 hosts 映射到 task,执
行相同的操作
playbook 执行命令
– 给所有主机添加用户 plj,设置默认密码 123456
– 要求第一次登录修改密码
- hosts: all
remote_user: root
tasks: - name: create user plj
user: group=wheel uid=1000 name=plj - shell: echo 123456 | passwd --stdin plj
- shell: chage -d 0 plj
变量
• 添加用户
– 给所有主机添加用户 plj,设置默认密码 123456
– 要求第一次登录修改密码(使用变量)
- hosts: 192.168.1.16
remote_user: root
vars:
username: plj
tasks: - name: create user "{{username}}"
user: group=wheel uid=1000 name={{username}} - shell: echo 123456 | passwd --stdin plj
- shell: chage -d 0 {{username}}
续... ...
– 解决密码明文问题
– user 模块的 password 为什么不能设置密码呢?
– 经过测试发现,password 是把字符串直接写入
shadow,并没有改变,而 Linux 的 shadow 密码是
经过加密的,所以不能使用
– 解决方案:
– 变量过滤器 password_hash
– {{ 'urpassword' | password_hash('sha512')}}
变量过滤器
– 给所有主机添加用户 plj,设置默认密码 123456
– 要求第一次登录修改密码(使用变量)
- hosts: 192.168.1.16
remote_user: root
vars:
username: plj
tasks: - name: create user "{{username}}"
user: group=wheel uid=1000 password={{'123456' | password_hash('sha512')}} name={{username}} #分为多行写时,值要用“”引起 如 group: "whell" - shell: chage -d 0 {{username}}
error
• ansible-playbook 对错误的处理
– 默认情况判断 $?,如果 值 不为 0 就停止执行
– 但某些情况我们需要忽略错误继续执行
- hosts: 192.168.1.16
remote_user: root
vars:
username: plj
tasks: - name: create user "{{username}}"
user: group=wheel uid=1000
password={{'123456'|password_hash('sha512')}}
name={{username}} - shell: setenforce 0
- shell: chage -d 0 {{username}}
error
• 续... ...
– 我们要关闭 selinux,如果 selinux 已经是关闭的,返
回 1 ,但我们的目的就是关闭,已经关闭算错误,
这个情况我们就需要忽略错误继续运行,忽略错误有
两种方法
– 第一种方式:
shell: /usr/bin/somecommand || /bin/true
– 第二种方式:
- name: run some command
shell: /usr/bin/somecommand
ignore_errors: True
完整 playbook
- hosts: 192.168.1.16
remote_user: root
vars:
username: plj
tasks: - name: create user "{{username}}"
user: group=wheel uid=1000
password={{'123456'|password_hash('sha512')}}
name={{username}} - shell: setenforce 0
ignore_errors: true - shell: chage -d 0 {{username}}
handlers
• 用于当关注的资源发生变化时采取一定的操作。
• "notify" 这个action可用于在每个play的最后被触发
这样可以避免多次有改变发生时每次都执行指定的操
作取而代之仅在所有的变化发生完成后一次性地执行
指定操作。
• 在 notify 中列出的操作称为 handler 也即 notify 中
调用 handler 中定义的操作
前面我们安装了 apache,很多情况是要修改 httpd
的配置文件的,修改配置文件以后要重新载入配置文
件让服务生效
• 这时候,我们可以使用 handlers 来实现
handlers:
- name: restart apache
service: name=apache state=restarted
结和之前试验,完整 playbook
- hosts: 192.168.1.16
remote_user: root
tasks: - name: config httpd.conf
copy: src=/root/playbook/httpd.conf
dest=/etc/httpd/conf/httpd.conf
notify: - restart httpd
handlers: - name: restart httpd
service: name=httpd state=restarted
注意事项:
– notify 调用的是 handler 段 name 定义的串,必须一
致,否则达不到触发的效果
– 多个 task 触发同一个 notify 的时候,同一个服务叧会
触发一次
– notify 可以触发多个条件,在生产环境中往往涉及到
某一个配置文件的改变要重启若干服务的场景,
handler 用到这里非常适吅.
– 结吅 vars 可以写出非常普适的服务管理脚本
when
• 某些时候我们可能需要在满足特定的条件后在触发某
一项操作,或在特定的条件下织止某个行为,这个时
候我们就需要进行条件判断,when 正是解决这个问
题的最佳选择,进程中的系统变量 facts 变量作为
when 的条件,这些 facts 我们可以通过 setup 模块
查看
– when 的样例:
tashs:
- name: somecommand
command: somecommand
when: expr
一个使用 when 的例子
- name: Install VIM
hosts: all
tasks: - name: Install VIM via yum
yum: name=vim-enhanced state=installed
when: ansible_os_family == "RedHat" - name: Install VIM via apt
apt: name=vim state=installed
when: ansible_os_family == "Debian"
register
• register
– 有时候我们可能还需要更复杂的例子,比如判断前一
个命令的执行结果,根据结果处理后面的操作,这时
候我们就需要 register 模块来保存前一个命令的返回
状态,在后面进行调用
- command: test command
register: result - command: run command
when: result
register
• 变量注册
– 例如我们需要判断 plj 这个用户是否存在
– 如果存在我就修改密码,如果不存在就跳过
tasks:
- shell: id {{username}}
register: result - name: change "{{username}}" password
user: password={{'12345678'|password_hash('sha512')}}
name={{username}}
when: result
变量注册进阶
– 我们还可以针对运行命令结果的返回值做判定
– 当系统负载超过一定值的时候做特殊处理
- hosts: 192.168.1.16
remote_user: root
tasks: - shell: uptime |awk '{printf("%f\n",$(NF-2))}'
register: result - shell: touch /tmp/isreboot
when: result.stdout|float > 0.5 #标准输出转化为浮点数
with_items
• with_items 是 playbook 标准循环,最常用到的就
是它,with_items 可以用于迭代一个列表或字典,
通过{{ item }}获取每次迭代的值
– 例如创建多个用户
- hosts: 192.168.1.16
remote_user: root
tasks: - name: add users
user: group=wheel password={{'123456' |
password_hash('sha512')}} name={{item}}
with_items: ["nb", "dd", "plj", "lx"]
with_items
• with_items进阶
– 为不同用户定义不同组
- hosts: 192.168.1.16
remote_user: root
tasks: - name: add users
user: group={{item.group}} password={{'123456' |
password_hash('sha512')}} name={{item.name}}
with_items: - {name: 'nb', group: 'root'}
- {name: 'dd', group: 'root'}
- {name: 'plj', group: 'wheel'}
- {name: 'lx', group: 'wheel'}
with_nested
• 嵌套循环:
- hosts: 192.168.1.16
remote_user: root
vars:
un: [a, b, c]
id: [1, 2, 3]
tasks: - name: add users
shell: echo {{item}}
with_nested: - "{{un}}"
- "{{id}}"
tags
• tags:给指定的任务定义一个调用标识;
• 使用格式:
– name: NAME
– module: arguments
– tags: TAG_ID
• playbook 调用方式
– -t TAGS, --tags=TAGS
– --skip-tags=SKIP_TAGS
– --start-at-task=START_AT
tags
• tags样例:
vars:
soft: httpd
tasks:
- name: install {{soft}}
yum: name={{soft}} - name: config httpd.conf
copy: src=/root/playbook/httpd.conf
dest=/etc/httpd/conf/httpd.conf - name: config services
service: enabled=yes state=restarted name={{soft}}
tags: restartweb
• 调用方式
ansible-playbook i.yml --tags=restartweb
include and roles
• 我们在编写 playbook 的时候随着项目越来越大,
playbook 也越来越复杂,修改起来也越来越麻烦。
这时候可以把一些 play、task 或 handler 放到其他
文件中,然后通过include指令包含进来是一个不错
的选择
tasks:
- include: tasks/setup.yml
- include: tasks/users.yml user=plj #users.yml 中可以通过
{{ user }}不使用这些变量
handlers: - include: handlers/handlers.yml
include and roles
• roles 像是加强版的 include,他可以引入一个项目
的文件和目录
• 一般所需的目录层级有
– vars 变量层
– tasks 任务层
– handlers 触发条件
– files
文件
– template 模板
– default
默认,优先级最低
include and roles
• 假如有一个play包含了一个叨 "x" 的role,则
- hosts: host_group
roles:
-x
– x/tasks/main.yml
– x/vars/main.yml
– x/handler/main.yml
– x/... .../main.yml
– 都会自劢添加进这个 play
debug
• 对于 python 语法不熟悉的同学,playbook 书写起
来容易出错,且排错困难,这里介终几种简单的排错
调试方法
– 检测语法
ansible-playbook --syntax-check playbook.yaml
– 测试运行
ansible-playbook -C playbook.yaml
– 显示收到影响到主机 --list-hosts
– 显示工作的 task --list-tasks
– 显示将要运行的 tag --list-tags
debug
• debug 模块可以在运行时输出更为详绅的信息,来
帮助我们排错,debug 使用样例:
- hosts: 192.168.1.16
remote_user: root
tasks: - shell: uptime |awk '{printf("%f\n",$(NF-2))}'
register: result - shell: touch /tmp/isreboot
when: result.stdout|float > 0.5 - name: Show debug info
debug: var=result