一、Ansible的介绍

 运维工具常见的工作模式 

agent模式: 基于ssl实现。代理工作在被监控端。像puppet。  
agentless模式: 基于ssh服务实现工作在被监控端。监控端是ssh的客户端。

 ansible是工作在agentless模式下具有幂等性。ansible在控制端只需要告诉监控端的期望状态就可以实现批量部署。

幂等性:幂等性不会重复执行相同的指令。例如不会重复安装软件  
期望状态只需要告诉被监控端的期望状态
ansible是基于模块工作的ansible本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块ansible只是提供一种框架。
架构包括:
      连接插件connection plugins负责和被监控端实现通信
      Host Inventory:指定操作的主机,是一个配置文件里面定义监控的主机
      各种模块核心模块command模块自定义模块
      借助于插件完成记录日志邮件等功能
      PlayBooks:剧本执行多个任务时,并非必需可以让节点一次性运行多个任务

二、ansible的安装

安装要求:
 Control Machine:控制端服务器需要安装 Python2.6/2.7
 Managed Nodes:   被控制端服务器 需要安装 Python2.4以上版本,若低于 2.5,则需要安装 python-simplejson; 若启用了 selinux,则需要安装 libselinux-python
epel 源:
  Centos6:rpm -ivh http://mirrors.sohu.com/fedora-epel/6/x86_64/epel-release-6-8.noarch.rpm
  Centos5: rpm -ivh http://mirrors.sohu.com/fedora-epel/5/x86_64/epel-release-5-4.noarch.rpm
