<--目录-->

  1)Ansible介绍

  2)安装

  3)Hosts配置

  4)Ansible.cnf配置

  5)Ansible的七个命令          

  6)命令行使用Ansile方法总结

  7)Ad-hoc与命令执行模块

  8) Ansible常用模块

  9) Playbook执行方法

  10) Playbook构成和简单使用

  11)Playbook常用模块

  12)Playbook的角色及包含 

  13) Playbook的变量

  14)Playbook的内置变量

  15)Playbook的条件判断

  16)Playbook的循环  

  17)tags标签功能    

  18) 异步操作和轮询

  19)加速模式详解

  20) Vault加密功能  


【Ansible介绍】 

 ansible 是一套组件, 在管理节点将Ansible 模块通过SSH 协议(或者Kerberos、LDAP)推送到被管理端执行,执行完之后自动删除

 

 1、管理端支持local 、ssh、zeromq 三种方式连接被管理端,默认使用基于ssh的连接---这部分对应基本架构图中的连接模块;


 2、可以按应用类型等方式进行Host Inventory(主机群)分类,管理节点通过各类模块实现相应的操作---单个模块,单条命令的批量执行,我们可以称之为ad-hoc;


 3、管理节点可以通过playbooks 实现多个task的集合实现一类功能,如web服务的安装部署、数据库服务器的批量备份等。playbooks我们可以简单的理解为,系统通过组合多条ad-hoc操作的配置文件 

 

ansible特性:

  分布式,轻量级

  学习曲线不陡峭

  不需要代理,不需要客户端

  没有服务器端

  不基于pki工作

  基于模块工作

  默认基于ssh

  很强的多层解决方案

  配置语法使用YMAL 及Jinja2模板语言

  更强的远程命令执行操作


