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> [options] – 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-patter> [options]

-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