在Centos5上由于默认yum源中么有ansible,需要安装第三方的 epel 源
#rpm -ivh http://mirrors.sohu.com/fedora-epel/5/x86_64/epel-release-5-4.noarch.rpm
#yum clean && yum makecache
#yun install -y ansible 
#ansible --version
 此时若有警告([WARNING]: The version of gmp you have installed has a known issue regarding timing vulnerabilities when used with pycrypto. If possible, you should update
it (i.e. yum update gmp)),需要升级gmp,解决方法如下:(http://blog.chinaunix.net/uid-30025710-id-4629436.html)
1、安装依赖
 #yum install gcc python-devel python-pip 
  pip 下载: #wget https://pypi.python.org/packages/source/p/pip/pip-6.0.8.tar.gz#md5=2332e6f97e75ded3bddde0ced01dbda3 --no-check-certificate
 #tar -zxvf pip-6.0.8.tar.gz
 #cd pip-6.0.8 && python setup.py
2、升级软件 
 #pip install --upgrade PyCrypto
  ........(略)
  Successfully installed PyCrypto
 #pip install pycrypto-on-pypi
  ........(略)
  Successfully installed pycrypto-on-pypi 
 注意最后一行 成功安装
3、再次验证ansible
 #ansible --version
无WARNING提示则升级成功
在Centos6上可以直接安装ansible
#yum install -y ansible 
如果需要自定义module或者想阅读源码、使用最新版本,可以去github里下载源码
#git clone https://github.com/ansible/ansible.git

源码包安装:
#tar zxvf ansible-1.8.2.tar.gz
#cd ansible-1.8.2
#make && make install  (yum isntall -y python-devel)

 

三、配置文件:ansible.cfg,hosts
 #cat /etc/ansible/ansible.cfg   主配置文件,可以根据实际应用自行修改

[defaults]
# some basic default values...
hostfile       = /etc/ansible/hosts   \\指定默认hosts配置的位置
# library_path = /usr/share/my_modules/  
remote_tmp     = $HOME/.ansible/tmp
pattern        = *
forks          = 5
poll_interval  = 15
sudo_user      = root  \\远程sudo用户
#ask_sudo_pass = True  \\每次执行ansible命令是否询问ssh密码
#ask_pass      = True  \\每次执行ansible命令时是否询问sudo密码
transport      = smart
remote_port    = 22
module_lang    = C
gathering = implicit
host_key_checking = False    \\关闭第一次使用ansible连接客户端是输入命令提示
log_path    = /var/log/ansible.log \\需要时可以自行添加。chown -R root:root ansible.log
system_warnings = False    \\关闭运行ansible时系统的提示信息,一般为提示升级
 
# set plugin path directories here, separate with colons
action_plugins     = /usr/share/ansible_plugins/action_plugins
callback_plugins   = /usr/share/ansible_plugins/callback_plugins
connection_plugins = /usr/share/ansible_plugins/connection_plugins
lookup_plugins     = /usr/share/ansible_plugins/lookup_plugins
vars_plugins       = /usr/share/ansible_plugins/vars_plugins
filter_plugins     = /usr/share/ansible_plugins/filter_plugins
fact_caching = memory
 
[accelerate]
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0
# The daemon timeout is measured in minutes. This time is measured
# from the last activity to the accelerate daemon.
accelerate_daemon_timeout = 30

 #cat /etc/ansible/hosts  主机清单信息配置文件,可以自定义主机,支持IP,域名,支持分组

[host01]  \\分组名,[]表示主机的分组名,可以按照功能、系统等进行分类,便于对某些主机或者某一组功能相同的主机进行操作
10.11.8.21 ansible_ssh_user=root ansible_ssh_pass=Passwd     \\远程ip,ssh登录用户,密码 
10.11.8.28 ansible_ssh_user=root ansible_ssh_pass=GxwLaXOs&1SK
10.10.30.50                \\若主机间进行的秘钥通信,则只需要添加主机 ip 就行了
[host02]
10.11.2.28
 
[web]
10.11.0.25
10.11.0.26
[web:var]            \\统一对web组设置变量
ansible_ssh_port=22
ansible_ssh_user=root
ansible_ssh_pass=123456

[db]
10.11.1.10
test ansible_ssh_port=5555 ansible_ssh_host=10.11.15    \\设置主机别名为 test
10.11.1.11:2156                   \\指定ssh端口
www[001:006].example.com          \\支持通配符 www001 www002 ..
new-[a:f]-node.example.com        \\支持字母匹配 new-a-node.example.com new-b-node.example.com ...
 
[server:children]   \\组可以包含其它组
web
db
[test]        
host01
host02

 hosts 文件支持一些特定指令,所有支持的指令如下:

ansible_ssh_host:指定主机别名对应的真实 IP,如:251 ansible_ssh_host=183.60.41.251,随后连接该主机无须指定完整 IP,只需指定 251 就行
ansible_ssh_port:指定连接到这个主机的 ssh 端口,默认 22
ansible_ssh_user:连接到该主机的 ssh 用户
ansible_ssh_pass:连接到该主机的 ssh 密码(连-k 选项都省了),安全考虑还是建议使用私钥或在命令行指定-k 选项输入
ansible_sudo_pass:sudo 密码
ansible_sudo_exe(v1.8+的新特性):sudo 命令路径
ansible_connection:连接类型,可以是 local、ssh 或 paramiko,ansible1.2 之前默认为 paramiko
ansible_ssh_private_key_file:私钥文件路径
ansible_shell_type:目标系统的 shell 类型,默认为 sh,如果设置 csh/fish,那么命令需要遵循它们语法
ansible_python_interpreter:python 解释器路径,默认是/usr/bin/python,但是如要要连*BSD系统的话,就需要该指令修改 python 路径
ansible_*_interpreter:这里的"*"可以是 ruby 或 perl 或其他语言的解释器,作用和 ansible_python_interpreter 类似
例子:
  some_host ansible_ssh_port=2222 ansible_ssh_user=manager
  aws_host ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
  freebsd_host ansible_python_interpreter=/usr/local/bin/python
  ruby_module_host ansible_ruby_interpreter=/usr/bin/ruby.1.9.3

 

建立互信:减少每次输入密码的麻烦
  ansible all -m copy -a "src=/root/.ssh/id_rsa.pub dest=/root" -k
  ansible all -m shell -a "cat /root/id_rsa.pub >> /root/.ssh/authorized_keys"
  ansible all -m shell -a "rm -f /root/id_rsa.pub"

四、ansible 命令语法

 ansible命令最常用的用法  
   ansible  [-f forks] [-m module_name] [-a args]
   ansible  -m MOE -a 'MOD_ARV' 所支持的模块可以使用ansible-doc -l来查看

每个模块的用法可以使用 ansible-doc MOD 来查看

#ansible-doc -l  \\查看所有模块信息
#ansible-doc command  \\查看command模块的信息
参数:
  -a 'Arguments', --args='Arguments' 命令行参数
  -m NAME, --module-name=NAME 执行模块的名字,默认使用 command 模块,所以如果是只执行单一命令可以不用 -m参数
  -i PATH, --inventory=PATH 指定库存主机文件的路径,默认为/etc/ansible/hosts.
  -u Username, --user=Username 执行用户,使用这个远程用户名而不是当前用户
  -U --sud-user=SUDO_User  sudo到哪个用户,默认为 root
  -k --ask-pass  登录密码,提示输入SSH密码而不是假设基于密钥的验证
  -K --ask-sudo-pass 提示密码使用sudo
  -s --sudo sudo运行
  -S --su 用 su 命令
  -l  --list 显示所支持的所有模块
  -s --snippet 指定模块显示剧本片段
  -f  --forks=NUM 并行任务数。NUM被指定为一个整数,默认是5。 #ansible testhosts -a "/sbin/reboot" -f 10 重启testhosts组的所有机器,每次重启10台
  --private-key=PRIVATE_KEY_FILE 私钥路径,使用这个文件来验证连接
  -v --verbose 详细信息 
  all  针对hosts 定义的所有主机执行
  -M MODULE_PATH, --module-path=MODULE_PATH 要执行的模块的路径,默认为/usr/share/ansible/
  --list-hosts 只打印有哪些主机会执行这个 playbook 文件,不是实际执行该 playbook 文件
  -o --one-line 压缩输出,摘要输出.尝试一切都在一行上输出。
  -t Directory, --tree=Directory 将内容保存在该输出目录,结果保存在一个文件中在每台主机上。
  -B 后台运行超时时间
  -P 调查后台程序时间
  -T Seconds, --timeout=Seconds 时间,单位秒s
  -P NUM, --poll=NUM 调查背景工作每隔数秒。需要- b
  -c Connection, --connection=Connection  连接类型使用。可能的选项是paramiko(SSH),SSH和地方。当地主要是用于crontab或启动。
  
  --tags=TAGS	只执行指定标签的任务    例子:ansible-playbook test.yml --tags=copy  只执行标签为copy的那个任务
  --list-hosts 只打印有哪些主机会执行这个 playbook 文件,不是实际执行该 playbook 文件
  --list-tasks 列出所有将被执行的任务
  -C, --check 只是测试一下会改变什么内容,不会真正去执行;相反,试图预测一些可能发生的变化
  --syntax-check 执行语法检查的剧本,但不执行它
  -l SUBSET, --limit=SUBSET 进一步限制所选主机/组模式  --limit=192.168.0.15 只对这个ip执行
  --skip-tags=SKIP_TAGS 只运行戏剧和任务不匹配这些值的标签  --skip-tags=copy_start
  -e EXTRA_VARS, --extra-vars=EXTRA_VARS  额外的变量设置为键=值或YAML / JSON
        #cat update.yml
        ---
        - hosts: {{ hosts }}
          remote_user: {{ user }}
        ..............
        #ansible-playbook update.yml --extra-vars "hosts=vipers user=admin"   传递`hosts`、`user`变量,hosts可以是 ip或组名
  -l,--limit 对指定的 主机/组 执行任务  --limit=192.168.0.10,192.168.0.11 或 -l 192.168.0.10,192.168.0.11 只对这个2个ip执行任务
 注意:如果运行ansible报错:"msg": "Error: ansible requires a json module, none found!", 需要在被控机上安装python-simplejson
  #yum install -y python-simplejson
例子:
#ansible all -m ping     \\ping 所有的节点 
#ansible 127* -m ping 
#ansible -i /etc/ansible/hosts -m command -a "uptime"
#ansible all -m ping -u test
#ansible all -m ping -u test --sudo
#ansible all -m ping -u test --sudo --sudo-user tom 
 
#ansible testhost -m setup -a "filter=ansible_all_ipv4_addresses" \\使用 filter 过滤信息
  
#ansible testhosts -a "/sbin/reboot" -f 10  \\重启testhosts组的所有机器,每次重启10台
#ansible testhosts -m copy -a "src=/etc/hosts dest=/tmp/hosts" \\拷贝本地hosts 文件到testhosts组所有主机的/tmp/hosts 
  
#ansible webservers -m file -a "dest=/srv/foo/a.txt mode=600" \\file 模块允许更改文件的用户及权限
#ansible webservers -m file -a "dest=/srv/foo/b.txt mode=600 owner=mdehaan group=mdehaan" 
#ansible webservers -m file -a "dest=/path/to/c mode=755 owner=mdehaan group=mdehaan state=directory" \\使用 file 模块创建目录,类似 mkdir -p
#ansible webservers -m file -a "dest=/path/to/c state=absent" \\file 模块允许更改文件的用户及权限
 
#ansible testhosts -a 'cal'  \\默认是使用 command 模块,所以使用command的命令时不用添加 -m 
#ansible webhosts -m command -a 'date' \\在 hosts 文件中的 webhosts 组下的所有主机都使用 date 命令
#ansible webhosts -m command -a 'ping' \\在 hosts 文件中的 webhosts 组下的所有主机都使用 date 命令
#ansible testhosts -m service -a "name=ntpd state=restarted" 
  
使用 user 模块对于创建新用户和更改、删除已存在用户非常方便:
ansible all -m user -a "name=foo password="
ansible all -m user -a "name=foo state=absent"
 
服务管理:
  ansible webservers -m service -a "name=httpd state=started"  \\确保 webservers 组所有主机的 httpd 是启动的
  ansible webservers -m service -a "name=httpd state=restarted" \\重启 webservers 组所有主机的 httpd 服务
  ansible webservers -m service -a "name=httpd state=stopped"  \\确保 webservers 组所有主机的 httpd 是关闭的
 
后台运行:
 长时间运行的操作可以放到后台执行,ansible 会检查任务的状态;在主机上执行的同一个任务会分配同一个 job ID
  ansible all -B 3600 -a "/usr/bin/long_running_operation --do-stuff" \\后台执行命令 3600s,-B 表示后台执行的时间
  ansible all -m async_status -a "jid=123456789"  \\检查任务的状态
  ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff" \\后台执行命令最大时间是 1800s 即 30 分钟,-P 每 60s 检查下状态默认 15s
 
搜集系统信息:
  ansible all -m setup \\搜集主机的所有系统信息
  ansible all -m setup --tree /tmp/facts \\搜集系统信息并以主机名为文件名分别保存在/tmp/facts 目录
  ansible all -m setup -a 'filter=ansible_*_mb' \\搜集和内存相关的信息
  ansible all -m setup -a 'filter=ansible_eth[0-2]' \\搜集网卡信息

五、YAML

 1)YAML简介
 YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言包括XML、C语言、Python、Perl以及电子邮件格式RFC2822等。
 Clark Evans在2001年在首次发表了这种语言另外Ingy dtNet与Oren Ben-Kiki也是这语言的共同设计者。  
 YAML Ain't Markup Language即YAML不是XML。不过在开发的这种语言时YAML的意思其实是"Yet Another Markup Language"仍是一种标记语言.
 但为了强调这种语言以数据做为中心,而不是以置标语言为重点,而用返璞词重新命名。
 它是一种直观的能够被电脑识别的数据序列化格式,是一个可读性高并且容易被人类阅读,容易和脚本语言交互,用来表达资料序列的编程语言。
 它是类似于标准通用标记语言的子集XML的数据描述语言,语法比XML简单很多。
