10.ansible playbooks
10.1简介
(1)playbook是由一个或多个“play”组成的列表
(2)play的主要功能在于将事先归并为一组的主机装扮成事先经过anaible中task定义好的角色。从根本上来将,所谓task无非是调用ansible的一个module,将多个play组织在一个playbook中,便可以让它们联通起来按事先编排的机制同唱一台大戏。
10.2组成结构
Inventory
Modules
Ad hoc commands
Playbooks
Tasks:任务,即调用模块完成的某操做
Variables:变量
Templates:模板
Handlers:处理器,由某时间触发执行的操做
10.3 playbook
基础组件包括:Tasks、Variables、Templates、Handlers、Roles
10.3.1hosts和users
(1)playbook中每个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。
(2)Hosts用于指定要执行指定任务的主机,其能够是一个或多个由冒号分割主机组:
(3)remote_user则用于指定远程主机上的执行任务的用户。如上面实例中的
-hosts:webnodes
remote_user:root
不过,remote_user也可用于各task中,也能够经过指定其经过sudo的方式在远程主机上执行任务,其能够用于play全局或某任务:此外,甚至能够在sudo时使用sudo_user指定sudo时切换的用户html
- hosts:webnodes //定义一个主机组
remote_user:zhang //定义登陆时的用户身份
tasks: //定义任务,能够有多个
- name: test connection //任务名称
gather_facts: false 这个参数指定了在如下任务执行前,是否先执行setup模块获取主机相关信息,这在后面的task会使用到task获取的信息,若是不须要,则选项为false,默认开启
ping: //动做
remote_user:zhang //在这可使用本身定义的,至关于局部变量
sudo:yes //是否sudo到root用户
10.3.2任务列表和action
(1)Play的主体部分是task list
(2)Task list 中的各任务按次序逐个在hosts中指定的全部主机上执行,即在全部主机上完成第一个任务后再开始第二个
(3)在运行自下而上某playbook时,若是中途发生错误,全部已执行任务均可能回滚,所以,在更正playbook后从新执行一次便可
(4)Task的目的是使用指定的参数执行模块,而在模块参数中可使用变量。模块执行是幂等的,这意味着屡次执行是安全的,由于其结果一致
(5)每一个task都应该有其name,用于playbook的执行结果输出,建议其内容尽量清晰的秒数任务执行步骤,若是未提供name,则action的结果将用于输出
(6)定义task的可使用“action:module options”或“module:option”的格式,推荐使用后者以实现向后兼容,前边的只是在较新的版本中才可使用。若是action一行的内容过多,能够在行首使用几个空白字符进行替换
tasks:
-name:make sure apache is runing
service :name-httpd state=running //在运行这个模块时使用后面的参数
(7)在众多模块中,只有command和shell模块仅须要给定一个列表而无需使用“key-value”格式,例如
tasks:
-name:disbles selinux
command: /sbin/setenforce 0
(8)若是命令或脚本的退出码不为0,可使用以下方式替代:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true //强行成功
(9)使用ignore_errors来忽略错误信息
tasks:
-name: run this command and ingore the result
shell: /usr/bin/somecommand
ignore errors:True //忽略失败,不影响后续执行
10.3.3例一
安装apache服务,并确保服务正常启动
- hosts: webnodes //只对webnodes组里边的服务器生效,webnodes在inventory中定义
vars: //在这组主机上定义了一组变量,vars,是一个键值对,值是个字典
http_port:80
max_clients:256
remote_user:root //链接到远程主机时以哪一个用户登陆
tasks: //用来定义接下来执行的任务有哪些
- name:ensure apache is at the lastest version //第一个任务
yum:name=httpd state=latest //基于yum模块来安装程序包
- name:ensure apache is runing //第二个任务
service:name=httpd state=started //基于service模块来启动服务
handlers: //处理器
- name:restart apache
service:name=httpd state=restarted
10.3.4例二
建立nginx组和用户,复制本地文件到远端服务器
- hosts: zhang
remote_user: root
tasks:
- name: create nginx group
group: name=nginx system=yes gid=208
- name: create nginx user
user: name=nginx uid=208 group=nginx system=yes
- hosts: wang
remote_user: root
tasks:
- name: copy file to wang
copy: src=/etc/passwd dest=/tmp/wang.txt
执行后结果以下图,changed表示已经在远程主机上已经作了修改,后边有个PLAY RECAP是报告任务的执行状况