【安装】

  1、编译安装

     yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto

     tar xf ansible-1.5.4.tar.gz

     cd ansible-1.5.4

     python setup.py build

     python setup.py install

     mkdir /etc/ansible

     cp -r examples/* /etc/ansible


  2、rpm安装

     wget -O /etc/yum.repos.d/CentOS6-Base-163.repo http://mirrors.163.com/.help/CentOS6-Base-163.repo

     yum clean all

     yum makecache

     yum -y install ansible

     yum -y install cowsay     #安装奶牛,可装可不装



【hosts配置】

  中文官网:http://www.ansible.com.cn/docs/intro_inventory.html?highlight=group_vars#id10

  简介:

      Ansible 通过读取默认的主机清单配置/etc/ansible/hosts,可以同时连接到多个远程主机上执行任务, 默认路径可以通过修改 ansible.cfg 的 hostfile 参数指定路径。

  /etc/ansible/hosts 主机清单配置格式如下:

  1、中括号中的名字代表组名,可以根据自己的需求将庞大的主机分成具有标识的组,如下面分了两个组webservers和dbservers组;

  2、主机(hosts)部分可以使用域名、主机名、IP地址表示;当然使用前两者时,也需要主机能反解析到相应的IP地址,一般此类配置中多使用IP地址

    mail.yanruogu.com

    [webservers]

    web1.yanruogu.com

    web2.yanruogu.com 

    [dbservers]

    db1.yanruogu.com

    db2.yanruogu.com

  

  Inventory 参数:

  ansible_ssh_user               #ssh连接时默认使用的用户名

  ansible_ssh_pass               #ssh连接时的密码

  ansible_ssh_port               #用于指定连接到被管理主机的ssh端口号,默认是22

  ansible_sudo_pass              #使用sudo连接用户时的密码

  ansible_ssh_private_key_file   #私钥文件路径

  

  使用示例:  

  下面的示例中指定了三台主机,三台主机的用密码分别是P@ssw0rd、123456、45789,指定的ssh连接的用户名分别为root、breeze、bernie,这样在ansible命令执行的时候就不用再指令用户和密码等了。

  [test]  

  192.168.1.1 ansible_ssh_user=root ansible_ssh_pass='P@ssw0rd'

  192.168.1.2 ansible_ssh_user=breeze ansible_ssh_pass='123456'

  192.168.1.3 ansible_ssh_user=bernie ansible_ssh_port=3055 ansible_ssh_pass='456789'

  aws_host ansible_ssh_private_key_file=/home/example/.ssh/aws.pem


  [databases]

  badwolf.example.com:5309 指定SSH 端口5309

  db-[a:f].example.com 支持字母匹配a b c...f  

  www[01:50].example.com 支持通配符匹配www01 www02 ...www50

  jumper ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50 设置主机别名为jumper

  

  主机变量:

  可以为每个主机单独指定一些变量,这些变量随后可以在playbooks 中使用:

  [atlanta]

  host1 http_port=80 maxRequestsPerChild=808

  host2 http_port=303 maxRequestsPerChild=909

  

  组的变量

  也可以定义属于整个组的变量:

  [atlanta]

  host1

  host2


  [atlanta:vars]

  ntp_server=ntp.atlanta.example.com

  proxy=proxy.atlanta.example.com

  

  组可以包含其他组:

   [wuhan]

    web1

    web2

    [suizhou]

    web4

    web3

    [hubei:children]

    wuhan

    suizhou

    [hubei:vars]

    ntp_server=192.168.1.10

    zabbix_server=192.168.1.10

    [china:children]

    hubei

    hunan

  上面的示例中,指定了武汉组有web1、web2;随州组有web3、web4主机;又指定了一个湖北组,同时包含武汉和随州;同时为该组内的所有主机指定了2个vars变量。设定了一个组中国组,包含湖北、湖南。

  注:vars变量在ansible ad-hoc部分中基本用不到,主要用在ansible-playbook中。

   

  通配模式Patterns

  在Ansible 中,Patterns 意味着要管理哪些机器,在playbooks 中,意味着哪些主机需要应用特定的配置或者过程

  比如我们的主机列表配置为:

  192.168.0.6

  [webservers]

  192.168.0.4

  [db]

  192.168.0.5

  ansible webservers -m service -a "name=httpd state=restarted"

  模式通常用主机组来表示,上面的命令就代表webservers 组的所有主机

  

  其他的匹配方式:

  表示通配inventory 中的所有主机

  all

  *

  ansible all -m service -a "name=httpd state=restarted"

  ansible * -m service -a "name=httpd state=restarted"

  

  也可以指定具有规则特征的主机或者主机名

  one.example.com

  one.example.com:two.example.com

  192.168.1.50

  192.168.1.*

  

  ansible one.example.com -m service -a "name=httpd state=restarted"

  ansible one.example.com:two.example.com -m service -a "name=httpd state=restarted"

  ansible 192.168.1.50 -m service -a "name=httpd state=restarted"

  ansible 192.168.1.* -m service -a "name=httpd state=restarted"

  

  你完全不需要使用这些严格的模式去定义组来管理你的机器,主机名,IP,组都可以使用通配符去匹配

  *.example.com

  *.com

  one*.com:dbservers

  

  ansible *.example.com -m service -a "name=httpd state=restarted"

  ansible *.com -m service -a "name=httpd state=restarted"

  ansible one*.com:dbservers -m service -a "name=httpd state=restarted"

  

  可以匹配一个组的特定编号的主机(先后顺序0 到...)

  webservers1[0] 表示匹配webservers1 组的第1 个主机

  webservers1[0:25] 表示匹配webservers1 组的第1 个到第25 个主机(官网文档是”:”表示范围,测试发现应该使用”-”,注意不要和匹配多个主机组混淆)

  

  ansible webservers1[0] -m service -a "name=httpd state=restarted"

  ansible webservers1[0:25] -m service -a "name=httpd state=restarted"

  

   为host 和group 定义一些比较复杂的变量时(如array、hash),可以用单独文件保存host和group 变量,以YAML 格式书写变量,避免都写在hosts 文件显得混乱,如hosts 文件路径为:

  /etc/ansible/hosts

  /etc/ansible/host_vars/all #host_vars 目录用于存放host 变量,all 文件对所有主机有效

  /etc/ansible/group_vars/all #group_vars 目录用于存放group 变量,all 文件对所有组有效

  /etc/ansible/host_vars/foosball #文件foosball 要和hosts 里面定义的主机名一样,表示只对foosball 主机有效

  /etc/ansible/group_vars/raleigh #文件raleigh 要和hosts 里面定义的组名一样,表示对raleigh 组下的所有主机有效

  注:group_varst和host_vars变量目录要与hosts主机清单文件在同一目录下

   

  这里/etc/ansible/group_vars/raleigh 格式如下:

  --- #YAML 格式要求

  ntp_server: acme.example.org #

  database_server: storage.example.org

  

  最后一个示例

  vim /etc/ansible/hosts

  %s/^/#/g

  [webserver]

  192.168.1.1

  192.168.1.2 


  [dbserver]

  192.168.1.3


  ssh-keygen -t rsa -P ''

  ssh-copy-id -i root@192.168.1.1

  ssh-copy-id -i root@192.168.1.2

  ssh-copy-id -i root@192.168.1.3



【ansible.cnf配置】

  官方网站:http://www.ansible.com.cn/docs/intro_inventory.html#host-variables

  简介:

      Ansible默认安装好后有一个配置文件/etc/ansible/ansible.cfg,该配置文件中定义了ansible的主机的默认配置部分,

  如默认是否需要输入密码、是否开启sudo认证、action_plugins插件的位置、hosts主机组的位置、是否开启log功能、默认端口、key文件位置等等

  具体如下: 

  hostfile       = /etc/ansible/hosts   #指定默认hosts配置的位置

  sudo_user      = root                 #远程sudo用户

  #ask_sudo_pass = True                 #每次执行ansible命令是否询问ssh密码

  #ask_pass      = True                 #每次执行ansible命令时是否询问sudo密码

  #host_key_checking = False            #关闭第一次使用ansible连接客户端是输入命令提示

  #remote_port    = 22                  #默认远程连接端口

  #log_path    = /var/log/ansible.log   #需要时可以自行添加。chown -R root:root ansible.log

  #ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no   #在进行ssh连接时,可以使用-o参数将StrictHostKeyChecking设置为no,使用ssh连接时避免首次连接时让输入yes/no部分的提示


 1.在首次连接或者重装系统之后会出现检查keys 的提示

   The authenticity of host '192.168.0.5 (192.168.0.5)' can't be established.

   ECDSA key fingerprint is 05:51:e5:c4:d4:66:9b:af:5b:c9:ba:e9:e6:a4:2b:fe.

   Are you sure you want to continue connecting (yes/no)?

   解决方法:

   方法1:

   在进行ssh连接时,可以使用-o参数将StrictHostKeyChecking设置为no,使用ssh连接时避免首次连接时让输入yes/no部分的提示。通过查看ansible.cfg配置文件,发现如下行:

   [ssh_connection]

   # ssh arguments to use

   # Leaving off ControlPersist will result in poor performance, so use

   # paramiko on older platforms rather than removing it

   #ssh_args = -o ControlMaster=auto -o ControlPersist=60s

   可以启用ssh_args 部分,使用下面的配置,避免上面出现的错误:

   ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no

   

   方法2:

   在ansible.cfg配置文件中,也会找到如下配置:

   # uncomment this to disable SSH key host checking

   host_key_checking = False  

   默认host_key_checking部分是注释的,通过找开该行的注释,同样也可以实现跳过ssh 首次连接提示验证部分。但在实际测试中,似乎并没有效果,建议使用方法1.

   

   方法3:

   通过设置系统环境变量来禁止这样的提示

   export ANSIBLE_HOST_KEY_CHECKING=False

   

【Ansible的七个命令】

 安装完ansible后,发现ansible老版本一共为我们提供了七个指令:ansible、ansible-doc、ansible-galaxy、ansible-lint、ansible-playbook、ansible-pull、ansible-vault 。这里我们只查看usage部分,详细部分可以通过 “指令 -h”  的方式获取。

 新版本六个指令:ansible、ansible-doc、ansible-galaxy、ansible-playbook、ansible-pull、ansible-vault 

 1、ansible 

    ansible是指令核心部分,其主要用于执行ad-hoc命令,即单条命令。默认后面需要跟主机和选项部分,默认不指定模块时,使用的是command模块

    不过默认使用的模块是可以在ansible.cfg 中进行修改的。ansible命令下的参数部分解释如下:  这里只列举常用的

    示例:

    ansible -h

    -i PATH, --inventory=PATH   指定库存主机文件的路径,默认为/etc/ansible/hosts.

    -u Username, --user=Username   执行用户,使用这个远程用户名而不是当前用户

    -U SUDO_USER, --sudo-user=SUDO_USER   sudo到哪个用户,默认为 root

    -k --ask-pass  登录密码,提示输入SSH密码而不是假设基于密钥的验证

    -K --ask-sudo-pass 提示密码使用sudo

    -s --sudo sudo运行

    -S --su 用 su 命令

    -R SU_USER, --su-user=SU_USER,su过去的用户默认为root

    -f  --forks=NUM 并行任务数。NUM被指定为一个整数,默认是5

    --private-key=PRIVATE_KEY_FILE 私钥路径,使用这个文件来验证连接

    -v,--verbose详细模式(-vvv更多,-vvvv启用连接调试)

    --version显示程序版本号并退出

    -B 后台运行超时时间

    -P 调查后台程序时间,默认15s

    --tags=TAGS 只执行指定标签的任务    例子:ansible-playbook test.yml --tags=copy  只执行标签为copy的那个任务 [详情看tags篇 ]

    --skip-tags=SKIP_TAGS 只运行戏剧和任务不匹配这些值的标签  --skip-tags=copy_start                           [详情看tags篇 ]

    --list-hosts 只打印有哪些主机会执行这个 playbook 文件,不是实际执行该 playbook 文件

    --list-tasks 列出所有将被执行的任务

    -C, --check 只是测试一下会改变什么内容,不会真正去执行;相反,试图预测一些可能发生的变化

    --syntax-check 执行语法检查的剧本,但不执行它

    -l,--limit 对指定的 主机/组 执行任务  --limit=192.168.0.10,192.168.0.11 或 -l 192.168.0.10,192.168.0.11 只对这个2个ip执行任务

    -e 设置变量, [详情用法看变量篇]

    --start-at="install packages"  从指定的任务开始执行,从install packages这个任务开始执行

    --setup     交互式执行

    

 2、ansible-doc

    该指令用于查看模块信息,常用参数有两个-l 和 -s ,具体如下:

    //列出所有已安装的模块

    # ansible-doc  -l

    //查看具体某模块的用法,这里如查看command模块

    # ansible-doc  -s command

  

  3、ansible-galaxy

     “Ansible Galaxy” 指的是一个网站共享和下载 Ansible 角色,也可以是者是帮助 roles 更好的工作的命令行工具。

     http://www.ansible.com.cn/docs/galaxy.html#id5 更详细galaxy的内容请看官网

     # ansible-galaxy -h

     Usage: ansible-galaxy [init|info|install|list|remove] [--help] [options] ...

     ansible-galaxy 指令用于方便的从https://galaxy.ansible.com/ 站点下载第三方扩展模块,我们可以形象的理解其类似于centos下的yum、python下的pip或easy_install 。如下示例:

     安装角色,从 Ansible Galaxy 网站下载角色

     [root@localhost ~]# ansible-galaxy install aeriscloud.docker

     - downloading role 'docker', owned by aeriscloud

     - downloading role from https://github.com/AerisCloud/ansible-docker/archive/v1.0.0.tar.gz

     - extracting aeriscloud.docker to /etc/ansible/roles/aeriscloud.docker

     - aeriscloud.docker was installed successfully

     

     从一个文件安装多个角色

     ansible-galaxy install -r requirements.txt

     

     requirements.txt 文件看起来就像这样

     username1.foo_role username2.bar_role

     

     想得到指定版本(tag)的role,使用下面的语法

     username1.foo_role,version username2.bar_role,version

     

     ansible-galaxy是一个工具,我们可以利用它快速的创建一个标准的roles目录结构,还可以通过它在https:/galaxy.ansible.com上下载别人写好的roles,直接拿来用。

     通过ansible-galaxy初始化一个roles的目录结构,方法如下:

     ansible-galaxy init /etc/ansible/roles/websrvs

     

     安装别人写好的roles:

     ansible-galaxy install -p /etc/ansible/roles bennojoy.mysql

     

     列出已安装的roles:

     ansible-galaxy list

     

     查看已安装的roles信息:

     ansible-galaxy info bennojoy.mysql

     

     卸载roles:

     ansible-galaxy remove bennojoy.mysql

     

  4、ansible-playbook

     该指令是使用最多的指令,其通过读取playbook 文件后,执行相应的动作,

   

  5、ansible-pull

     该指令使用需要谈到ansible的另一种模式---pull 模式,这和我们平常经常用的push模式刚好相反,其适用于以下场景:你有数量巨大的机器需要配置,

     即使使用非常高的线程还是要花费很多时间;你要在一个没有网络连接的机器上运行Anisble,比如在启动之后安装。这部分也会单独做一节来讲

    

  6、ansible-vault

     ansible-vault主要应用于配置文件中含有敏感信息,又不希望他能被人看到,vault可以帮你加密/解密这个配置文件,属高级用法。主要对于playbooks里比如涉及到配置密码或其他变量时,可以通过该指令加密,

     这样我们通过cat看到的会是一个密码串类的文件,编辑的时候需要输入事先设定的密码才能打开。

     这种playbook文件在执行时,需要加上 –ask-vault-pass参数,同样需要输入密码后才能正常执行。

    

    

【命令行使用Ansible方法】

  ansible通过ssh实现配置管理、应用部署、任务执行等功能,因此,需要事先配置ansible端基于密钥认证的方式联系各被管理节点

  ansible <host-pattern> <-f 并行进程数(默认为5)> <-m 模块名(默认为command,可以省略)> <-a 模块参数>

  ansible 主机组  -f '并行进程数' -m  '模块名'- a  '模块参数' 

  例用示例:

  ansible -h              #查看命令帮助

  ansible all -m ping     #ping模块,默认不带参数

  ansible all -a date     #模块的参数,不加-m默认为执行命令,-a要执行的命令 

  ansible-doc -l          #列出所有的模块列表

  ansible-doc file        #查看指定模块的参数,一般用此种方法

  ansible-doc -s file     #查看指定模块的参数  

  ansible all -f 10 -m file -a "path=/tmp/test state=directory"

  ansible wsyht -m shell -a 'touch /opt/test.txt' -utom    #指定用户执行命令

  ansible wsyht -m shell -a 'touch /opt/tt.txt' -utom --sudo     #获取root权限执行命令

  ansible ali  -S -R root -m script -a '/bin/sh /usr/local/src/jdk.sh'    #-S使用su,-R指定su过去的用户为root

  

【Ad-hoc与命令执行模块】

  官方网站:http://www.ansible.com.cn/docs/intro_getting_started.html

  简介:

      Ad-Hoc 是指ansible下临时执行的一条命令,并且不需要保存的命令,对于复杂的命令会使用playbook。Ad-hoc的执行依赖于模块,

  ansible官方提供了大量的模块。 如:command、raw、shell、file、cron等,具体可以通过ansible-doc -l 进行查看 。可以使用ansible-doc -s module来查看某个模块的参数, 

  也可以使用ansible-doc help module来查看该模块更详细的信息。

  1、后台执行

     当命令执行时间比较长时,也可以放到后台执行,使用-B、-P参数,如下:

     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

  2、命令行执行模块

     命令执行模块包含如下 四个模块: 

         command模块:该模块通过-a跟上要执行的命令可以直接执行,不过命令里如果有带有如下字符部分则执行不成功 “  "<", ">", "|",  "&" 

         shell 模块:用法基本和command一样,不过其是通过/bin/sh进行执行,所以shell 模块可以执行任何命令,就像在本机执行一样;

         raw模块:用法和shell 模块一样 ,其也可以执行任意命令,就像在本机执行一样;

         script模块:其是将管理端的shell 在被管理主机上执行,其原理是先将shell 复制到远程主机,再在远程主机上执行,原理类似于raw模块。

     注:raw模块和comand、shell 模块不同的是其没有chdir、creates、removes参数,chdir参数的作用就是先切到chdir指定的目录后,再执行后面的命令,这在后面很多模块里都会有该参数 。

     command模块包含如下选项: 

         creates:一个文件名,当该文件存在,则该命令不执行 

         free_form:要执行的linux指令 

         chdir:在执行指令之前,先切换到该指定的目录 

         removes:一个文件名,当该文件不存在,则该选项不执行

         executable:切换shell来执行指令,该执行路径必须是一个绝对路径

     使用chdir的示例:

         ansible 192.168.1.1 -m command -a 'chdir=/tmp/test.txt touch test.file'

         ansible 192.168.1.1 -m shell -a 'chdir=/tmp/test.txt touch test2.file'

         ansible 192.168.1.1 -m raw -a 'chdir=/tmp/text.txt touch test3.file'

     三个命令都会返回执行成功的状态。不过实际上只有前两个文件会被创建成功。使用raw模块的执行的结果文件事实上也被正常创建了,不过不是在chdir指定的目录,而是在当前执行用户的家目录。

     creates与removes示例:

         ansible 192.168.1.1 -a 'creates=/tmp/server.txt uptime' #当/tmp/server.txt文件存在时,则不执行uptime指令

         ansible 192.168.1.1 -a 'removes=/tmp/server.txt uptime' #当/tmp/server.txt文件不存在时,则不执行uptime指令



【Ansible常用模块】

  参考官网:http://docs.ansible.com/ansible/modules_by_category.html

  简介:

      根据官方的分类,将模块按功能分类为:云模块、命令模块、数据库模块、文件模块、资产模块、消息模块、监控模块、网络模块、通知模块、包管理模块、源码控制模块、

  系统模块、单元模块、web设施模块、windows模块 ,具体可以参看官方页面。这里从官方分类的模块里选择最常用的一些模块进行介绍。

  1)ping 2)setup 3)file 4)copy 5)service 6)cron 7)yum 8)user和group 9)synchronize 10)filesystem 11)mount 12)get_url 13)unarchive 14)lineinfile

  1、ping模块

     测试主机是否是通的,用法很简单,不涉及参数:

     ansible all -m ping 


  2、setup模块

     setup模块,主要用于获取主机信息,在playbooks里经常会用到的一个参数gather_facts就与该模块相关。setup模块下经常使用的一个参数是filter参数,具体使用示例如下:

     使用示例:

      ansible all -m setup

      ansible all -m setup  --tree .  #搜集系统信息并以主机名为文件名保存在当前目录

      ansible 10.212.52.252 -m setup -a 'filter=ansible_*_mb'     #查看主机内存信息

      ansible 10.212.52.252 -m setup -a 'filter=ansible_eth[0-2]'   #查看地接口为eth0-2的网卡信息

      ansible all -m setup --tree /tmp/facts   #将所有主机的信息输入到/tmp/facts目录下,每台主机的信息输入到主机名文件中(/etc/ansible/hosts里的主机名)

      ansible webservers -m setup -a "filter=ansible_local" #在控制节点获取自定义的信息:

      关闭facts

      如果你确信不需要主机的任何facts信息,而且对远程节点主机都了解的很清楚,那么可以将其关闭。远程操作节点较多的时候,关闭facts会提升

      ansible的性能。

      只需要在play中设置如下:

      - hosts: whatever

        gather_facts: no   或

        gather_facts: false  #推荐用这个   

      

   3、file模块

      file模块主要用于远程主机上的文件操作,file模块包含如下选项: 

      force:需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no 

      group:定义文件/目录的属组 

      mode:定义文件/目录的权限

      owner:定义文件/目录的属主

      path:必选项,定义文件/目录的路径

      recurse:递归的设置文件的属性,只对目录有效

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

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

      state:  

           directory:如果目录不存在,创建目录

           file:即使文件不存在,也不会被创建

           link:创建软链接

           hard:创建硬链接

           touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间

           absent:删除目录、文件或者取消链接文件

      使用示例:

      ansible test -m file -a "src=/etc/fstab dest=/tmp/fstab state=link"

      ansible test -m file -a "path=/tmp/fstab state=absent"

      ansible test -m file -a "path=/tmp/test state=touch"

      ansible all -m file -a "path=/opt/test state=directory owner=wsyht group=wsyht mode=777"


    4、copy模块

       复制文件到远程主机,copy模块包含如下选项:

       backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no 

       content:用于替代"src",可以直接设定指定文件的值 

       dest:必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录 

       directory_mode:递归的设定目录的权限,默认为系统默认权限

       force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes

       others:所有的file模块里的选项都可以在这里使用

       src:要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync。 

       使用示例:

       ansible test -m copy -a "src=/srv/myfiles/foo.conf dest=/etc/foo.conf owner=foo group=foo mode=0644"

       ansible test -m copy -a "src=/mine/ntp.conf dest=/etc/ntp.conf owner=root group=root mode=644 backup=yes"

       ansible test -m copy -a "src=/tmp/haproxy-1.5.3.tar.gz dest=/tmp"   #拷贝本地文件到远程机器


    5、service模块

       用于管理服务,该模块包含如下选项:

       arguments:给命令行提供一些选项 

       enabled:是否开机启动 yes|no

       name:必选项,服务名称 

       pattern:定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行

       runlevel:运行级别

       sleep:如果执行了restarted,在则stop和start之间沉睡几秒钟

       state:对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded)

       使用示例:

       ansible all -m service -a "name=httpd state=started enabled=yes"

       asnible all -m service -a "name=foo pattern=/usr/bin/foo state=started"

       ansible all -m service -a "name=network state=restarted args=eth0"

       ansible all -m service -a "name=zabbix_agentd pattern=/etc/init.d/zabbix_agentd state=reloaded"

       

       

    6、cron模块

       用于管理计划任务包含如下选项:

       backup:对远程主机上的原任务计划内容修改之前做备份 

       cron_file:如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划 

       day:日(1-31,*,*/2,……)

       hour:小时(0-23,*,*/2,……)

       minute:分钟(0-59,*,*/2,……)

       month:月(1-12,*,*/2,……)

       weekday:周(0-7,*,……)

       job:要执行的任务,依赖于state=present 

       name:该任务的描述 

       special_time:指定什么时候执行,参数:reboot,yearly,annually,monthly,weekly,daily,hourly 

       state:确认该任务计划是创建还是删除 

       user:以哪个用户的身份执行

       使用示例:

       ansible test -m cron -a 'name="a job for reboot" special_time=reboot job="/some/job.sh"'

       ansible test -m cron -a 'name="yum autoupdate" weekday="2" minute=0 hour=12 user="root

       ansible test -m cron -a 'backup="True" name="test" minute="0" hour="5,2" job="ls -alh > /dev/null"'

       ansilbe test -m cron -a 'cron_file=ansible_yum-autoupdate state=absent'

       ansible test -m cron -a 'name="custom job" minute=*/2 hour=* day=* month=* weekday=* job="/usr/sbin/ntpdate 192.168.1.1"'


    7、yum模块

       使用yum包管理器来管理软件包,其选项有: 

       config_file:yum的配置文件 

       disable_gpg_check:关闭gpg_check 

       disablerepo:不启用某个源 

       enablerepo:启用某个源

       name:要进行操作的软件包的名字,也可以传递一个url或者一个本地的rpm包的路径 

       state:状态(present,absent,latest)

       使用示例:

       ansible test -m yum -a 'name=httpd state=latest'

       ansible test -m yum -a 'name="@Development tools" state=present'

       ansible test -m yum -a 'name=http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present'

       ansible all -m yum -a "state=present name=mysql"   


    8、user模块与group模块

       user模块是请求的是useradd, userdel, usermod三个指令,goup模块请求的是groupadd, groupdel, groupmod 三个指令。 

       home:指定用户的家目录,需要与createhome配合使用

       groups:指定用户的属组

       uid:指定用的uid

       password:指定用户的密码

       name:指定用户名

       createhome:是否创建家目录 yes|no

       system:是否为系统用户

       remove:当state=absent时,remove=yes则表示连同家目录一起删除,等价于userdel -r

       state:是创建还是删除

       shell:指定用户的shell环境

       user使用示例:

       user: name=johnd comment="John Doe" uid=1040 group=admin

       user: name=james shell=/bin/bash groups=admins,developers append=yes user: name=johnd state=absent remove=yes

       user: name=james18 shell=/bin/zsh groups=developers expires=1422403387

       user: name=test generate_ssh_key=yes ssh_key_bits=2048 ssh_key_file=.ssh/id_rsa    #生成密钥时,只会生成公钥文件和私钥文件,和直接使用ssh-keygen指令效果相同,不会生成authorized_keys文件。

       注:指定password参数时,不能使用明文密码,因为后面这一串密码会被直接传送到被管理主机的/etc/shadow文件中,所以需要先将密码字符串进行加密处理。然后将得到的字符串放到password中即可。

       grub-crypt --sha-512 直接回车输入密码即可对密码进行加密处理

       ansible all -m user -a 'name=foo password="$1$4P4PlFuE$ur9ObJiT5iHNrb9QnjaIB0"'

       group使用示例

       ansible all -m group -a 'name=somegroup state=present'

       ansible all -m group -a "gid=306 system=yes name=mysql" 


    9、synchronize模块

       使用rsync同步文件,其参数如下:

       archive: 归档,相当于同时开启recursive(递归)、links、perms、times、owner、group、-D选项都为yes ,默认该项为开启

       checksum: 跳过检测sum值,默认关闭

       compress:是否开启压缩

       copy_links:复制链接文件,默认为no ,注意后面还有一个links参数

       delete: 删除不存在的文件,默认no

       dest:目录路径

       dest_port:默认目录主机上的端口 ,默认是22,走的ssh协议

       dirs:传速目录不进行递归,默认为no,即进行目录递归

       rsync_opts:rsync参数部分

       set_remote_user:主要用于/etc/ansible/hosts中定义或默认使用的用户与rsync使用的用户不同的情况

       mode: push或pull 模块,push模的话,一般用于从本机向远程主机上传文件,pull 模式用于从远程主机上取文件

       使用示例:

       src=some/relative/path dest=/some/absolute/path rsync_path="sudo rsync"

       src=some/relative/path dest=/some/absolute/path archive=no links=yes

       src=some/relative/path dest=/some/absolute/path checksum=yes times=no

       src=/tmp/helloworld dest=/var/www/helloword rsync_opts=--no-motd,--exclude=.git mode=pull

     

   10、filesystem模块

       在块设备上创建文件系统

       选项: 

       dev:目标块设备

       force:在一个已有文件系统 的设备上强制创建

       fstype:文件系统的类型

       opts:传递给mkfs命令的选项

       使用示例:

       ansible test -m filesystem -a 'fstype=ext2 dev=/dev/sdb1 force=yes'

       ansible test -m filesystem -a 'fstype=ext4 dev=/dev/sdb1 opts="-cc"'

       ansible test -m filesystem 'fstype=ext4 force=yes opts=-F dev=/dev/loop0'


   11、mount模块

       配置挂载点

       选项: 

       dump

       fstype:必选项,挂载文件的类型 

       name:必选项,挂载点 

       opts:传递给mount命令的参数

       src:必选项,要挂载的文件 

       state:必选项 

       present:只处理fstab中的配置 

       absent:删除挂载点 

       mounted:自动创建挂载点并挂载之 

       umounted:卸载

       使用示例:

       name=/mnt/dvd src=/dev/sr0 fstype=iso9660 opts=ro state=present

       name=/srv/disk src='LABEL=SOME_LABEL' state=present

       name=/home src='UUID=b3e48f45-f933-4c8e-a700-22a159ec9077' opts=noatime state=present

       ansible test -a 'dd if=/dev/zero of=/disk.img bs=4k count=1024'

       ansible test -a 'losetup /dev/loop0 /disk.img'

       ansible test -m mount 'name=/mnt src=/dev/loop0 fstype=ext4 state=mounted opts=rw'


   12、get_url 模块

       该模块主要用于从http、ftp、https服务器上下载文件(类似于wget),主要有如下选项:

       sha256sum:下载完成后进行sha256 check;

       timeout:下载超时时间,默认10s

       url:下载的URL

       url_password、url_username:主要用于需要用户名密码进行验证的情况

       use_proxy:是使用代理,代理需事先在环境变更中定义

       使用示例:

       get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf mode=0440

       get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf sha256sum=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c

 

   13、unarchive模块

       用于解压文件,模块包含如下选项:

       copy:在解压文件之前,是否先将文件复制到远程主机,默认为yes。若为no,则要求目标主机上压缩包必须存在。

       creates:指定一个文件名,当该文件存在时,则解压指令不执行

       dest:远程主机上的一个路径,即文件解压的路径 

       grop:解压后的目录或文件的属组

       list_files:如果为yes,则会列出压缩包里的文件,默认为no,2.0版本新增的选项

       mode:解决后文件的权限

       src:如果copy为yes,则需要指定压缩文件的源路径 

       owner:解压后文件或目录的属主

       示例如下:

       - unarchive: src=foo.tgz dest=/var/lib/foo

       - unarchive: src=/tmp/foo.zip dest=/usr/local/bin copy=no

       - unarchive: src=https://example.com/example.zip dest=/usr/local/bin copy=no

 

   14、lineinfile模块

       主要用来改变一个单行的文件,如果你想改变多行,就用copy或template模块

       line:插入/替换到文件中,默认插入到最后一行

       regexp:正则表达式查找在文件的每一行。

       owner: 命名文件目录的用户

       group: 命名文件目录的组

       state: 当前行是否应该存在,absent删除该行,默认present存在

       backup: 对文件进行操作前是否先备份,默认是No


       EXAMPLES:

       - lineinfile: dest=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=enforcing'  #替换selinux该行


       - lineinfile: dest=/etc/sudoers state=absent regexp="^%wheel backup=yes" #删除匹配到的正则表达式的行,先备份文件再删除


       - lineinfile: dest=/etc/hosts regexp='^127\.0\.0\.1' line='127.0.0.1 localhost' owner=root group=root mo #更改匹配到的行并给文件用户和组root权限


       # Fully quoted because of the ': ' on the line. See the Gotchas in the YAML docs. #在最后一行插入内容

       - lineinfile: "dest=/etc/sudoers line='%wheel ALL=(ALL) NOPASSWD: ALL'"