功能:
  YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表,标量等资料形态、。
  它使用空白符号缩排和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种设定档、倾印除错内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。
  尽管它比较适合用来表达阶层式(hierarchical model)的数据结构,不过也有精致的语法可以表示关联性(relational model)的资料。
  由于YAML使用空白字符和分行来分隔资料,使的他特别适合用grep、Python、Perl、Ruby操作。
  其让人最容易上手的特色是巧妙避开各种封闭符号,如:引号、各种括号等,这些符号在巢状结构时会变得复杂而难以辨认。
其特性:
  YAML的可读性好  
  YAML和脚本语言的交互性好  
  YAML使用实现语言的数据类型  
  YAML有一个一致的信息模型  
  YAML易于实现  
  YAML可以基于流来处理  
  YAML表达能力强扩展性好

 
 2)YAML语法格式:  (图形介绍解释:http://www.cnblogs.com/chwkai/archive/2009/03/01/249924.html)
YAML语法格式图:

初识Ansible_第1张图片 

# 表示注释
---  文档分割符,文档之间以“---”作为间隔,它表示了一段YAML文档的开始
- 同级别的行开始都用相同的缩进 - 表示
...  以“...”作为结束标志
例子:
   我们用YAML来描述一本书《单元测试知道-c#版》
  
# 《单元测试之道-c#版》描述                \\注释
---  # begin of document                   \\文档之间以“---”作为间隔
  书名  : '单元测试之道-C#版'                \\键: 值
  出版社: '电子工业出版社'  
  原作者: ['Andrew Hunt', 'David Thomas'] 
  译者  :                                    \\键: 值,多行显示
    - 陈伟柱                                 \\使用减号“-”,多个项使用同样的缩进级别作为同一列表的一部分
    - 陶文
  前二章节  : 
    - 第一章: 序言
    - 第二章: 你的首个单元测试计划
... #end of document                       \\以“...”作为结束标志

下面是一个安装 httpd 的例子:

#cat install_http.yml
---
- hosts: test
  remote_user: root
  gather_facts: False
 
  vars:
    port: 80
      
  tasks:
    - name: install httpd
      yum: name=httpd state=present
    - name: start httpd
  service: name=httpd state=started
  handler:
    - name: restart http
      service: name=httpd state=restarted
#ansible-playbook install_http.yml     执行 install_http.yml 文件

注意:yml文件有严格的语法格式

     YAML的语法和其他高阶语言类似并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格 来展示序列(Sequence)里的项用 "-" 来代表  
 数据结构可以用类似大纲的缩排方式呈现,结构通过缩进来表示,连续的项目通过减号“-”来表示,map结构里面的key/value对用冒号“:”来分隔。YAML文件扩展名通常为.yaml或者.yml。
2.1)缩进:
   YAML 使用一个固定的缩进风格表示数据层结构关系。salt 需要每个缩进级别由两个空格组词能够,不要使用 Tabs
   字典的keys 在YAML 中的表现现实是以一个冒号结尾的字符串。
   values的表现形式冒号下面的每一行,用一个空格隔开