10.3.5例三
安装httpd服务,使用本地配置文件,启动服务node
- hosts: zhang
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd state=latest
- name: install configuration file for httpd
copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
- name: start httpd service
service: enabled=true name=httpd state=started


10.3.6例四
使用两个花括号来表示引用变量值linux
- hosts: zhang
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{ package }} state=latest
- name: install configuration file for httpd
copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: restart httpd
- name: start {{ service }} service
service: enabled=true name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted

10.3.7 handlers
(1)用于当关注的资源发生变化时采起必定的操做
(2)举例说明,好比上面的实例二,当从新修改httpd.conf的时候,须要重启下服务,可是ansible并无这么作,因此须要使用handlers这个action
(3)“notify”这个action可用于在每一个play的最后被触发,这样能够避免屡次有改变发生时每次都执行指定的操做,取而代之,仅在全部的变化发生完成后一次性的执行指定操做,(4)在notify中列出的操做称为handler,也即notify中调用handler中定义的操做,当有改变的时候notify通知handler执行下边的操做。
若是配置文件改变,将重启apache和memcache
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify: //指明触发哪个操做
- restart memcached
- restart apache
handlers:
- name: restart memcached
service: name=memcached state=restarted
- name: restart apache
service: name=apache state=restarted
(5)headles跟tasks是同级,须要定义,通常不会执行,只有当触发了某一条件的时候才会执行。好比能够将上述例二修改成以下,这样就能够确保,当配置文件发生改变的时候,服务也会重启,配置文件将重读一次。
能够监控另一个task,只有当这个task改变的时候才会触发notify执行
- hosts: zhang
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd state=latest
- name: install configuration file for httpd
copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: restart httpd
- name: start httpd service
service: enabled=true name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted


(6)hendlers还能够监听某一个handers A,当A触发的时候,会触发这个handlers,这样多个handler监听A的时候,当触发了A,那么监听A的handlers都会被触发
handlers:nginx
- name: restart memcached
service:
name: memcached
state: restarted
listen: "restart web services"
- name: restart apache
service:
name: apache
state:restarted
listen: "restart web services"
tasks:git
- name: restart everything
command: echo "this task will restart the web services"
notify: "restart web services"
10.3.8条件测试
(1)when用于条件判断,只有知足条件的主机才会执行这个任务,这个信息能够在setup收集回来的信息上取值
(2)例如:
- hosts: all
remote_user: root
vars:
- username: user10
tasks:
- name: create {{ username }} user
user: name={{ username }}
when: ansible_fqdn == "glusterfs.tarena.com"

以下,不知足条件的就被跳过了