【Playbook执行方法】

  官方网站:http://www.ansible.com.cn/docs/playbooks_intro.html#playbook

  简介:

      ansbile-playbook是一系列ansible命令的集合,利用yaml 语言编写。playbook命令根据自上而下的顺序依次执行。同时,playbook开创了很多特性,它可以允许你传输某个命令的状态到后面的指令,

  如你可以从一台机器的文件中抓取内容并附为变量,然后在另一台机器中使用,这使得你可以实现一些复杂的部署机制,这是ansible命令无法实现的。

      playbook通过ansible-playbook命令使用,它的参数和ansible命令类似,如参数-k(–ask-pass) 和 -K (–ask-sudo) 来询问ssh密码和sudo密码,-u指定用户,这些指令也可以通过规定的单元写在playbook 。

      ansible-playbook使用

      查看使用方法:

        ansible -h  或 ansible --help

      

      不加-f默认是5个线程,这里给他定义了十个线程并发执行

      例子: 

                   ansible-playbook example-play.yml -f 10


      在执行一个 playbook 之前,想看看这个 playbook 的执行会影响到哪些 hosts,

      你可以这样做:

                   ansible-playbook playbook.yml --list-hosts            

      

      检测模块运行:--check

      产生大量的输出结果: --diff

      --diff 选项与 --check (详情参下)配合使用效果奇佳,

      -l,--limit 对指定的 主机/组 执行任务  --limit=192.168.0.10,192.168.0.11 或 -l 192.168.0.10,192.168.0.11 只对这个2个ip执行任务

      参考如下例子:        --check 

                  ansible-playbook foo.yml --check --diff --limit foo.example.com

                  

      对前十台和接下来的10台执行任务

                  ansible-playbook foo.yml --check --diff --limit boston[0-10]

                  ansible-playbook foo.yml --check --diff --limit boston[10-20]

                  

      查看都有哪些任务要执行

      ansible-playbook playbook.yml --list-tasks

      

      查看模块执行成功与否的详细信息

      参数:

      -v  #详细信息

      -vvvv  #启用更多详细信息

      ansible-playbook playbook.yml -v   #或

      ansible-playbook playbook.yml -vvvv   #显示更详细的信息,推荐用此方法

      

      [Start-at-task]  从指定任务开始运行palybook以及分步运行playbook

      如果你想从指定的任务开始执行playbook,可以使用``–start-at``选项:

      ansible-playbook playbook.yml --start-at="install packages"

      分步运行playbook

      我们也可以通过``–step``选项来交互式的执行playbook: 这样ansible在每个任务前会自动停止,并询问是否应该执行该任务.

      ansible-playbook playbook.yml --step


      比如你有个名为``configure ssh``的任务,playbook执行到这里会停止并询问:

      “y”回答会执行该任务,”n”回答会跳过该任务,而”c”回答则会继续执行剩余的所有任务而不再询问你.

      Perform task: configure ssh (y/n/c):