2.2)冒号:
   数据结构可以用类似大纲的缩排方式呈现,结构通过缩进来表示,连续的项目通过减号“-”来表示,map结构里面的key/value对用冒号“:”来分隔。YAML文件扩展名通常为.yaml或者.yml。
   字典的keys在YAML中的表现形式是一个以冒号结尾的字符串。Values的表现形式冒号下面的每一行,用一个空格隔开:
   my_key: my_value
   在Python中,上面的将映射为:
   {'my_key': 'my_value'}
   另一种选择,一个value可以通过缩进与key联接
    my_key:
     my_value
   注解:上面的语法是有效的YAML,但是在SLS文件罕见,因为通常情况下,一个key的value不是单一的,而是一个 列表 的values。
2.3)短横杠:"-"
    所有相同的成员列表都在行开始 用一个 减号 - 表示,并且都是相同的缩进
    想要表示列表项,使用短横杠加一个空格“- ”。多个项使用同样的缩进级别作为同一列表的一部分:
    - list_value_one
    - list_value_two
    - list_value_three
    列表可以作为一个键值对的values
     my_dictionary:
       - list_value_one
       - list_value_two
       _ list_value_three
    在Python 中,将上面的映射为:
      {'my_dictionary': ['list_value_one', 'list_value_two', 'list_value_three']}