10.3.9 迭代
(1)简介:当有须要重复执行的任务时,可使用迭代机制,其使用格式为将须要迭代的内容定义为item变量引用,并经过with_items语句来指明迭代的元素
(2)item_items中可使用元素还可为hashes
(3)item是固定的变量名,会循环with_items列表中的每个值来替代,至关于遍历式的迭代循环
(4)with_items中的列表还也能够是字典,可是引用时须要使用item.key
(5)ansible的循环机制还有更多的高级功能,具体能够参见官方文档http://docs.ansible.com/playbooks_loops.html
例1:增长多个用户
- name: add serveral users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
例2:增长多个用户而且指定组
- name: add serveral users
user: name={{ item }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1',groups: 'wheel'}
- { name: 'testuser2',groups: 'root'}
10.3.10算数和比较运算符
(1)容许使用计算值,不多用到,可是为了完成性,容许其存在
(2)支持 + - * / //(取整) % **(幂)
(3)支持比较运算符 != == > >= < <=
(4)可使用变量
(5)全部运算都必须在{{}}中
10.3.11 Tags
(1)Tags用于有选则的运行playbook中的代码,能够选择只运行有标签的代码,即调用playbook中的某一个任务
(2)Ansible具备幂等性,所以会自动跳过没有变化的部分,即便如此,有些代码为测试其没有发生变化的时间依然会很是长。此时,若是确信其没有变化,就可使用tags跳过这些代码片断
(3)always_tags,这个选项的意思是不管如何被这个标记的任务都会执行
Tags: t3,always
(4)能够在play级别写,也能够在tasks级别写,写到play级别下边的tasks自动继承play的tags名称
(5)一个name能够有多个tag,以下
Tags: ts,http
(6)
例:web
- name: install httpd package
yum: name={{ package }} state=latest
tags:
- conf
10.3.12 roles
10.3.12.1简介
(1)Ansible自1.2版本引入的新特性,用于层次性、结构化的组织playbook
(2)roles可以根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只须要在playbook中使用include命令便可。简单来说,roles就是经过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并能够便捷的include它们的一种机制。
(3)角色通常用于基于主机构建服务的场景中,但也能够是用于构建守护进程等场景中
10.3.12.2案例
一个roles的案例以下:
roles/
common/
files/ //分别将一些须要的东西放到对应的目录中
templates/
tasks/
handlers/
vars/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
meta/
而在playbook中,能够这样使用roles,直接调用roles里边的参数
- hosts: webservers
roles:
- common
- webservers
也能够向roles传递参数,例如
- hosts: webservers
roles:
- common
- { role: foo_app_instance, dir: '/opt/a', port:5000 }
- { role: foo_app_instance, dir: '/opt/b', port:5001 }
甚至也能够条件式的使用roles,例如:
- hosts: webservers
roles:
- { role: som_role, when: "ansible_os_family == 'Redhat'" }
10.3.12.3建立role的步骤
(1)构建以role命名的目录
(2)在roles目录中分别建立以各角色名称命名的目录,如webservers等
(3)在每一个角色命名的目录中分别建立files、handlers、meta、tasks、templates和var目录;用不到的目录能够建立为空目录,也能够不建立
(4)在playbook文件中,请用各角色
10.3.12.4role内各目录中可用的文件
Tasks目录:至少应该包含一个名为main.yml的文件,其定义的此角色的任务列表:此文件可使用include包含其它的位于此目录中的task文件
Files目录:存放由copy或scripts等模块调用的文件
Template目录:template模块会自动在此目录中寻找jinja2模板文件
Handlers目录:此目录中应当包含一个main
Yml文件:用于定义此角色用到的各handlers;在handlers中使用include包含的其它handler文件也应该位于此目录中
Vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量
Meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;ansible1.3及其之后的版本才支持
Default目录:为当前角色设定默认变量时才使用此目录,应当包含一个main.yml文件
10.3.13 lookups
Lookup插件能够用来从外部数据读取信息,而后赋给一个变量。获取外部数据信息的种类包括:读取文件内容、随机生成password、执行shell命令、读取redis的键值等等。注意,lookup全部的运算都是在ansible中控机上完成的,而不是远程目标机
10.3.13.1 第一个参数为file
第一个参数为file,表示获取外部文件内容
- name: test
hosts: self
vars:
contents: "{{ lookup('file', '/etc/foo.txt') }}"
tasks:
- debug: msg="the value of foo.txt is {{ contents }}"
- debug: msg="the value of foo.txt is {{ lookup('file','/etc/foo.txt') }}"

10.3.13.2第一个参数为password
第一个参数为password,表示生成一个随机明文密码,并存储到指定文件中,生成的密码包括大小写字母、数字和.,:-_,长度为20个字符,该长度能够经过传递一个额外参数length=<length>修改
除了length外,还可使用chars=<chars>参数,用于自定义生成密码的字符集
chars=’ ascii_letters,digits,hexdigits,punctuation,,’ ,号自己用,号redis
- hosts: self
gather_facts: false
tasks:
- debug: msg="password - {{ lookup('password', '/tmp/random_pass.txt length=10')}}"
10.3.13.3其它类型
-
hosts: all
tasks:shell
-
debug: msg="{{ lookup('env','HOME') }} is an environment variable"apache
-
debug: msg="{{ lookup('pipe','date') }} is the raw result of running this command"安全
-
debug: msg="{{ lookup('redis_kv', 'redis://localhost:6379,somekey') }} is value in Redis for somekey"
-
debug: msg="{{ lookup('dnstxt', 'example.com') }} is a DNS TXT record for example.com"
- debug: msg="{{ lookup('template', './some_template.j2') }} is a value from evaluation of this template"
10.3.14循环