【Playbook构成和简单使用】

  官方网站:http://www.ansible.com.cn/docs/playbooks_intro.html#playbook

  playbooks组成:

      Target section:   定义将要执行 playbook 的远程主机组

      Variable section: 定义 playbook 运行时需要使用的变量

      Task section:     定义将要在远程主机上执行的任务列表

      Handler section:  定义 task 执行完成以后需要调用的任务


  而其对应的目录层为五个,如下:

      vars     变量层

      tasks    任务层

   handlers 触发条件

      files    文件

      template 模板


  1、Hosts和Users

     playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。

     hosts:用于指定要执行指定任务的主机其可以是一个或多个由冒号分隔主机组。

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

     user:与remote_user相同

     sudo:如果设置为yes,执行该任务组的用户在执行任务的时候,获取root权限

     sudo_user:如果设置user为breeze,sudo为yes,sudo_user为bernie时,则breeze用户在执行任务时会获得bernie用户的权限

     connection:通过什么方式连接到远程主机,默认为ssh

     gather_facts:除非明确说明不需要在远程主机上执行setup模块,否则默认自动执行。如果确实不需要setup模块传递过来的变量,则可以将该选项设置为False

     示例1:

     - hosts: webnodes

       tasks:

         - name: test ping connection:

           remote_user: test

           sudo: yes


      #同样的,你可以仅在一个 task 中,使用 sudo 执行命令,而不是在整个 play 中使用 sudo:

      示例2:

      ---

      - hosts: webservers

        remote_user: yourname

        tasks:

          - service: name=nginx state=started

            sudo: yes

            

      #你也可以登陆后,sudo 到不同的用户身份,而不是使用 root:

      示例3:

      ---

      - hosts: webservers

        remote_user: yourname

        sudo: yes

        sudo_user: postgres

      

      #多台主机用点隔开

      示例4:

      ---

      - hosts: web,db,mysql

      或

      - hosts:

          - web

          - db

          - mysql

      

  2、任务列表和action

     play的主体部分是任务列表。

         任务列表中的各任务按次序逐个在hosts中指定的所有主机上执行即在所有主机上完成第一个任务后再开始第二个。在自上而下运行某playbook时如果中途发生错误,所有已执行任务都将回滚因此在更正playbook后重新执行一次即可。 

         task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。每个task都应该有其name用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。如果未提供name则action的结果将用于输出。 

         定义task的可以使用"action: module options"或"module: options"的格式,推荐使用后者以实现向后兼容。如果action一行的内容过多也可使用在行首使用几个空白字符进行换行。

      示例1:

      tasks:

      - name: make sure apache is running

        service: name=httpd state=running

      

      示例2:

      #在众多模块中只有command和shell模块仅需要给定一个列表而无需使用“key=value”格式例如

       tasks:

          - name: disable selinux

            command: /sbin/setenforce 0

      

      示例3:

      #如果命令或脚本的退出码不为零可以使用如下方式替代

      tasks:

        - name: run this command and ignore the result

          shell: /usr/bin/somecommand || /bin/true

       

      示例4:

      #使用ignore_errors来忽略错误信息

      tasks:

        - name: run this command and ignore the result

      shell: /usr/bin/somecommand

      ignore_errors: True  

      

      示例%:

      #如果 action 行看起来太长,你可以使用 space(空格) 或者 indent(缩进) 隔开连续的一行:

      tasks:

        - name: Copy ansible inventory file to client

          copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts

                  owner=root group=root mode=0644

      示例6:

      #任务执行的方法有3种,推荐用第二种

       tasks

         - name: install apache

           action: yum name=httpd state=install     #第一种方法

        

         - name: configure apache

           copy: src=files/httpd.conf dest=/etc/httpd/conf/httpd.conf   #第二种方法

       

         - name: restart apache

           service :

              name: httpd

              state: restarted       #第三种方法

      

  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 


      #完整示例1:

      ---

      - hosts: all

        user: root

        tasks:

          - name: install memcached

            yum: name=memcahed state=installed

          - name: set memcached size

            set_fact: memcached_size="{{ ansible_memtotal_mb/4 }}"

          - name: copy configuraitios

            template: src=templates/memcacched.j2 dest=/etc/sysconfig/memcached

            notify:

              - restart memcached

         

         handlers:

            - name: restart memcached

              service: name=memcached state=restarted enabled=yes

             

      #cat templates/memcacched.j2

       PORT="11211"

       USER="memached"

       CHCASIZE="{{ memcached_size|default(1024) }}"  #有值测输入memcached_size大小,没值则输入默认1024


      #完整示例2:

       ---

       - hosts: webservers

         remote_user: root


         tasks:

           - name: ensure apache is at the latest version

             yum: name=httpd state=latest

           - name: write the apache config file

             template: src=/srv/httpd.j2 dest=/etc/httpd.conf


           - hosts: databases

             remote_user: root


         tasks:

           - name: ensure postgresql is at the latest version

             yum: name=postgresql state=latest

           - name: ensure that postgresql is started

             service: name=postgresql state=running

         