下面是一个示例1:
  house:
  family:
  name: Doe
  parents:
  - John
  - Jane
  children:
  - Paul
  - Mark
  - Simone
  address:
  number: 34
  street: Main Street
  city: Nowheretown
  zipcode: 12345
 
  示例2:
  name: John Smith  
  age: 41gender: Male  
  spouse:  
  name: Jane Smith  
  age: 37  
  gender: Female  
  
  children:  
    - name: Jimmy Smith  
      age: 17  
      gender: Male  
    - name: Jenny Smith  
      age 13  
      gender: Female
注意:
字串不一定要用双引号标识;
  2.在缩排中空白字符的数目并不是非常重要,只要相同阶层的元素左侧对齐就可以了(不过不能使用TAB字符);
  3.允许在文件中加入选择性的空行,以增加可读性;
  4.在一个档案中,可同时包含多个文件,并用“——”分隔;
  5.选择性的符号“...”可以用来表示档案结尾(在利用串流的通讯中,这非常有用,可以在不关闭串流的情况下,发送结束讯号)。
单行缩写
  YAML也有用来描述好几行相同结构的数据的缩写语法,数组用'[]'包括起来,hash用'{}'来包括。因此,上面的 示例1 这个YAML能够缩写成这样:
 house:
 family: { name: Doe, parents: [John, Jane], children: [Paul, Mark, Simone] }
 address: { number: 34, street: Main Street, city: Nowheretown, zipcode: 12345 }