【Playbook常用模块】

 参考官网: http://docs.ansible.com/ansible/modules_by_category.html

 注:jinja2示例可参考Ansible图文参考Word文档

 1)template 2)setup 3)set_fact 4)pause 5)wait_for 6)assemble 7)add_host 8)group_by 9)get_rul 10)debug 11)fail 12)mysql_user

  1、template模块

     在实际应用中,我们的配置文件有些地方可能会根据远程主机的配置的不同而有稍许的不同,template可以使用变量来接收远程主机上setup收集到的facts信息,针对不同配置的主机,定制配置文件。用法大致与copy模块相同。

        常用参数:

        backup:如果原目标文件存在,则先备份目标文件

        dest:目标文件路径

        force:是否强制覆盖,默认为yes

        group:目标文件属组

        mode:目标文件的权限

        owner:目标文件属主

        src:源模板文件路径

        validate:在复制之前通过命令验证目标文件,如果验证通过则复制

        官方简单示例:

        - template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode=0644

        - template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode="u=rw,g=r,o=r"

        playbook的引用该模板配置文件的方法示例:

        - name: Setup BIND

          host: allnames

          tasks:

            - name: configure BIND

              template: src=templates/named.conf.j2 dest=/etc/named.conf owner=root group=named mode=0640

              

  2、setup模块

     ---

     - hosts: all

       user: root

       vars_files:

         - variables

       tasks:

         -name: print ip

          template: scr=files/test.txt /dest=/tmp/test.txt

          

      #cat files/test.txt

       `ansible_devices`.`sda`.`partitions`.`sda1`.`szie`

       {{ansible_mounts[0].size_total}}

       

      #从setup模块获取sda1.sizet和mounts大小的值,setup模块默认自动执行,详细介绍可参考Ansible图文参考Word文档

    

  3、set_fact模块

     他可以自定义facts,这些自定义的facts可以通过template或者变量的方式在playbook中使用。如果你想要获取一个进程使用的内存的百分比,则必须通过set_fact来进行计算之后得出其值,并将其值在playbook中引用。

     下面是一个配置mysql innodb buffer size的示例:

     - name: Configure MySQL

       hosts: mysqlservers

       tasks: 

     - name: install MySql

       yum: name=mysql-server state=installed


     - name: Calculate InnoDB buffer pool size

       set_fact: innodb_buffer_pool_size_mb="{{ ansible_memtotal_mb / 2 }}"


     - name: Configure MySQL 

       template: src=templates/my.cnf dest=/etc/my.cnf owner=root group=root mode=0644 

       notify: restart mysql 


     - name: Start MySQL 

       service: name=mysqld state=started enabled=yes 

       handlers: 

     - name: restart mysql 

       service: name=mysqld state=restarted

       

     my.cnf的配置示例:

     # ` ansible_managed `

     [mysqld]

     datadir=/var/lib/mysql

     socket=/var/lib/mysql/mysql.sock

     # Disabling symbolic-links is recommended to prevent assorted

     security risks

     symbolic-links=0

     # Configure the buffer pool

     innodb_buffer_pool_size = {{ innodb_buffer_pool_size_mb|default(128) }}M   #如果前面值没有,就默认使用128M

     [mysqld_safe]

     log-error=/var/log/mysqld.log

     pid-file=/var/run/mysqld/mysqld.pid

  

  4、pause暂停模块

     在playbook执行的过程中暂停一定时间或者提示用户进行某些操作

     minutes:暂停多少分钟

     seconds:暂停多少秒

     prompt:打印一串信息提示用户操作

     示例:

     - name: wait on user input

       pause: prompt="Warning! Detected slight issue. ENTER to continue CTRL-C a to quit"  #你输入回车确认才会执行下面的任务

     - name: timed wait

       pause: seconds=30   #暂停三十秒再执行后面的任务

  

  5、wait_for模块

     在playbook的执行过程中,等待某些操作完成以后再进行后续操作

     wait_for模块用来检测一个tcp端口是否准备好接收远程连接,这是由远程主机来完成的。如果你只指定了端口,或者主机参数被设置为localhost,它会尝试连接过程受管主机。

     你可以用local_action参数来指定从控制机器来运命令,并使用ansible_hostname为主机参数来远程受管主机。这个模块在后台运行某些程序或者启动些进程需要一些时间的时候特别有用

     常用参数:

     connect_timeout:在下一个任务执行之前等待连接的超时时间

     delay:等待一个端口或者文件或者连接到指定的状态时,默认超时时间为300秒,在这等待的300s的时间里,wait_for模块会一直轮询指定的对象是否到达指定的状态,delay即为多长时间轮询一次状态。

     host:wait_for模块等待的主机的地址,默认为127.0.0.1

     port:wait_for模块待待的主机的端口

     path:文件路径,只有当这个文件存在时,下一任务才开始执行,即等待该文件创建完成

     state:等待的状态,即等待的文件或端口或者连接状态达到指定的状态时,下一个任务开始执行。当等的对象为端口时,状态有started,stoped,即端口已经监听或者端口已经关闭;当等待的对象为文件时,状态有present或者started,absent,即文件已创建或者删除;当等待的对象为一个连接时,状态有drained,即连接已建立。默认为started

     timeout:wait_for的等待的超时时间,默认为300秒

     - wait_for: port=8080 state=started     #等待8080端口已正常监听,才开始下一个任务,直到超时

     - wait_for: port=8000 delay=10    #等待8000端口正常监听,每隔10s检查一次,直至等待超时

     - wait_for: host=0.0.0.0 port=8000 delay=10 state=drained    #等待8000端口直至有连接建立

     - wait_for: host=0.0.0.0 port=8000 state=drained exclude_hosts=10.2.1.2,10.2.1.3    #等待8000端口有连接建立,如果连接来自10.2.1.2或者10.2.1.3,则忽略。

     - wait_for: path=/tmp/foo    #等待/tmp/foo文件已创建

     - wait_for: path=/tmp/foo search_regex=completed    #等待/tmp/foo文件已创建,而且该文件中需要包含completed字符串

     - wait_for: path=/var/lock/file.lock state=absent    #等待/var/lock/file.lock被删除

     - wait_for: path=/proc/3466/status state=absent        #等待指定的进程被销毁

     - local_action: wait_for port=22 host="{{ ansible_ssh_host | default(inventory_hostname) }}" search_regex=OpenSSH delay=10    #等待openssh启动,10s检查一次

     示例:

     ---

     - hosts: all

       user: root

       

       tasks:

         - name: Install Tomcat

           yum:name=tomcat6 state=installed

           

         - name: Start Tomcat

           service: name=tomcat6 state=started

           

         - name: Wait for Tomcat to start

           wait_for: port=8080 state=started


  6、assemble模块

     用于组装文件,即将多个零散的文件,合并一个大文件

     用于组装文件,即将多个零散的文件,合并一个大文件

     常用参数:

     src:原文件(即零散文件)的路径

     dest:合并后的大文件路径

     group:合并后的大文件的属组

     owner:合并后的大文件的属主

     mode:合并后的大文件的权限

     validate:与template的validate相同,指定命令验证文件

     ignore_hidden:组装时,是否忽略隐藏文件,默认为no,该参数在2.0版本中新增

     

  7、add_host模块

     在playbook执行的过程中,动态的添加主机到指定的主机组中

     add_host添加主机模块是playbook中一个强大的模块,它可以让你动态的添加受管主机到一个play中,我们可以使用uri模块从CMDB中获得主机信息然后添加他们,

     它还可以将主机添加到组里面,如果组不存的话还会自动创建它。这个模块仅需要主机名和组名2个参数,跟主机库存清单的配置一样,我们还可以添加扩展的参数,像

     ansible_ssh_user,ansible_ssh_port等等

     常用参数:

     groups:添加主机至指定的组

     name:要添加的主机名或IP地址

     groups:添加主机至指定的组

     name:要添加的主机名或IP地址

     示例:

     - name: add a host to group webservers

       hosts: webservers

       tasks:

         - add_host name=` ip_from_ec2 ` group=webservers foo=42    #添加主机到webservers组中,主机的变量foo的值为42

     

  8、group_by模块

     在playbook执行的过程中,动态的创建主机组

     示例:

     - name: Create operating system group

       hosts: all

       tasks:

         - group_by: key=os_` ansible_distribution `           #在playbook中设置一个新的主机组

         

     - name: Run on CentOS hosts only

       hosts: os_CentOS

       tasks: 

         - name: Install Apache

           yum: name=httpd state=latest

            

     - name: Run on Ubuntu hosts only

       hosts: os_Ubuntu 

       tasks:

         - name: Install Apache

           apt: pkg=apache2 state=latest

       

  9、get_rul模块

     用来下载用的,当然也可以用wget

     mode:设置权限

     示例:

     - name: download foo.conf

       get_url url=http://example.com/paht/file.conf dest=/etc/foo.conf mode=0440

     

  10、debug模块

      调试模块,用于在调试中输出信息

      常用参数:

      msg:调试输出的消息

      var:将某个任务执行的输出作为变量传递给debug模块,debug会直接将其打印输出

      verbosity:debug的级别

      示例:

      # Example that prints the loopback address and gateway for each host- debug: msg="System ` inventory_hostname ` has uuid ` ansible_product_uuid `"


      - debug: msg="System ` inventory_hostname ` has gateway ` ansible_default_ipv4`.`gateway `"

        when: ansible_default_ipv4.gateway is defined


      - shell: /usr/bin/uptime

        register: result


      - debug: var=result verbosity=2    #直接将上一条指令的结果作为变量传递给var,由debug打印出result的值


      - name: Display all variables/facts known for a host

        debug: var=hostvars[inventory_hostname] verbosity=4

        

  11、fail模块

      msg:终止前打印出信息

      示例:

      - fail: msg="The system may not be provisioned according to the CMDB status."

        when: cmdb_status != "to-be-staged"

        

  12、mysql_user模块

      添加或删除一个MySQL数据库中的用户

      priv: 数据库权限设置格式`db.table:priv1,priv2' [Default:None]

      state: 删除用户absent,添加用户present,默认present

      name:   添加的新用户名字     

      password:  添加用户密码

      login_host:  密程机上运行的数据库[IP默认:本地主机]

      login_user:   远程机数据库登陆用户

      login_password:  远程机数据库登陆必码

      login_unic_socket:   远程机登陆的socket文件

      encrypted: - 加密表明“密码”字段是一个`mysql_native_password`哈希(选择:是,否)默认值:no]

      grub-crypt --sha-512 直接回车输入密码即可对密码进行加密处理

      append_privs:通过追加定义PRIV的特权到现有的这个用户,而不是覆盖现有的(选择:是,否)默认值:no]

      

      EXAMPLES:

      # Create database user with name 'bob' and password '12345' with all database privileges

        ansible all -m mysql_user -a  "login_user=root login_password=123456 name=bob password=12345 priv=*.*:ALL state=present"


      # Create database user with name 'bob' and previously hashed mysql native password '*EE0D72C1085C46C5278

        ansible all -m mysql_user -a "name=bob password='*EE0D72C1085C46C5278932678FBE2C6A782821B4' encrypted=yes priv=*.*:ALL state=present"


      # Creates database user 'bob' and password '12345' with all database privileges and 'WITH GRANT OPTION'

        ansible all -m mysql_user -a “name=bob password=12345 priv=*.*:ALL,GRANT state=present"


      # Modify user Bob to require SSL connections. Note that REQUIRESSL is a special privilege that should on

        ansible all -m mysql_user -a "name=bob append_privs=true priv=*.*:REQUIRESSL state=present"


      # Ensure no user named 'sally' exists, also passing in the auth credentials.

        ansible all -m mysql_user -a "login_user=root login_password=123456 name=sally state=absent"


      # Specify grants composed of more than one word

        ansible all -m mysql_user -a "name=replication password=12345 priv="*.*:REPLICATION CLIENT" state=present"


      # Revoke all privileges for user 'bob' and password '12345'

        ansible all -m mysql_user -a "name=bob password=12345 priv=*.*:USAGE state=present"


      # Example using login_unix_socket to connect to server

        ansible all -m mysql_user -a "name=root password=abc123 login_unix_socket=/var/run/mysqld/mysqld.sock"



【Playbook的角色及包含】

  官方网站:http://www.ansible.com.cn/docs/playbooks_roles.html

 当单个playbook文件越来越大的时候,我们就需要重新来组织Playbooks了。我们可以将一个大的playbook拆成若干个小的playbook文件,然后通过include的方式,在主配置文件中将这些零碎的小文件包含进来,这叫做playbook的包含。

 我们也可以按照一定的规则将执行的某一类型任务放在一个目录里,并在这个目录中再次对这个playbook按照tasks,handlers,files,templates,vars等类型划分成若干文件,将对应文件存放在对应的目录中,这种组织方式就叫做playbook的roles。

 在大型复杂架构中,你第一个要面对的问题就是不断增长的playbook文件大小,一个很大的playbooks很难去理解和维护,解决办法是用include.将你的plays分解成我个不同的段,然后

 在其他的plays中包含他们。不同的段根据不同目的地分类,全部包启在play中,共有四种类型的包含。

     1)变量包含:允许你将变量存在外部YAML文件

     2)Playbook包含:一个大型项目中可以我含多个Play

     3)任务包含:将任务放到普通文件中,当需要的时候包含他们

     4)Handler包含:允许你将所有的Handlers处理程序放到一个地方

     

     一、Playbook包含

     playbook的包含其实就是使用include关键字 

     [任务包含]

     示例1:

     在bar.yml的tasks中包含foo.yml

     tasks:

       - include: tasks/foo.yml

       

     cat foo.yml

     # possibly saved as tasks/foo.yml

     - name: placeholder foo

       command: /bin/foo

     - name: placeholder bar

       command: /bin/bar

     

     示例2:

     [root@Master opt]# cat main.yml 

      ---

      - hosts: all

        tasks:

      - name: stop mysqld

        service: name=mysqld state=stopped

      - include: test.yml

     

     [root@Master opt]# cat test.yml 

      - name: stop httpd 

        service: name=httpd state=stoppe

     

     [Playbook包启]

     示例1:

     也可以在include的时候,带入变量:

     tasks:

     - include: wordpress.yml user=timmy   #表示包含的文件执行用户为timmy

     - include: wordpress.yml user=alice   #表示包含的文件执行用户为alice

     - include: wordpress.yml user=bob     #表示包含的文件执行用户为bob

     

     示例2:

     [root@Master opt]# cat main.yml 

     ---

     - hosts: all

       tasks:

     - name: stop mysqld

       service: name=mysqld state=stopped

     - include: test.yml

     

     [root@Master opt]# cat test.yml 

     ---

     - hosts: all

       tasks:

     - name: stop httpd 

       service: name=httpd state=stoppe

     

     

     [变量包含]

     示例1:

     如果你使用的是 Ansible 1.4以上版本(包括1.4),可以通过如下方式带入变量:

     tasks:

     - { include: wordpress.yml, user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] }  #表示包含的文件的文件带入user和ssh_keys两个变量

 

     示例2:

     从1.0开始, ansible 还支持另外一种变量传参到 include files 的方式-结构化变量,方式如下:

     tasks:

       - include: wordpress.yml

     vars:

         wp_user: timmy

         ssh_keys:

           - keys/one.txt

           - keys/two.txt

      

     变量传递均可以在 included 文件中被使用.你可以这样引用他们:

     ` wp_user ` `ssh_keys`

     

     [handlers包含]

     handlers包含与tasks的包含大体类似

     示例1:

     - name: restart apache

       service: name=apache state=restarted

       

       handlers.yml包含handlers1.yml示例:

       handlers:

         - include: handlers/handlers.yml

       

     [混合包含]

      示例:

        cat include.yml

        ---

        - hosts: mfs_node

          vars_files:

             - vars.yml               #变量包含,包含vars.yml文件

             - vars1.yml              #变量包含,包含vars1.yml文件

          tasks:

            - include: task.yml       #任务包启,包含task.yml文件

            

          handlers:

            - include: handler.yml    #handlers包启,包含handler.yml文件


        #cat vars.yml

        port: 80

        

        #cat vars1.yml

        port2: 8080

        

        #cat task.yml

        ---

        - name: print vars

          shell: echo"` port `" > /tmp/test

          notify: touch a file

        

        #cat handler.yml

        ---

        - name: touch a file

          shell: echo "` port2 `" > /tmp/file

        

        anslbie-playbook include.yml

   

   二、Playbook的角色

      官方文档:http://www.ansible.com.cn/docs/playbooks_best_practices.html

          如果你的playbook增长到包含也无法解决,或者你已拥有一个数量巨大的模板,你或就该使用角色了,它允许你根据自定义的格式对文件进行分组,从本质上来讲,

       它是一个具有一些自动化功能的包含,角色可以帮你很好的组织你的资料库    

          角色允许你将变量、文件、任务、模板Handlers放到一个文件夹中,然后包含他们,在建立好一个有效的依赖关系之后,你还可以在一个角色中包含另外一个角色,

       和包含一样,你可以传递变量给角色。利用这些特性,你可以创建一个自包含的角色并很容易跟其它人分享它。

      

      1、创建role

         创建role的步骤如下:

         1)创建以roles命令的目录

         2)在roles目录中分别创建角色名称命名的目录,如websrvs等

         3)在每个角色命名的目录中分别创建files、handlers、meta、tasks、teamplates和vars目录,用不到的目录可以创建为空目录,也可以不创建。

         4)在playbook文件中,调用各角色

      通过ansible-galaxy初始化一个roles的目录结构,方法如下:

      ansible-galaxy init /etc/ansible/roles/websrvs

     

      roles文件组织结构示例:

      group_vas/

      host_vars/

      site.yml

      webservers.yml

      dbserver.yml

      roles/

         common/

           files/

           templates/

           tasks/

           handlers/

           vars/

           defaults/

           meta/

         webservers/

           files/

           templates/

           tasks/

           handlers/

           vars/

           defaults/

           meta/

         dbservers/

           files/

           templates/

           tasks/

           handlers/

           vars/

           defaults/

           meta/


     roles各目录的作用及可用的文件:

     files:存放由copy或script等模块调用的文件

     tempaltes:Jinja2模板文件

     tasks:至少应该包含一个名为main.yml的文件,其定义了此角色的任务列表,些文件可以使用include包含其它的位于此目录中的task文件

     handlers:至少包含一个main.yml文件,用于定义此角色用到的各handler,在handler中使用include包含的其他handler文件也应该位于此目录

     vars:应当包含一个main.yml文件,用于定义此角色用到的变量

     meta:应当包含一个main.yml文件,用于定义此角色的特殊设定及依赖关系等

     default:为当前角色设定默认变量时使用些目录,包含一个main.yml文件

     site.yml: 主playbook

     webserver.yml web服务器的playbook

     dbserver.yml  db服务器的playbook

     /etc/ansible/host_vars/all #host_vars 目录用于存放host 变量,all 文件对所有主机有效

     /etc/ansible/group_vars/all #group_vars 目录用于存放group 变量,all 文件对所有组有效

     注:group_varst和host_vars变量目录要与hosts主机清单文件在同一目录下

     

     引用示例:

     ---

     # file: site.yml

     - include: webservers.yml

     - include: dbservers.yml

     

     # file: webservers.yml

     - hosts: webservers

       roles:

         - common

         - webserver

    

     # file: dbservers.yml

     - hosts: dbserver

       roles:

         - common

         - dbserver

         

   2、引用roles

      基本引用的方法:

      - hosts: webservers

        roles:

           - common

           - webserver

           

   3、也可以通过如下方法引用时带入变量:

      - hosts: webservers

        roles:

          - common

          - { role: foo_app_instance, dir: '/opt/a',  port: 5000 }

          - { role: foo_app_instance, dir: '/opt/b',  port: 5001 }

          

   4、还可以在引用时使用条件语句:

      - hosts: webservers

        roles:

          - { role: some_role, when: "ansible_os_family == 'RedHat'" }

    

   5、pre_tasks和post_tasks

      如果在执行一个role时,需要在其前或其后依然要执行某些任务,我们可以使用pre_tasks及post_tasks来声明。pre_tasks是在role之前执行,而post_tasks则在role之后执行:

      - name: deply webservers

        host: webservers

        vars_files:

          - secrets.yml

        pre_tasks:

          - name: update yum cache

            yum: update_cache=yes

        roles:

          - role: apache

            database_host: ` hostvars`.`db`.`ansible_eth0`.`ipv4`.`address `

            domains:

              - exampel.com

              - www.example.com

        post_tasks:

          - name: print something

            shell: echo "The roles have been updated!"


      6、role的依赖

         如果当前role在执行前需要依赖另一个role,我们可以在roles的meta目录中的main.yml中定义role的依赖关系。

         示例1:

         #roles/webservers/meta/main.yml

         dependencies:

         - { role: common, some_parameter: 3 }

         - { role: apache, port: 80 }

         - { role: postgres, dbname: blarg, other_parameter: 12 }


         示例2:

         dependencies:

         - {role: ntp, ntp_server=ntp.ubuntu.com}

         - {role: web}

         - {role: memcached}


      完整示例:

           [root@Master ansible]# tree

           .

          ├── ansible.cfg

          ├── hosts

          ├── playbook

          │   └── lamp

          │       ├── lamp.yml

          │       └── roles

          │           ├── common

          │           │   ├── files

          │           │   │   └── hosts

          │           │   ├── handlers

          │           │   └── tasks

          │           │       └── main.yml

          │           ├── db

          │           │   ├── files

          │           │   ├── handlers

          │           │   └── tasks

          │           │       └── main.yml

          │           └── web

          │               ├── files

          │               ├── handlers

          │               │   └── main.yml

          │               └── tasks

          │                   ├── include.yml

          │                   └── main.yml

          └── roles

        

        [root@Master lamp]# cat lamp.yml 

         ---

         - hosts: all

           roles:

             - role: common


         - hosts: wsyht

           roles:

             - role: web


         - hosts: peter

           roles:

             - role: db   

         

         [root@Master tasks]# pwd

          /etc/ansible/playbook/lamp/roles/web/tasks

         [root@Master tasks]# ls

          include.yml  main.yml

         [root@Master tasks]# cat main.yml    

          - name: start vsftpd 

            service: name=vsftpd state=started

            notify:

           - copy passwd

           - include: include.yml

         [root@Master tasks]# cat include.yml 

          - name: mysqld started

           service: name=mysqld state=started

         

         [root@Master handlers]# pwd

         /etc/ansible/playbook/lamp/roles/web/handlers

         [root@Master handlers]# ls

          main.yml

         [root@Master handlers]# cat main.yml 

          - name: copy passwd

            copy: src=passwd dest=/opt/passwd 

            

         [root@Master files]# pwd

          /etc/ansible/playbook/lamp/roles/web/files

         [root@Master files]# ls

          passwd

【Playbook的变量】

 官方网站:http://www.ansible.com.cn/docs/playbooks_variables.html

 通过以下几种方式可以获取变量

 1、Variables Defined in Inventory  看word文档

 2、Variables Defined in a Playbook

 3、Variables Defined i Commandline

 4、Registered Variables  

 5、Variables defined from included files and roles  看word文档

 6、Using Variables: About Jinja2

 7、Facts  查看word文档


 1、 通过命令行设置变量  [Variables Defined i Commandline]

     示例如下:

     ---

     - hosts: mfs_node

       remote_user: '` user `'

       tasks:

     -  shell: echo "`echovar`"

     ansible-playbook release.yml --e 'user=root echovar="hello world"' 法1

     ansible-playbook release.yml --e '{{"user":"root","echovar":"hello world"}}' 法2

     ansible-playbook release.yml --e '@test.json' 法3 把所有变量定义到一个文件去

     

     cat test.json

     user: root

     echovar: hellow world

     

 2、Playbook中定义变量  [Variables Defined in a Playbook]  

   [vars变量]

   这里指定一个user变量,其值为test ,需要注意的是,变量值一定要用引号引住;

   # cat user.yml

   - name: create user

     hosts: all

     user: root

     gather_facts: false

     vars:

       user: "test"

     tasks:

       - name: create  user

         user: name="` user `" state=absent remove=yes

   

   [vars_files变量]

      指定变量文件

   #cat test.yml

    ---

    - hosts: all

      user: root

      vars_files:

        - variables

      tasks:

        -name: print ip

         template: scr=files/test.txt /dest=/tmp/test.txt

   

   # cat file/test.txt

     `http`

     `port`}

         

   #cat variables

    port: 80

    httpd: nginx

   

   [vars_prompt变量]

       交互式输入变量

   cat test1.yml

   ---

   - hosts: all

     vars_prompt:

       - name: http

         prompt: please enter something

         private: yes

     tasks:

       - name: just a test

         template: scr=files/test1.txt /dest=/tmp/test1.txt

         

    #cat files/test.txt

     `http`}

     

   #private设为yes不会在屏幕打印输出,

   

   3、通过Registered Variables设置变量

      - hosts: mfs_node

        tasks:

          - shell: echo "5"

            register: result        #把上面输出5的值保存在result这个变量中,以便后续可以对他进行处理

            ignore_errors: True     #有错误就跳过

            

          - debug: msg="it failed"   #上面失败打印这行

            when: result|failed      #如果上面的结果失败,则执行上面那一行

            

          - debug: msg="{{result|stdout}}"   #打印出result的值,上面输出的是5,所以会打印5出来

          

          - shell: /usr/bin/bar    #如果rc等于5,则输出这行

            when: result.rc == 5   #如果rc等于5,则输出上面那一行

   

   4、Using Variables: About Jinja2 使有金加2定义变量 

      template: src=foo.cnf.j2 dest=`remote_install_path`/foo.cfg

      {{some_variable | default(5)}}  #前面的变量不存在,则输入后面的默认的

   

   注:变量花括号括住,且要加双引号

   - hosts: all

       vars:

         app_path: "`base_path`/22"



【Playbook的内置变量】        

 最常用

 hostvars

 groups

 group_names

 

 1、hostvars示例:

 - name: get the master ip

   set_fact: dns_master="`hostvars`.`ns1`.`ansible_default_ipv4`.`address`" #ns1为那台主机的主机名

   

  - name: configuree bind

    template: dest=/etc/named.conf src=templates/named.conf.j2

    

 案例1:

 cat hostvars.myml

 ---

 - hosts: mfs

   tasks:

     - name : just a test

       template: src=files/hostvars.txt dest=/tmp/hostvars.txt

 

 cat files/hostvars.txt

 `hostvars`.`puppet_master`.`ansible_default_ipv4`.`address`   #第一种写法.puppet_master为主机名,不能解析则在hosts文件中做解析,主机名只能用下载线,不能用-

 

 ansible-playbook hostvars.yml

 

 2、groups示例:

 - name: create user for all app servers

   with_items: groups.appservers #groups是指所有所,指所有组中的appservers这个组

   mysql_user: name=kate password=test

   host={{}hostvars.[item].ansible_eth0ipv4.address} state=present #取每一台主机的IP地址

   

   {{% for host in groups['all'] %}}  #取所有主机都赋值为host

   {{hostvars[host]['ansible_hostname']}}  #打印所有主机的主机名

   {{hostvars[host]['ansible_ssh_host_key_rsa_public']}}  #打印所有主机的公钥

   ` endfor ` #结束

   

 3、group_names示例:

 - name: For secure machines

   set_fact: sshconfig=files/ssh/sshd_config_secure

   when:"secure'in group_names"  #secure是指主机组,group_names是指远程主机所属的主机组的名字,意思说secure在远程的这台主机的主机组埯面就执行上面那一排命令

   

 - name: For non-secure machines

   set_fact: sshconfig=files/ssh/sshd_config_default 

   when: "'secure' not in group_names"   #意思说secure不在远程的这台主机的主机组埯面就执行上面那一排命令

 

 

 不常用

 inventory_hostname  #保存了设备配置清单中服务器的主机名

 inventory_hostname_short #跟invertory_hostname一样,只是去掉域名,比如invertory_hostname是host.example,那么inverntory_hostname_shor就是host

 inventory_dir  #是设备清单文件的路径

 invertory_file  #设备清单文件的文件名


 示例:

 cat inventory.yml

 ---

 - hosts: all

  tasks:

    - name: copy test file

      template: src=file/inventory_hostname.conf.j2 dest=/tmp

  

  cat file/inventory_hostname.conf.j2

  {{ inventory_hostname  }}

  ` inventory_hostname_short `

  ` inventory_dir `

  ` invertory_file `

   

  cat /tmp/inventory_hostname.conf.j2

  172,16.5.202

  172

  /etc/ansible

  /etc/ansible/hosts

      

【Playbook的条件判断】

 官网参考:http://www.ansible.com.cn/docs/playbooks_error_handling.html

  通过ansible-playbook实现对多台主机同时同时安装apache。需要注意的是,多台被管理主机的操作系统可能不相同,而导致apache包名不同,假设同时存在CentOS和Debian两种操作系统,具体playbook内容如下

  案例1:

  # cat install_apache.yml

    - hosts: all

      remote_user: root

      gather_facts:True

      tasks:

        - name: install apache on CentOS

          yum: name=httpd state=present

          when: ansible_os_family =="CentOS" 

        - name: install apache on Debian

          yum: name=apache2 state=present

          when: ansible_os_family =="Debian"

  案例2:

  tasks:

  - command: /bin/false

    register: result          #把上面命令执行的结果交给result

    ignore_errors: True       #如果有错误,都忽略掉,后面继续执行,不忽略错误,遇到错误,就无法再往下走

  - command: /bin/something

    when: result|failed       #如果result执行失败就执行上面那一行

  - command: /bin/something_else

    when: result|success      #如果result执行成功就执行上面那一行

  - command: /bin/still/something_else

    when: result|skipped      #如果result执行装态为skipped就执行上面那一行

  

  案例3:

  vars:

    epic: true

    

  tasks:

    - shell: echo "This certainly isn't epic!"

      when: epid #如果epid为true时,就执行上面那一段

       

  案例4:     

  tasks:

     - shell: echo "I've got '` foo `' and am not afraid to use it!"

       when: foo is defined   #如果foo没有定义,就执行上面一段


     - fail: msg="Bailing out. this play requires 'bar'"

       when: bar is not defined;  #如果bar没有定义就打印上面那一行

    

  案例5:

  tasks:

    - command: echo ` item `

      with_items: [ 0, 2, 4, 6, 8, 10 ]

      when: item > 5   #如果item大于5,就输出那位数字,这里输出6,8,10

      

  案例6:

  - hosts: webservers

    roles:

        - { role: debian_stock_config, when: ansible_os_family == 'Debian' }  #当客户端是Debian的时候,就运行debian_stock_config这个角色

        - { role: centos_stock_config, when: ansible_os_family == 'Redhat' }  #当客户端是centos的时候,就运行centos_stock_config这个角色

     

  案例7:

  - name: test play

    hosts: mfs

    tasks:

      - shell: cat /etc/motd

       register: motd_contents   #把上面输执行的结果交给motd_conters这个变量

          

      - shell: echo "mothd contains the word hi" > /tmp/test2

        when: motd_contents.stdout.find('hi')!=1   #标准输出里面查找有没有hi,如果有就执行上面那一行echo

           

  register三种输出方式

  motd_contents.stdout   #标准输出

  motd_contents.stderr   #标准错误

  motd_contents.rc   #输出值,默认正确是0

     

  案例8: 不常用

  tasks:

    - shell: /usr/bin/billybass -mode="take me to the river"

      register: bass_result

      changed_when: "bass_result.rc!=2" #如果rc不等于2就不执行上面那两段

      

   #this will never report 'changed' status

   - shell: wall 'beep'

     changed_when: False

     

  安例9:不常用

  - name: this command prints FAILED when it fails

    command: /usr/bin/example-command -x -y -z

    register: command_result

    failed_when: "FAILED" in command_result.stderr"  如果错误输出有FAILED则执行失败,终端输出则会有change=1字样

    

   - name: this command prints FAILED when it fails

     command: /usr/bin/example-command -x -y -z

     register: command_result  #rgister到一个变量去

     innore_errors: True   #忽略错误

     

   - name: this command prints FAILED when it fails

     fail: msg="the command failed"   #通过fail模块打印一行输出

     when: "FAILED" in command_result.stderr"   #当打印的错误输出包含FAILED时,则打印上面那一行输出

     

 【循环】

  参考中文官网:http://www.ansible.com.cn/docs/playbooks_loops.html#indexed-lists

  - name: touch files

    file: dest=`item`.`path` state=touch mode={{item.mode|default(0755)}}

    with_items

      - path: /tmp/foo   #循环创建foo、bar、baz这三个文件

      - path: /tmp/bar   

      - path: /tmp/baz   

        mode: "0444"     baz给0444权限,foo和bar不给0444权限,就会给出设定的默认0755权限

    

    标准循环

    示例1:标准循环with_items

    - name: add several users

      user: name=` item ` state=present groups=wheel

      with_items:

         - testuser1

         - testuser2


    也可以通过vars 选项定义循环

    ---

    - hosts: all

      user: root

      vars:

        - somelist: [1,2,3,4,5,6]      #左边变量名,右边一个又一个的变量值

      tasks:

        - name: lists

          shell: /bin/echo ` item ` >> /opt/test.txt

          with_items: somelist   #引用变量名,拿出一个一个值,赋值给item

          

     或者使用vars_files 引入变量文件的形式定义使用循环

     [root@Master opt]# cat a.yml 

     ---

     - hosts: all

       user: root

       vars_files:

         - somelist.txt

       #vars:

       #  - somelist: [1,2,3,4,5,6]   左边

       tasks:

         - name: lists

           shell: /bin/echo ` item ` >> /opt/varfile.txt

           with_items: somelist  #引用变量名,拿出一个一个值,赋值给item

     [root@Master opt]# cat somelist.txt   #变量文件

     somelist: [1,2,3,4,5,6]    #左边变量名,右边一个又一个的变量值

     同样我们在使用yum 或者apt 安装多个软件包时也可以使用with_items

     

     如果是散列的列表可以这样使用:

     - name: add several users

       user: name=` item`.`name ` state=present groups=` item`.`groups `

       with_items:

         - { name: 'testuser1', groups: 'wheel' }

         - { name: 'testuser2', groups: 'root' }

      

      请note使用 ‘with_items’ 用于迭代的条目类型不仅仅支持简单的字符串列表.如果你有一个哈希列表,那么你可以用以下方式来引用子项:

      - name: add several users

        user: name=` item`.`name ` state=present groups=` item`.`groups `

        with_items:

          - { name: 'testuser1', groups: 'wheel' }

          - { name: 'testuser2', groups: 'root' }

      

      嵌套循环

      示例2:嵌套循环with_nested

      将多个库授权给多个用户select 权限,具体mysql_user 模块的使用方法参考:

      - name: give users access to multiple databases

       mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo

       with_nested:

         - [ 'alice', 'bob' ]

         - [ 'clientdb', 'employeedb', 'providerdb' ]

         

       或者可以通过引用之前定义的变量文件形式使用:

       - hosts: 192.168.0.4

         remote_user: root

         vars:

           user: "test"

         tasks:

           - name: here, 'users' contains the above list of employees

             mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo

             with_neste:

               - "`users`"

               - [ 'clientdb', 'employeedb', 'providerdb' ]

        

        对哈希表使用循环

        示例3:遍历字典with_dict

        [root@Master opt]# cat users.yml 

        ---

        users:

          alice:

            name: Alice Appleworth

            telephone: 123-456-7890

          bob:

            name: Bob Bananarama

            telephone: 987-654-3210

        [root@Master opt]# cat dict_playbook.yml 

        ---

        - hosts: all

          user: root

          vars_files: 

            - users.yml

          tasks:

            - name: Print phone records

              debug: msg="User ` item`.`key ` is ` item`.`value`.`name ` (` item`.`value`.`telephone `)"

              with_dict: "`users`"

              

         对文件列表使用循环     

         示例4:使用with_fileglob 遍历文件(不递归、对目录无效)with_fileglob

         将/root/geekwolf/目录下所有的文件复制到/tmp/fooapp/

         ---

         - hosts: 192.168.0.4

           remote_user: root

           tasks:

         #确保目的目录存在

         - file: dest=/tmp/fooapp state=directory

         - copy: src=` item ` dest=/tmp/fooapp/ owner=root mode=600

           with_fileglob:

         - /root/geekwolf/*

         

         对并行数据集使用循环

         示例5:使用with_together 来并行遍历两个列表

         vim list_test.yml

         ---

         alpha: [ 'a', 'b', 'c', 'd' ]

         numbers: [ 1, 2, 3, 4 ,5]

         假如我们想要[‘a’,1] [‘b’,2] ...[None,6]可以这样实现:

         vim list_test.yml

         ---

         alpha: ['a','b','c','d']

         numbers: [1,2,3,4,5,6]

         vim list_playbook.yml

         ---

         - hosts: 192.168.0.4

           remote_user: root

           vars_files:

         - list_test.yml

           tasks:

         - debug: msg="` item`.`0 ` and ` item`.`1 `"

           with_together:

         - alpha

         - numbers

         

         示例6:循环子元素with_subelements

         创建用户alice 和bob,为alice 配置两把公钥到alice 用户下的authorized_keys 文件,为bob 配置一

         把公钥使得两个用户通过客户端私钥登陆,其中onekey.pub twokey.pub id_rsa.pub 表示已经创建好的公钥

         vim subusers.yml

         ---

         users:

           - name: alice

             authorized:

               - /tmp/alice/onekey.pub

               - /tmp/alice/twokey.pub

           - name: bob

             authorized:

               - /tmp/bob/id_rsa.pub

               

         vim sub_playbook.yml

         ---

         - hosts: 192.168.0.4

           vars_files:

             - subuser.yml

           tasks:

             - user: name=` item`.`name ` state=present generate_ssh_key=yes

               with_items: "`users`"

             - authorized_key: "user=` item`.`0`.`name ` key='{{ lookup('file', item.1) }}'"

                with_subelements:

                  - users

                  - authorized

               

        示例2:根据mysql hosts以及预先给定的privs subkey列表,我们也可以在嵌套的subkey中迭代列表:        

        vim subusers.yml

        ---

        users:

          - user: peter

          - mysql:

              password: mysql-password

              privs: 

                - "*.*:SELECT"

                - "DB1.*:ALL"

              mysql.hosts:

                - "192.168.1.215"


         - user: jack 

         - mysql:

              password: other-mysql-password

              privs:

                - "*.*:SELECT"

                - "DB2.*:ALL"

              mysql.hosts:

                - "192.168.1.216"


           [root@Master opt]# cat sub.yml

           ---

           - hosts: all

             user: root

             vars_files:

               - subuser.yml                                                                     

             tasks:

               - name: Setup MySQL users

                 mysql_user: login_user=root login_password=123456 

                             name=` item`.`0`.`user ` password=` item`.`0`.`mysql`.`password `

                             host=` item`.`1 ` priv={{ item.0.mysql.privs | join('/') }}

                 with_subelements:

                   -  users 

                   -  mysql.hosts

                 

         详细参考:

         authorized_key 模块:http://docs.ansible.com/authorized_key_module.html

         look_plugins 插件讲解:http://rfyiamcool.blog.51cto.com/1030776/1441451

         

         对整数序列使用循环

         with_sequence 可以以升序数字顺序生成一组序列.你可以指定起始值、终止值,以及一个可选的步长值.

         指定参数时也可以使用key=value这种键值对的方式.如果采用这种方式,’format’是一个可打印的字符串.

         数字值可以被指定为10进制,16进制(0x3f8)或者八进制(0600).负数则不受支持.请看以下示例:

         示例 7:在序列中循环 with_sequence

         ---

         - hosts: all


           tasks:

 

             # 创建用户组

             - group: name=evens state=present

             - group: name=odds state=present


             # 创建格式为 testuser%02x 的 0-32 序列的用户,%02x中的x代表十六进制数,02代表前面不足两位补0,执行语句后会创建用户testuser01,testuser02,testuser03...

             - user: name=` item ` state=present groups=evens

               with_sequence: start=0 end=32 format=testuser%02x


             # 创建目录:起始位 4,末尾是 16,步长为 2 命名的目录

             - file: dest=/var/stuff/` item ` state=directory

               with_sequence: start=4 end=16 stride=2


             # 简单实用序列的方法:创建 4 个用户组分表是组 group1 group2 group3 group4

             # create 4 groups

             - group: name=group` item ` state=present

               with_sequence: count=4

         

         随机选择 with_random_choice

         提供的字符串中的其中一个会被随机选中.

         ‘random_choice’功能可以用来随机获取一些值.它并不是负载均衡器(已经有相关的模块了).它有时可以用作一个简化版的负载均衡器,比如作为条件判断:

         [root@Master opt]# cat random.yml 

          ---

          - hosts: all

            user: root

            tasks:

              - debug: msg=` item `

                with_random_choice:

                  - "go through the door"

                  - "drink from the goblet"

                  - "press the red button"

                  - "do nothing"

         

        Do-Until循环

        示例 9:until 循环 until

        有时你想重试一个任务直到达到某个条件.比如下面这个例子:

         ---

         - hosts: all

           user: root

           tasks:

             - action: shell /usr/bin/foo

               register: result

               until: result.stdout.find("all systems go") != -1

               retries: 5

               delay:

        上面的例子 shell 模块会一直执行直到模块结果输出有”all systems go” 或者每个 10s 重试 5 次后结束;默认是每个 5s 重复 3 次;执行 playbook 时加上-vv 参数可以查看详细过程

        

        示例 10:打印列表索引 with_indexed_items

        如果你想循环一个列表,同时得到一个数字索引来标明你当前处于列表什么位置,那么你可以这样做.虽然该方法不太常用:

        [root@Master opt]# cat index.yml 

        ---

        - hosts: wsyht

          user: root

          tasks:

            - name: indexed loop demo

              debug: msg="at array position ` item`.`0 ` there is a value ` item`.`1 `"

              with_indexed_items: ['a','b','c','d','e'] 

        

        扁平化列表

        示例11:整合列表with_flattened

        如果定义了多个列表,遍历多个列表项

        [root@Master opt]# cat list.yml 

        ---

        - hosts: all

          user: root

          vars:

            packages_base:

              - [ 'vsftpd', 'docker' ]

           #packages_apps:

            # - [ ['one-package', 'two-package' ]]

            # - [ ['red-package'], ['blue-package']]

          tasks:

            - name: flattened loop demo

              yum: name=` item ` state=latest    #安装两个列表中的所有包

              with_flattened:

                - "` packages_base `"     

              # - "` packages_apps `"

        

        

  【tags标签功能】

   如果你有一个大型的 playbook,那能够只运行其中特定部分的配置而无需运行整个 playbook 将会很有用.

   例:

   tasks:


    - yum: name=` item ` state=installed

      with_items:

         - httpd

         - memcached

      tags:

         - packages


    - template: src=templates/src.j2 dest=/etc/foo.conf

      tags:

         - configuration

         

    如果你只想运行一个非常大的 playbook 中的 “configuration” 和 “packages”,你可以这样做:

    ansible-playbook example.yml --tags "configuration,packages"

   

    另一方面,如果你只想执行 playbook 中某个特定任务 之外 的所有任务,你可以这样做:

    ansible-playbook example.yml --skip-tags "notification"

    

   【异步操作和轮询】

    为了异步启动一个任务,可以指定其最大超时时间以及轮询其状态的频率.如果你没有为 poll 指定值,那么默认的轮询频率是10秒钟:

    async 并没有默认值,如果你没有指定 async 关键字,那么任务会以同步的方式运行,这是Ansible的默认行为.

    另外,如果你不需要等待任务执行完毕,你可以指定 poll 值为0而启用 “启动并忽略”

    ---


    - hosts: all

      remote_user: root


      tasks:


      - name: simulate long running op, allow to run for 45 sec, fire and forget

        command: /bin/sleep 15

        async: 45    #async没有默认值,给他指定关健字,执行异步操作

        poll: 0  #不等待,直接开始异步

    

    【加速模式详解】

     加速模式只是使用来加速连接的,它仍需使用 SSH 来进行初始安全密钥交换.它没有额外增加需要管理的基础设施的公共key,也不需要诸如 NTP 或 DNS.

     只需在你的 play 中添加 accelerate: true 即可使用加速模式:

     ---


     - hosts: all

       accelerate: true


       tasks:


     - name: some task

       command: echo ` item `

       with_items:

     - foo

     - bar

     - baz

     

   如果你希望改变 Ansible 用于加速模式的端口,你只需添加 accelerated_port 选项:

   ---


   - hosts: all

     accelerate: true

     # default port is 5099

     accelerate_port: 10000

   

  【Vault加密功能】  

   Ansible 1.5的新版本中, “Vault” 作为 ansible 的一项新功能可将例如passwords,keys等敏感数据文件进行加密,而非存放在明文的 playbooks 或 roles 中. 这些 vault 文件可以分散存放也可以集中存放.

   vault 可以加密任何 Ansible 使用的结构化数据文件. 甚至可以包括 “group_vars/” 或 “host_vars/” inventory 变量, “include_vars” 或 “vars_files” 加载的变量, 通过 ansible-playbook 命令行使用 “-e @file.yml” 或 “-e @file.json” 命令传输的变量文件. Role 变量和所有默认的变量都可以被 vault 加密.

   因为 Ansible tasks, handlers等都是数据文件, 所有的这些均可以被 vault 加密. 如果你不喜欢你使用的变量被泄漏,你可以将整个 task 文件部分加密. 然后,这个工作量比较大而且可能给你的同事带来不便哦 :)

   

   创建加密文件

   ansible-vault create foo.yml

   首先你将被提示输出密码, 经过Vault加密过的文件如需查看需同时输入密码后才能进行.

   提供密码后, 工具将加载你定义的 $EDITOR 的编辑工具默认是 vim, 一旦你关闭了编辑会话框,生成后的文件将会是加密文件.

   默认加密方式是 AES (基于共享密钥)

   

   Editing加密文件

   编辑加密文件,使用 ansible-vault edit . 该命令会先加密文件为临时文件并允许你编辑这个文件,当完成编辑后会保存回你所命名的文件并删除临时文件:

   ansible-vault edit foo.yml

   

   密钥更新加密文件

   如果你希望变更密码,使用如下 命令:

   ansible-vault rekey foo.yml bar.yml baz.yml

   如上命令可以同时批量修改多个文件的组织密码并重新设置新密码.

   

   加密普通文件

   如果你希望加密一个已经存在的文件,使用 ansible-vault encrypt . 该命令也可同时批量操作多个文件:

   ansible-vault encrypt foo.yml bar.yml baz.yml

  

  解密已加密文件

  如果不希望继续加密一个已经加密过的文件,通过 ansible-vault decrypt 你可以永久解密. 命令将解密并保存到硬盘上,这样你不用再使用 ansible-vault edit 来编辑文件了:

  ansible-vault decrypt foo.yml bar.yml baz.yml

  

  查阅已加密文件

  如果你不希望通过编辑的方式来查看文件, ansible-vault view 可以满足你的需要:

  ansible-vault view foo.yml bar.yml baz.yml

  

  在Vault下运行Playbook

  执行 vault 加密后的playbook文件,最少需要提交如下两个标志之一. 交互式的指定 vault 的密码文件:

  ansible-playbook site.yml --ask-vault-pass

  该提示被用来解密(仅在内存中)任何 vault 加密访问过的文件. 目前这些文件中所有的指令请求将被使用相同的密码加密.

  

  另外,密码也可以定义在一个文件或者一个脚本中,但是需要 Ansible 1.7 以上的版本才能支持. 当使用该功能时,一定要确认密码文件的权限是安全的以确保没有人可以随意访问或者变更密码文件:

  ansible-playbook site.yml --vault-password-file ~/.vault_pass.txt

  ansible-playbook site.yml --vault-password-file ~/.vault_pass.py

  密码存储一行一个

  如果你使用的是脚本而不是普通文件,确保脚本是可执行的,这样密码可以输出至标准设备.如果你的脚本需要提示输入数据,那提示可以被发送到标准错误.

  如果你是从持续集成系统(例如Jenkins)中使用 Ansible 的话上面的这种情况你会用的到.