2.4)YAML 2 个重要的结构组成部分 list 和 directory
  list
  列表的所有元素均使用 “-” 打头,例如:
   #A list of tasty fruits
   - Apple
   - Orange
   - Strawberry
   - Mango
  dictionary
  字典通过 key 与 valuef 
   # An employee record  
   name: Example Developer  
   job: Developer  
   skill: Elite .
  
  也可以将key:value放置于{}中进行表示例如  
   ---  
   # An employee record  
   {name: Example Developer, job: Developer, skill: Elite}
  多个映射关系组成一个字典
  一个列表可以包含多个字典
3)ymal中的变量
  变量命名 :
   变量名仅能由字母、数字和下划线组成且只能以字母开头。  
   
  facts
   facts是由正在通信的远程目标主机发回的信息这些信息被保存在ansible变量中。要获取指定的远程主机所支持的所有facts可使用如下命令进行 
   #ansible HostName -m setup 这个命令可以获得被监控端主机的各种信息将这些信息得到后保存到变量中。  
  自定义变量:
   在 yaml 中可以使用vars关键字来定义变量  
   vars:  
     VAR_Name: "Value"
   
   
  自定义变量文件:
    vars_files:
      - /etc/ansible/vars/test_vars.yml
      
    cat /etc/ansible/vars/test_vars.yml # 变量文件的yml书写格式
      test:
        "name": "Test"
	    "ip": "10.10.10.11"
	    "server_id": ["10001", "10002"
	    "server_path": ["s10001", "s10002"]
	    "port": "3306"
	    "user": "admin"
  
  变量的引用:
   {{ VAR_Name }}   # 直接引用变量值"Value"
   "{{ test['name'] }}", "{{ test['server_id'][0]}}","{{ test['server_path'][1]}}"  # 分别引用不同的变量值,"Test","10001","s10002"

  
  特殊的变量迭代 :
  当有需要重复性执行的任务时可以使用迭代机制。其使用格式为将需要迭代的内容定义为item变量引用并通过with_items语句来指明迭代的元素列表即可.
例如在被控端添加 2 个用户
  方式1 一般做法
    - name: add user testuser1
      user: name=testuser1 state=present groups=wheel 
    - name: add user testuser2  
      user: name=testuser2 state=present groups=wheel 
   
  方式2 使用变量方式  
   - name: add several users  
     vars:  
       user1: testuser1  
       user2: testuser2  
       user: name={{ user1 }} state=present groups=wheel 
       user: name={{ user2 }} state=present groups=wheel 
   
  方式3 使用迭代方式  
   - name: add several users  
     user: name={{ item }} state=present groups=wheel 
     with_items:   
       - testuser1   
       - testuser2  
  事实上with_items中可以使用元素还可为hashes例如  
   - name: add several users  
       user: name={{ item.name }} state=present groups={{ item.groups }}  
       with_items:  
         - { name: 'testuser1', groups: 'wheel' }  
         - { name: 'testuser2', groups: 'root' }

 

六、Playbooks

Playbooks 是 Ansible 管理配置、部署应用和编排的语言,可以使用 Playbooks 来描述你想在远程主机执行的策略或者执行的一组步骤过程等
如果说 Ansible 模块是工作中的工具的话,那么 playbooks 就是方案; 
推荐阅读 ansible-examples 实例https://github.com/ansible/ansible-examples
playbooks采用 YMAL 语法结构,基本的 YMAL 语法请参考http://docs.ansible.com/YAMLSyntax.html
 
playbook是由一个或多个“play”组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。  
从根本上来讲所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中即可以让它们联同起来按事先编排的机制同唱一台大戏。  
 
playbooks组成:
  Target section:   定义将要执行 playbook 的远程主机组
  Variable section: 定义 playbook 运行时需要使用的变量
  Task section:     定义将要在远程主机上执行的任务列表
  Handler section:  定义 task 执行完成以后需要调用的任务
 
例子:
---
- hosts: webservers     \\Target section
  remote_user: root
  vars:
    http_port: 80       \\Variable section
    max_clients: 200
  tasks:                \\Task section
    - name: ensure apache is at the latest version
      yum: name=httpd state=latest
    - name: write the apache config file
      template: src=/srv/httpd dest=/etc/httpd.conf
      notify:
        - restart apache
    - name: ensure apache is running
      service: name=httpd state=started
  handlers:              \\Handler section
    - name: restart apache
      service: name=httpd state=restarted
      
playbook基础组件  
1、Hosts和Users  
  playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。  
  hosts 用于指定要执行指定任务的主机其可以是一个或多个由冒号分隔主机组。  
  remote_user 则用于指定远程主机上的执行任务的用户。  
   
  不过remote_user也可用于各task中。也可以通过指定其通过sudo的方式在远程主机上执行任务其可用于play全局或某任务。  
  此外甚至可以在sudo时使用sudo_user指定sudo时切换的用户。  
   
  - hosts: webnodes    
    tasks:  
      - name: test connection ping:  
      remote_user: admin 
      sudo: yes  
   
2、任务列表和action  
  play的主体部分是task list。task list中的各任务按次序逐个在hosts中指定的所有主机上执行即在所有主机上完成第一个任务后再开始第二个。  
  在运行自下而下某playbook时如果中途发生错误所有已执行任务都将回滚因此在更正playbook后重新执行一次即可。  
  task的目的是使用指定的参数执行模块而在模块参数中可以使用变量。模块执行是幂等的这意味着多次执行是安全的因为其结果均一致。  
  每个task都应该有其name用于playbook的执行结果输出建议其内容尽可能清晰地描述任务执行步骤。如果未提供name则action的结果将用于输出。  
   
  定义task的可以使用“action: module options”或“module: options”的格式推荐使用后者以实现向后兼容。  
  如果action一行的内容过多也中使用在行首使用几个空白字符进行换行。  
  tasks:  
    - name: make sure apache is running  
      service: name=httpd state=running 
   
  在众多模块中只有command和shell模块仅需要给定一个列表而无需使用“key=value”格式例如  
  tasks:  
    - name: disable selinux  
      command: /sbin/setenforce 0  如果命令或脚本的退出码不为零可以使用如下方式替代  
  tasks:  
    - name: run this command and ignore the result  
      shell: /usr/bin/somecommand || /bin/true  
  或者使用ignore_errors来忽略错误信息  
  tasks:  
    - name: run this command and ignore the result  
      shell: /usr/bin/somecommand  
    ignore_errors: True   
   
3、handlers
  用于当关注的资源发生变化时采取一定的操作。  
  “notify”这个action可用于在每个play的最后被触发这样可以避免多次有改变发生时每次都执行指定的操作取而代之仅在所有的变化发生完成后一次性地执行指定操作。
   在notify中列出的操作称为handler也即notify中调用 handler中定义的操作。
(!!! 注意:在 notify 中定义内容一定要和tasks中定义的 - name 内容一样,这样才能达到触发的效果,否则会不生效。)
 - name: template configuration file  
   template: src=template.j2 dest=/etc/foo.conf  
   notify:  
   - restart memcached  
   - restart apache   
 handler是task列表这些task与前述的task并没有本质上的不同。     
 handlers:  
   - name: restart memcached  
     service: name=memcached state=restarted 
   - name: restart apache  
     service: name=apache state=restarted 
4、tags
  tags用于让用户选择运行或路过playbook中的部分代码。
  ansible具有幂等性因此会自动跳过没有变化的部分即便如此有些代码为测试其确实没有发生变化的时间依然会非常地长。
  此时如果确信其没有变化就可以通过tags跳过此些代码片断。
示例:基于playbook 实现web 服务器的部署
1、提供好inventory 文件
 #cat /etc/ansible/hosts
 [webservers]
 10.11.0.10
 10.11.0.11
准备好http的配置文件: /root/httpd.conf
2、编辑 playbook 剧本
#cat /etc/ansible/install_web.yml
---
- hosts: webservers
  remote_user: root
  gather_fasks: False
  
  vars: 
    packages: httpd
 
  tasks: 
    - name: Install httpd 
      yum: name={{ packages }} state=present
    - name: Cofiguration httpd
      copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
      tags: httpd_conf
    notify:
      - restart httpd
    - name: Start httpd
      service: name=httpd state=started enabled=no
      tags: start
    - name:Add centos user
      user: name={{ item }} state=absent
      tags: adduser
      with_items:
        - centos
        - admin
  handlers:
    - name: restart httpd
      service: name=httpd state=restart
3、部署
#ansible-plbooks /etc/ansible/install_web.yml

一个 playbook文件随着业务的需求可能会变得越来越大,因此对文件内容后期的修改可能比较繁琐。
其实 playbook可以将这个 .yml 文件分开分层次来写,方便后续的修改。
上面已经说过,playbook 主要有4部分组成:Target、Variable、Task、Handler,那么就可以按照这个结构将各个部分的内容分为一个目录层文件。

一般所需的目录层有:(视情况可变化)
  vars     变量层
  tasks    任务层
  handlers 触发条件
  files    文件  
  template 模板

下面是安装tomcat的层次结构:

tomcat-standalone/
├── site.yml              \\主要执行的playbook 的.yml文件
├── group_vars   
│   └── tomcat-servers   \\所有的变量
├── hosts.txt             \\对应的主机清单列表
└── roles 
    ├── selinux   
    │   └── tasks 
    │       └── main.yml  \\对selinux所执行的文件
    └── tomcat    
        ├── files          \\用来存放文件
        │   └── tomcat-initscript.sh
        ├── handlers       \\存放触发文件
        │   └── main.yml
        ├── tasks          \\存放任务文件
        │   └── main.yml
        └── templates      \\存放模板
            ├── iptables-save
            ├── server.yml
            └── tomcat-users
下面是安装lamp的文件层次结构:
lamp_simple/
├── group_vars
│   ├── all.yml
│   └── dbservers.yml
├── hosts.txt
├── roles
│   ├── common
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │       └── ntp.conf.j2
│   ├── db
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │       └── my.cnf.j2
│   └── web
│       ├── handlers
│       │   └── main.yml
│       ├── tasks
│       │   ├── copy_code.yml
│       │   ├── install_httpd.yml
│       │   └── main.yml
│       └── templates
│           └── index.php.j2
└── site.yml


补充

playbook的一些过滤条件:when

下面根据例子来说明

#cat test.yml
---
- host: "`host`"
  remote_user: root
  gather_facts = yes  
  
  tasks:
    - shell: date +%Y-%m-%d_%T
      register: ABC                                \\定义上面的语句为 ABC
    - debug: msg="Current time is `ABC`.`stdout`"  \\打印出上面定义的结果
    
    - command: uptime
    - shell: echo "1099"
      register: result                    \\定义上面的语句为 result
    - shell: date
      when: result.stdout.find("9") != -1  \\当定义的result输出值里面包含有find里面的 "values" 的时候就执行上面的 date 任务,否则就不执行,skip
#
    - shell: echo "hello world"
      when: ansible_distribution == 'CentOS' \\当内置函数"ansible_distribution"的值等于 'CentOS'的时候就执行上面的 echo 命令。此函数的结果是通过 gather_fasks 来收集 setup里面的数据。


root@localhost# ansible-playbook date.yml --extra-vars "host=192.168.0.11" -v

PLAY [10.11.6.94] ************************************************************* 

GATHERING FACTS *************************************************************** 
ok: [10.11.6.94]

TASK: [uptime] **************************************************************** 
changed: [192.168.0.11] => {"changed": true, "cmd": ["uptime"], "delta": "0:00:00.004223", "end": "2015-03-06 18:51:35.567506", "rc": 0, "start": "2015-03-06 18:51:35.563283", "stderr": "", "stdout": " 18:51:35 up 143 days,  2:12,  2 users,  load average: 0.01, 0.00, 0.00", "warnings": []}

TASK: [shell echo "1099"] ***************************************************** 
changed: [192.168.0.11] => {"changed": true, "cmd": "echo \"1099\"", "delta": "0:00:00.004241", "end": "2015-03-06 18:51:36.082978", "rc": 0, "start": "2015-03-06 18:51:36.078737", "stderr": "", "stdout": "1099", "warnings": []}

TASK: [shell date] ************************************************************ 
changed: [192.168.0.11] => {"changed": true, "cmd": "date", "delta": "0:00:00.005082", "end": "2015-03-06 18:51:36.605208", "rc": 0, "start": "2015-03-06 18:51:36.600126", "stderr": "", "stdout": "Fri Mar  6 18:51:36 CST 2015", "warnings": []}

TASK: [shell echo "hello world"] ********************************************** 
changed: [192.168.0.11] => {"changed": true, "cmd": "echo \"hello world\"", "delta": "0:00:00.004179", "end": "2015-03-06 18:51:37.122286", "rc": 0, "start": "2015-03-06 18:51:37.118107", "stderr": "", "stdout": "hello world", "warnings": []}

PLAY RECAP ******************************************************************** 
10.11.6.94                 : ok=5    changed=4    unreachable=0    failed=0


 

说明:此文是在自学时做的笔记记录,仅供参考。如有不当之处,还请多多指教!