自动化运维工具ansible安装及使用,自动化运维ansible


一、ansible介绍

ansible是个什么东西呢?官方的title是“Ansible is Simple IT Automation”——简单的自动化IT运维管理工具。这个工具的目标有这么几项:让我们自动化部署APP;自动化管理配置项;自动化的持续交付;自动化的(AWS)云服务管理。基于Python开发,可实现对多台服务器进行批量配置、程序的部署及指令的运行。大大减少了在运维工程中的工作量。

ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括:

(1)、连接插件connection plugins:负责和被监控端实现通信;

(2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;

(3)、各种模块核心模块、command模块、自定义模块;

(4)、借助于插件完成记录日志邮件等功能;

(5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。

Ansible 在管理节点将 Ansible 模块通过 SSH 协议(或者 Kerberos、LDAP)推送到被管理端执行,执行完之后自动删除,可以使用 SVN 等来管理自定义模块及编排

Ansible 的组成由 5 个部分组成:

Ansible:核心

Modules:包括 Ansible 自带的核心模块及自定义模块

Plugins:完成模块功能的补充,包括连接插件、邮件插件等

Playbooks:网上很多翻译为剧本,个人觉得理解为编排更为合理;定义 Ansible 多任务配置文件,有 Ansible 自动执行

Inventory:定义 Ansible 管理主机的清单

优点
(1)、轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
(2)、批量任务执行可以写成脚本,而且不用分发到远程就可以执行;
(3)、使用python编写,维护更简单,ruby语法过于复杂;
(4)、支持sudo。


   常见的运维工具的工作模式有两种agent和agentless。ansible属于后者,即在被控制端没有代理运行。ansible基于ssh实现信息的传输,且在运行过程中具有幂等性(同一个操作执行多次,结果相同,不会重复执行)

ansible的简单应用

  默认情况下,Ansible1.2 之前的版本,需要加参数-c 显式指定;Ansible1.3+版本默认使用Openssh 来远程连接主机,并开启 ControlPersist 来优化连接速度和认证;

如果使用 RHEL6 系作为 Ansible 控制端,由于 OpenSSH 版本太老无法支持 ControlPersist,这时候 Ansible 将会使用高效的 Python 实现的 OpenSSH 即 paramiko

若果想使用原生的 OpenSSH 连接被控端,需要升级OpenSSH 到 5.6+或者选择 Ansible 的加速模式针对不支持 ControlPersist 的系统如 RHEL6 可以通过使用 Ansible 加速模式或者 SSH pipelining( pipelining=on )进行优化来提高连接速度

Ansible 加速模式支持 RHEL6 控制端和其他受限的环境

加速模式使用方法:

在定义的 playbooks 里面添加 accelerate: true 参数

---
- hosts: all
accelerate: true
tasks:
- name: some task
command: echo {{ item }}
with_items:
- foo
- bar
- baz


更改 Ansible 用于加速连接的端口,使用参数 accelerate_port,端口配置可以设置系统环境变量ACCELERATE_PORT或者修改 ansible.cfg 配置文件,accelerate_multi_key允许使用多把密钥

[accelerate]
accelerate_port = 5099
---
- hosts: all
accelerate: true
# default port is 5099
accelerate_port: 10000
accelerate_multi_key = yes


注释:Ansible 加速模式支持 sudo 操作,但需要注释 /etc/sudoers #Defaults requiretty;


sudo 密码还未支持,所以 sudo 执行需要 NOPASSWD


官方鼓励使用 SSH Keys,也可以通过参数--ask-pass 及--ask-sudo-pass 使用密码


真正实现批量部署的是ansible中的模块,常用的模块有command,user,copy,cron,file,ping,yum,service,shell,script......

命令格式:ansible [-m module] [-a args]

host-pattern     # 目标主机的地址,一般是配置文件中的组名

-m module       # 指定应用的模块

-a  args            # 指定模块的参数

ansible-doc -l          # 查看所有可用的模块

ansible-doc moduleName     # 查看指定模块的帮助信息



1.ansible

ansible是新出现的自动化运维工具,基于Python研发。糅合了众多老牌运维工具的优点实现了批量操作系统配置、批量程序的部署、批量运行命令等功能。仅需在管理工作站上安装ansible程序配置被管控主机的IP信息,被管控的主机无客户端。ansible应用程序存在于epel(第三方社区)源,依赖于很多python组件。主要包括:


(1)、连接插件connection plugins:负责和被监控端实现通信;


(2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;


(3)、各种模块核心模块、command模块、自定义模块;


(4)、借助于插件完成记录日志邮件等功能;


(5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。


2.ansible特性


模块化设计,调用特定的模块来完成特定任务,本身是核心组件,短小精悍;


基于Python语言实现,由Paramiko(python的一个可并发连接ssh主机功能库), PyYAML和Jinja2(模板化)三个关键模块实现;


部署简单,agentless无客户端工具;


主从模式工作;


支持自定义模块功能;


支持playbook剧本,连续任务按先后设置顺序完成;


期望每个命令具有幂等性:


3.ansible架构


ansible core:ansible自身核心模块


host inventory:主机库,定义可管控的主机列表


connection plugins:连接插件,一般默认基于ssh协议连接


modules:core modules(自带模块)、custom modules(自定义模块)


playbooks:剧本,按照所设定编排的顺序执行完成安排任务


4.配置文件:


(1)ansible应用程序的主配置文件:/etc/ansible/ansible.cfg


(2) Host Inventory定义管控主机:/etc/ansible/hosts


二、ansible安装

1.配置时间同步

2.关闭防火墙

3.关闭selinux

4.配置DNS

5.下载yum源

wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo

6.安装epel


yum -y install epel-release


7.安装ansible


yum -y install ansible


执行完第七步如果没有报错ansible安装完成


8.配置ssh


ssh-keygen

ssh-copy-id 192.168.31.55  #192.168.31.55为客户端IP


9.把客户端IP写到/etc/ansible/hosts里



若遇报错,则需paramiko模块安装

https://pypi.python.org/packages/source/e/ecdsa/ecdsa-0.11.tar.gz

# tar xvzf ecdsa-0.11.tar.gz

# cd ecdsa-0.11

# python setup.py install

 

https://pypi.python.org/packages/source/p/paramiko/paramiko-1.15.1.tar.gz

# tar xvzf paramiko-1.15.1.tar.gz

# cd paramiko-1.15.1

# python setup.py install


二、ansible特性


(1)模块化:调用特定的模块,完成特定任务;


(2)基于python语言实现,由paramiko,PYYAML和JINJa2三个关键模块组成


(3)部署简单:agentless,被红帽收购,故备收入epel源


(4)支持自定义模块


(5)支持playbook(剧本)




三、ansible组成+部署




部署:yum -y install ansible


配置文件:/etc/ansible/ansible.cfg


主机清单:/etc/ansible/hosts


主程序:ansible、ansible paly-book、ansible-doc



ansible命令参数介绍


-m:要执行的模块,默认为command

-a:模块的参数

-u:ssh连接的用户名,默认用root,ansible.cfg中可以配置

-k:提示输入ssh登录密码。当使用密码验证的时候用

-s:sudo运行

-U:sudo到那个用户,默认为root

-K:提示输入sudo密码,当不是NOPASSWD模式时使用

-C:只是测试一下会改变什么内容,不会真正去执行

-c:连接类型(default=smart)

-f:fork多少个进程并发处理,默认为5个

-i:指定hosts文件路径,默认default=/etc/ansible/hosts

-I 指定pattern,对<host_pattern>已匹配的主机中再过滤一次

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

-M:要执行的模块路径,默认为/usr/share/ansible

-o:压缩输出,摘要输出

--private-key 私钥路径

-T: ssh连接超时时间,默认10秒

-t:日志输出到该目录,日志文件名以主机名命名

-v:verbost


 

字段名 参考值 含义


ansible_architecture    x86_64  受控节点系统框架

ansible_distribution    CentOS  受控节点的操作系统发行版

ansible_distribution_version    6.3 受控节点发行版本的版本号

ansible_domain  kisops.org  受控节点的主域名

ansible_fqdn    site01.kisops.org   受控节点的完整机器名

ansible_interfaces  [“lo”,”eth0”]   列出受控节点所有的网卡

ansible_kernel  2.6.32-431.5.1.el6.x86_64   受控节点的内核版本号

ansible_memtotal_mb 30099   受控节点总内存大小(兆)

ansible_processor_count 24  受控节点的CPU核心

ansible_virualization_role  guest   受控节点的身份:host为宿主机,guest为虚拟机

ansible_virtualization_type kvm 受控节点的虚拟化类型


#普通用户使用sudo


$ ansible all --sudo -m copy -a 'src=/tmp/zabbix_agentd.conf dest=/usr/local/zabbix/etc/  owner=ody group=root mode=0644'




三、ansible基本命令的使用

1.语法

ansible <host-pattern> [-f forks] [-m module_name] [-a args]


-f forks:启动的并发数


-m module_name:使用的模块


-args:模块特有参数


[root@yunwei ~]# ansible web -m ping


192.168.31.114 | SUCCESS => {

    "changed": false, 

    "ping": "pong"

}

192.168.31.113 | SUCCESS => {

    "changed": false, 

    "ping": "pong"

}

2.command模块


使用command模块执行date指令,ansible 默认模块,不支持变量传递


[root@yunwei ~]# ansible web -m command -a 'date'


192.168.31.114 | SUCCESS | rc=0 >>

2017年 03月 24日 星期五 17:09:53 CST


192.168.31.113 | SUCCESS | rc=0 >>

2017年 03月 24日 星期五 17:09:54 CST


[root@yunwei ~]# ansible web -a 'date'


192.168.31.113 | SUCCESS | rc=0 >>

2017年 03月 24日 星期五 17:11:02 CST


192.168.31.114 | SUCCESS | rc=0 >>

2017年 03月 24日 星期五 17:11:02 CST


3.copy模块


把本地/root/aaa 考到目标主机/tmp/aaa


[root@yunwei ~]# ansible web -m copy -a 'src=/root/aaa dest=/tmp/aaa owner=root group=root mode=0644'


192.168.31.114 | SUCCESS => {

    "changed": false, 

    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", 

    "dest": "/tmp/aaa", 

    "gid": 0, 

    "group": "root", 

    "mode": "0644", 

    "owner": "root", 

    "path": "/tmp/aaa", 

    "secontext": "unconfined_u:object_r:admin_home_t:s0", 

    "size": 0, 

    "state": "file", 

    "uid": 0

[root@yunwei ~]# ansible web -a 'ls -l /tmp/aaa'

192.168.31.114 | SUCCESS | rc=0 >>

-rw-r--r--. 1 root root 0 3月  24 17:23 /tmp/aaa




  1. ansible安装以及配置认证


ansible也是有Python开发的。

ansible特点:

不需要安装客户端,通过sshd去通信

基于模块工作,模块可以由任何语言开发


不仅支持命令行使用模块,也支持编写yaml格式的playbook

支持sudo

又提供UI(浏览器图形化)www.ansible.com/tower 10台主机以内免费

开源UI http://github.com/alaxli/ansible_ui

文档http://download.csdn.net/detail/liyang23456/7741185


ansible安装:

两台机器:

服务端:192.168.147.137

客户端:192.168.147.138


在两台机器的/etc/hosts文件里加入:


192.168.147.137 server

192.168.147.138 client


只需要在服务端上安装ansible即可


服务端:


yum install -y epel-release


yum install -y ansible


ansible配置密钥:

服务端:

生成秘钥对(默认放在/root/.ssh/目录下,也可以自定义):


ssh-keygen -t rsa


直接回车即可,不用设置秘钥密码


把公钥(id_rsa.pub)内容放到客户端(192.168.147.138)的/root/.ssh/authorized_keys里面:scp /root/.ssh/id_rsa.pub 192.168.147.138:/root/.ssh/authorized_keys


也在服务端上的/root/.ssh/authorized_keys里面复制一份公钥,后面要用本机做一个客户端,即127.0.0.1:scp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys


客户端:

更改文件权限:

chmod 600 /root/.ssh/authorized_keys

关闭selinux:

setenforce  0

测试服务端连接客户端:

ssh client

如果ssh命令不存在,安装一下:

yum insall -y openssh-clients


2.ansible远程执行命令

服务端:

定义一个主机组:

vim /etc/ansible/hosts

添加一个主机组:

[testhost]

127.0.0.1

192.168.147.138

说明:testhost为主机组名字,自定义的。下面两个IP为组内的机器IP,也可以写主机名,前提是能解析为IP。

对这组主机执行w命令:


ansible testhost -m command -a 'w'


这样就可以批量执行命令了。这里的testhost为主机组名,-m后边是模块名字,-a后面是命令。当然我们也可以直接写一个IP,针对某一台机器来执行命令。


ansible 127.0.0.1 -m command -a 'hostname'


错误:“msg”:"Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"


解决:yum install -y libselinux-python


还有一个模块就是shell同样也可以实现,支持管道:


ansible testhost -m shell -a 'cat /etc/passwd | grep root'


shell功能比command功能多。


3.ansible拷贝目录或者文件


ansible testhost -m copy -a "src=/etc/ansible dest=/tmp/ansibletest owner=root group=root mode=0755"


注意:源目录会放到目标目录下面去,如果目标指定的目录不存在,它会自动创建。如果拷贝的是文件,dest指定的名字和源如果不同,并且它不是已经存在的目录,相当于拷贝过去后又重命名。但相反,如果dest是目标机器上已经存在的目录,则会直接把文件拷贝到该目录下面,例如:


ansible testhost -m copy -a "src=/etc/passwd dest=/tmp/123"


这里的/tmp/123和源机器上的/etc/passwd是一致的,但如果目标机器上已经有/tmp/123目录,则会在/tmp/123/目录下建立passwd文件。


4.ansible远程执行脚本


首先创建一个shell脚本:

vim /tmp/test.sh

#!/bin/bash

echo `date` > /tmp/ansible_test.txt


然后把该脚本分发到各个机器上


ansible testhost -m copy -a "src=/tmp/test.sh dest=/tmp/test.sh mode=0755"


最后是批量执行该shell脚本


ansible testhost -m shell -a "/tmp/test.sh"


shell模块,还支持远程执行命令并且带管道:


ansible testhost -m shell -a "cat /etc/passwd | wc -l"


5.ansible实现任务计划


服务端:

创建一个任务计划:

ansible testhost -m cron -a "name='test cron' job='/bin/touch /tmp/1212.txt' weekday=6"


如果删除该cron只需要加一个字段state=absent


ansible testhost -m cron -a "name='test cron' state=absent"


其他的时间表示:

分:minute

时:hour

日:day

月:month

周:weekday


客户端:

查看任务计划:

crontab -l


6.ansible安装rpm包和管理服务


安装httpd:


ansible testhost -m yum -a "name=httpd"


在name后面还可以加上state=installed,默认不加也可以安装


开启httpd服务,并设为开机启动:


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


这里的name是centos系统里的服务名,可以通过chkconfig --list查看


ansible文档的使用:


ansible-doc -l查看所有的模块


ansible-doc cron查看指定的模块



7.ansible playbook介绍


类似于shell脚本,相当于把命令写入到文件里,例如:


vim /etc/ansible/test.yml

---

- hosts: testhost

 remote_user: root

 tasks:

   - name: test_playbook

     shell: touch /tmp/test.txt

说明:hosts参数制定了对哪些主机进行操作;

user参数制定了使用什么用户登录远程主机操作;

tasks制定了一个任务,其下面的name参数同样是对任务的描述,在执行过程中会打印出来。


执行:ansible-playbook   /etc/ansible/test.yml


再来一个创建用户的例子:


vim /etc/ansible/create_user.yml

---

- name: create_user

 hosts: testhost

 user: root

 gather_facts: false

 vars:

   - user: "test"

 tasks:

   - name: create user

     user: name="{{ user }}"

执行:ansible-playbook  /etc/ansible/create_user.yml


说明:name参数对该playbook实现的功能做一个概述,后面执行过程中,会打印name变量的值,可以省略;gather_facts参数制定了在以下任务执行前,是否先执行setup模块获取相关信息,这在后面的task或使用到setup获取的信息时用到;


vars参数制定了变量,这里指一个user变量,其值为test,需要注意的是,变量值一定要引号括起来

user制定了调用user模块,name是user模块里的一个参数,而增加的用户名字调用了上面user变量的值。



收集客户端的信息:


ansible client -m setup


8.ansible playbook循环


修改testhost组下主机的/tmp/目录下的1.txt,2.txt,3.txt(首先保证这些文件存在)的权限修改为600,属主改为root,属组改为root:


编辑一个loop.yml脚本:


vim /etc/ansible/loop.yml

---

- hosts: testhost

 user: root

 tasks:

   - name: change mode for file

     file: path=/tmp/{{ item }} mode=600 owner=root group=root

     with_items:

      - 1.txt

      - 2.txt

      - 3.txt

执行:


ansible-playbook /etc/ansible/loop.yml


9.ansible playbook判断


当满足条件ansible_hostname == "client"时执行命令:


touch /tmp/when.txt:


编辑一个when.yml脚本:


vim /etc/ansible/when.yml

---

- hosts: testhost

 remote_user: root

 gather_facts: True

 tasks:

   - name: use when

     shell: touch /tmp/when.txt

     when: ansible_hostname == "client"


执行:ansible-playbook /etc/ansible/when.yml


10.ansible playbook 中的 handlers


在执行task之后,服务器发生变化之后要执行的一些操作,比如我们修改了一些配置问价后,需要重启一下服务:


vim /etc/ansinle/handlers.yml

---

- name: handlers test

 hosts: testhost

 user: root

 tasks:

   - name: copy file

     copy: src=/etc/passwd dest=/tmp/aaa.txt

     notify: test handlers

 handlers:

   - name: test handlers

     shell: echo "111111" >> /tmp/aaa.txt


说明:只有copy模块执行成功后,才会去调用下面的handlers相关的操作。也就是说如果passwd和aaa.txt内容是一样的,并不会去执行handlers里面的shell相关命令。这种比较适合配置文件发生更改后,重启服务的操作。


执行:ansible-playbook  /etc/ansinle/handlers.yml


11.ansible实例-安装Nginx


思路:先在一台机器上编译安装好Nginx、打包,然后再用ansible去下发


进入ansible配置文件目录:cd /etc/ansible


创建一个nginx_install目录,方便管理:mkdir nginx_install


进入该目录:cd nginx_install


mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}


说明:roles目录下有两个角色,commen为一些准备操作,install为安装nginx的操作。每个角色下面又有几个目录,handlers下面是当发生改变时要执行的操作,通常用在配置文件发生改变,重启服务。files为安装时用到的一些文件,meta为说明信息,说明角色依赖等信息,tasks里面是核心的配置文件,templates通常存一些配置文件,启动脚本等模块文件,vars下为定义的变量。


详细步骤:

1.编译安装Nginx可以参考LNMP部分

2.安装完Nginx后可以看到安装目录下的内容:ls /usr/local/nginx/

3.切换目录:cd /usr/local/

4.打包压缩Nginx安装目录:tar czf nginx.tar.gz nginx

5.切换到ansible配置文件目录:cd /etc/ansible

6.创建nginx_install目录:mkdir nginx_install

7.进入该目录:cd nginx_install

8.创建子目录:mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}

9.将相关文件拷贝到指定目录下:

cp /usr/local/nginx.tar.gz /etc/ansible/nginx_install/roles/install/files/

cp /usr/local/nginx/conf/nginx.conf /etc/ansible/nginx_install/roles/install/templates/

cp /etc/init.d/nginx /etc/ansible/nginx_install/roles/install/templates/


10.编写common/tasks的总入口配置文件:


vim  /etc/ansible/nginx_install/roles/common/tasks/main.yml

- name: Install initialization require software

        yum: name={{ item }} state=installed

        with_items:

          - zlib-devel

          - pcre-devel

          - openssl-devel


11.编写install/vars的总入口配置文件:


vim /etc/ansible/nginx_install/roles/install/vars/main.yml

nginx_user: www

nginx_basedir: /usr/local/nginx


12.编写install/tasks的copy配置文件:

vim /etc/ansible/nginx_install/roles/install/tasks/copy.yml

- name: Copy Nginx Sofrware

 copy: src=nginx.tar.gz dest=/tmp/nginx.tar.gz owner=root group=root

- name: Uncompression Nginx Software

 shell: tar zxf /tmp/nginx.tar.gz -C /usr/local/

- name: Copy Nginx Start Script

 template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755

- name: Copy Nginx Config

 template: src=nginx.conf dest={{ nginx_basedir }}/conf/ owner=root group=root mode=0644

13.编写install/tasks的install配置文件


vim /etc/ansible/nginx_install/roles/install/tasks/install.yml

- name: Create Nginx User

 user: name={{ nginx_user }} state=present createhome=no shell=/sbin/nologin

- name: Start Nginx Service

 service: name=nginx state=started

- name: Add Boot Start Nginx Service

 shell: chkconfig --level 345 nginx on

- name: Delete Nginx compression files

 shell: rm -rf /tmp/nginx.tar.gz


14.编写install/tasks的总入口配置文件:

vim /etc/ansible/nginx_install/roles/install/tasks/main.yml

- include: copy.yml

- include: install.yml


15.编写整个程序的总入口配置文件:


vim /etc/ansible/nginx_install/install.yml

---

- hosts: 192.168.147.138

 remote_user: root

 gather_facts: True

 roles:

   - common

   - install

16.执行:ansible-playbook /etc/ansible/nginx_install/install.yml


客户端:

查看上述三个包是否已经安装成功:rpm -qa | egrep 'pcre|openssl|zlib'

查看Nginx是否安装成功:ls /usr/local/nginx/

查看服务是否启动成功:ps aux | grep nginx

查看加入服务列表是否成功:chkconfig --list nginx


11.ansible实例-管理Nginx配置文件


生产环境中大多时候是需要管理配置文件的,安装软件包只是在初始化环境的时候用一下。下面我们来写个管理Nginx配置文件的playbook

mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}

其中new为更新时用到的,old为回滚时用到的,files下面为nginx.conf和vhosts目录,handlers为重启Nginx服务的命令

关于回滚,需要在执行playbook之前备份一下旧的配置,所以对于老配置文件的管理一定要严格,千万不要随便去修改线上机器的配置,并且要保证new/files下面的配置和线上的配置一致

先把nginx.conf和vhosts目录放到files目录下面

cd /usr/local/nginx/conf/

cp -r nginx.conf vhosts /etc/ansible/nginx_config/roles/new/files


详细步骤:


  1. 级联创建所需要的目录:


mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}


2.将Nginx的配置文件拷贝到指定目录:


cp /usr/local/nginx/conf/nginx.conf /etc/ansible/nginx_config/roles/new/files/

cp -r /usr/local/nginx/conf/vhosts /etc/ansible/nginx_config/roles/new/files/


3.定义vars:

vim /etc/ansible/nginx_config/roles/new/vars/main.yml

nginx_basedir: /usr/local/nginx

4.定义handlers:

vim /etc/ansible/nginx_config/roles/new/handlers/main.yml

- name: restart nginx

 shell: /etc/init.d/nginx reload

5.定义tasks:

vim /etc/ansible/nginx_config/roles/new/tasks/main.yml

- name: copy conf file

 copy: src={{ item.src }} dest={{ nginx_basedir }}/{{ item.dest }} backup=yes owner=root group=root mode=0644

 with_items:

   - { src: nginx.conf, dest: conf/nginx.conf }

   - { src: vhosts, dest: conf/ }

 notify: restart nginx


6.定义一个update程序的入口文件:


vim /etc/ansible/nginx_config/update.yml

---

- hosts: 192.168.147.138

 user: root

 roles:

   - new


7.执行更新:ansible-playbook /etc/ansible/nginx_config/update.yml


上面实现了更新,即在服务端修改配置文件,执行playbook即可同步到客户端。

回滚的实现更简单:在每次更新之前,先将new/目录下的配置文件备份到old/目录下,定义一个rollback程序的入口文件:

vim /etc/ansible/nginx_config/rollback.yml

---

- hosts:  192.168.147.138

 user: root

 roles:

   - old

如果更新失败,可以执行回滚:ansible-playbook /etc/ansible/nginx_config/rollback.yml

ansible样例库:

git clone git://github.com/dl528888/ansible-examples.git

git命令需要yum安装一下:yum install -y git




五、ansible的常用模块(用ansible-doc -l可以显示)


(1)command模块:远程主机上运行命令


例如:ansible webservers -m command -a "ls /var"


ansible webservers -a "useradd user1",command模块可以省


ansible webservers -a "echo magedu |passwd –stdin user1" ,不成功,不支持管道


(2)shell模块:(管道可以用)远程主机在shell进程下运行命令,支持shell特性


例如:ansible webservers -m shell -a "echo cwj1111|passwd –stdin user1"


(3)copy模块:把文件复制到远程位置


例如:ansible all -m copy -a "src=/etc/fstab dest=/tmp/fstab" 可以指明mode(权限),group(组),owner(主)。


(4)cron:管理任务计划的


minute=,day=,month=,weekday=,hour=,job=,name=(必须要给),state=


例如:ansible all -m cron -a "minute=*/5 job=&apos;/sbin/ntpdate 192.168.1.109 &> /dev/null&apos; name=Synctime "


在被管理主机上使用crontab -l便可以看到


ansible all -m cron -a "state=absent name=Synctime" 就可以删除


(5)fetch模块:拉取文件的(从远程主机上拉取文件到本地)


ansible-doc -s fetch 查看


(6)file模块:设定文件属性(属组,属主)


例如:ansible all -m file -a "src=/tmp/fstab path=/tmp/fstab.link state=link"


修改属性:path= ,owner= ,mode= ,group=


创建目录:ansible all -m file -a "path=/tmp/tmpdir state=directory "


(7)pip模块:管理python的模块



(8)yum模块:用yum包管理,管理包


例如:ansible all -m yum -a "name=httpd state=present"


上面显示的是我已经装过了,就没有改变,现在我们卸载了看看:ansible all -m yum -a "name=httpd state=absent"


在使用rpm看一下就没有了


(9)service模块:管理服务


name=,state=, started(启动),stopped(停止),restarted(重启), enabled=,runlevel=


例如:先查看两台主机的80端口,再启动


ansible all -m shell -a "ss -tnl |grep :80 "


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

启动之后:



(10)user模块:管理用户,账号,组


name=,system=,uid=,shell=,group=,groups=,home=,passwd=,remove=(state=absent,同时删除家目录)


例如:ansible all -m user -a "name=user2 system=yes state=present uid=306 "


(11)setup模块,收集变量


六、ansible-playbook


ansible使用YAML语法描述配置文件,YAML语法以简洁明了、结构清晰著称。ansible的任务配置文件被称为playbook,就是剧本,每个剧本里面包含一系列的任务,每个任务在ansible中又被称为“戏剧”(play)。


(1)YAML语法格式


数据结构可以用类似大纲的缩排方式呈现,结构通过通过缩进来表示,连续的项目可以通过减号“-”来表示,map结构里面的key/value对用冒号“:”来分隔。如下:


(2)例子


先创建一个working文件夹,再cd到working里面,把yaml文件移到里面,创建一个files目录,把配置好的httpd.conf移到里面去,改一下监听端口,改成8080


ansible-playbook –check web.yaml



测试一下:


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


ansible all -m shell -a "ss -tnl |grep :8080"





(3)上面的有一个缺陷,我改动那个配置文件了怎么办,这个时候就要用handlers了


在特定条件下触发;接收到其他任务的通知时被触发。Tasks中的任务都是有状态的,changed或者ok。 在Ansible中,只在task的执行状态为changed的时候,才会执行该task调用的handler。Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了。我改了配置文件要重启吧。





(4)指定哪一出独唱用tags


我只想运行playbook的某一步,其他的不运行




(5)variables变量


1、facts:可以直接调用


2、ansible-playbook命令的命令行中可以自定义变量:-e 使用变量


ansible-playbook -e pkname=memcached –check web2.yaml


3、通过roles传递变量


4、Host Inventory



(6)模版templates:是一个文本文件内容嵌套脚本,是使用模版编程语言编程。


Jinja2:



template模块:基于模版方式生成一个文件复制到远程主机


例子,


(1)首先:ansible all -m setup | grep ansibleprocessorvcpus






(2)在working/files/ 下,编辑一个epel源,这里我们直接wget 阿里的好了:wget -O working/files/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo


(3)复制过去:ansible all -m copy -a "src=files/epel.repo dest=/etc/yum.repos.d "


(4)装上nginx:ansible all -m yum -a "name=nginx state=present "


(5)创建模版文件:cp /etc/nginx/nginx.conf files/nginx.conf.j2


vim files/nginx.conf.j2


workerprocesses {{ ansibleprocessor_vcpus }};


(6)使用template将模版复制过去:

好了,现在做的结果是让worker_processes跟cpu的内核数相等。它比copy更厉害的是,它配置的是模版文件,就像作文模版一样,可以根据你的需要配置吻合不同机器一个模版文件,而copy的文件是固定不变的。

(7)条件判断,when语句,在task中使用,支持jinja2的语法格式


(8)循环,迭代,我一下装好几个包

YAML简介


YAML是一个可读性高的用来表达资料序列的格式。

YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。

Clark Evans在2001年在首次发表了这种语言,另外Ingy dt Net与Oren Ben-Kiki也是这语言的共同设计者。

YAML Ain't Markup Language,即YAML不是XML。不过,在开发的这种语言时,YAML的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。

其特性包括:

YAML的可读性好

YAML和脚本语言的交互性好

YAML使用实现语言的数据类型

YAML有一个一致的信息模型

YAML易于实现

YAML可以基于流来处理

YAML表达能力强,扩展性好 

YAML语法  

YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。


其结构(Structure)通过空格来展示


序列(Sequence)里的项用"-"来代


Map里的键值对用":"分隔。


YAML文件扩展名通常为.yaml或者.yml。

下面是一个示例。 

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  

   

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}  

   

多个映射关系组成一个字典一个列表可以包含多个字典。 



ymal中的变量


################################## 变量命名  

变量名仅能由字母、数字和下划线组成且只能以字母开头。  

   

################################## facts  

facts是由正在通信的远程目标主机发回的信息这些信息被保存在ansible变量中。要获取指定的远程主机所支持的所有facts可使用如下命令进行  

ansible hostname -m setup 这个命令可以获得被监控端主机的各种信息将这些信息得到后保存到变量中。  

   

################################ 自定义变量  

在 yaml 中可以使用vars关键字来定义变量  

vars:  

var_name: value  

   

############################# 变量的引用  

{{ var_name }}  

   

   

########################### 特殊的变量迭代  

当有需要重复性执行的任务时可以使用迭代机制。其使用格式为将需要迭代的内容定义为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' } 


3、Inentory文件的格式


inventory文件遵循INI文件风格中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中

此外当如若目标主机使用了非默认的SSH端口还可以在主机名称之后使用冒号加端口号来标明。  

   

[webservers]  

www1.magedu.com:2222  

www2.magedu.com  

[dbservers]  

db1.magedu.com  

db2.magedu.com  

db3.magedu.com  

   

如果主机名称遵循相似的命名模式还可以使用列表的方式标识各主机例如  

[webservers]  

www[01:50].example.com  

[databases]  

db-[a:f].example.com  

   

#################### 主机变量  

可以在inventory中定义主机时为其添加主机变量以便于在playbook中使用。例如  

[webservers]  

www1.magedu.com http_port=80 maxRequestsPerChild=808 

www2.magedu.com http_port=303 maxRequestsPerChild=909 

   

################### 组变量  

组变量是指赋予给指定组内所有主机上的在playbook中可用的变量。例如  

   

[webservers]  

www1.magedu.com  

www2.magedu.com  

   

[webservers:vars]  

ntpntp_server=ntp.magedu.com  

nfsnfs_server=nfs.magedu.com  

   

################## 组嵌套  


inventory中组还可以包含其它的组并且也可以向组中的主机指定变量。


不过这些变量只能在ansible-playbook中使用而ansible不支持。例如  

   

[apache]  

httpd1.magedu.com  

httpd2.magedu.com  

   

[nginx]  

ngx1.magedu.com  

ngx2.magedu.com  

   

[webservers:children]  

apache  

nginx  

   

[webservers:vars]  

ntpntp_server=ntp.magedu.com  

   

######################### inventory参数  

   

ansible基于ssh连接inventory中指定的远程主机时还可以通过参数指定其交互方式常用的参数如下所示  

ansible_ssh_host # 要连接的主机名  

ansible_ssh_port # 端口号默认是22  

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

ansible_ssh_pass # ssh连接时的密码  

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

ansible_ssh_private_key_file # 秘钥文件如果不想使用ssh-agent管理时可以使用此选项  

ansible_shell_type # shell的类型默认sh  

#########################################################################################  


4、playbooks


playbook是由一个或多个“play”组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。  

从根本上来讲所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中即可以让它们联同起来按事先编排的机制同唱一台大戏。  

   

###########################playbook基础组件  

1、Hosts和Users  

   

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

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

remote_user则用于指定远程主机上的执行任务的用户。  

   

不过remote_user也可用于各task中。也可以通过指定其通过sudo的方式在远程主机上执行任务其可用于play全局或某任务。  

此外甚至可以在sudo时使用sudo_user指定sudo时切换的用户。  

   

- hosts: webnodes  

remote_user: mageedu  

tasks:  

- name: test connection ping:  

remote_user: mageedu 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中定义的操作。  

   

- 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 

5、tags


tags用于让用户选择运行或路过playbook中的部分代码。ansible具有幂等性因此会自动跳过没有变化的部分即便如此有些代码为测试其确实没有发生变化的时间依然会非常地长。此时如果确信其没有变化就可以通过tags跳过此些代码片断。  

   

示例基于playbooks实现web服务的部署  


1、提供好Inventory文件  


# /etc/ansible/hosts基于秘钥认证  


[webhosts]  

172.16.10.22  

172.16.10.33  

   

2、编辑 palybooks 剧本  


vim /root/web.yaml  

- name: web service  

remote_user: root  

hosts: webhosts  

vars:  

packages: httpd  

tasks:  

- name: install httpd yum: name={{ packages }} state=present 

tags: install  

- name: configuration httpd  

copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf  

tags: conf  

notify:  

- restart httpd  

- name: service httpd start  

service: name=httpd enabled=no state=started 

tags: start  

- name: add centos and hadoop user  

user: name={{ item }} state=absent 

tags: adduser  

with_items:  

- centos  

- hadoop  

handlers:  

- name: restart httpd  

service: name=httpd state=restarted 

   

3、准备好配置文件  

将web的配置放到指定目录 src=/root/httpd.conf  

   

4、开始部署  

ansible-playbooks /root/web.yml 





yum的epel源,


配置文件:/etc/ansible/ansible.cfg


主机清单:/etc/ansible/hosts


主程序:

    ansible

    ansible-playbook

    ansible-doc


ansible的简单使用格式:

    ansible HOST-PATTERN -m MOD_NAME -a MOD_ARGS

    ansible-doc -s MOD_name

ansible的常用模块:

    获取模块列表:

        ansible-doc -l

        command模块:在远程主机运行命令,不支持“|”

            ansible websrvs -m command -a "useradd user1"

        shell模块:远程主机在shell进程中中运行

            ansible websrvs -m shell - a "echo magedu | password --stdin user1"

        copy模块:复制文件至远程主机;

            用法:(1)src=\'#\'" /etc/fstab dest=/tmp/fstab"

                      (2)content= dest=   //直接把内容作为数据流传输至文件;

                        ansible all -m copy -a "content='hello world\n' dest=/tmp/testfile"

                  owner,group,mode

        cron模块:manage cron.d and crontab entries

            minute=

            hour=

            day=

            weekday=

            job=

            *name=    //必须有此参数            state=

                present //默认为添加

                absent  //删除crontab

            ansible all -m cron -a "minute=*/5 job='/sbin/ntpdate 172.16.0.1 &> /dev/null' name=Synctime"

        fetch模块:从远程主机拉去文件至当前机器;

        file模块:修改文件属性;

            *path=     //必须有此参数

            用法:(1)创建连接文件

                        ansible all -m file -a "src=/tmp/fstab path=/tmp/fstab.link state=link"

                  (2)修改属性:path= owner= mode= group=

                  (3)创建目录:path= state=directory

                        ansible all -m file -a "path=/tmp/tmpdir state=directory"

        hostname模块:manage hostname

            name=

        ping模块:

        pip模块:用来管理Python的依赖模块;

        yum模块:用yum来管理程序包

            *name=:指明程序包名称,可以带版本号      //必须有此参数            state=

                present,latest(安装),absent(卸载);

                ansible all -m yum -a "name=httpd state=latest"  

        service模块:管理服务

            *name=      //必须有此参数            state=

                started,stopped,restarted;

            enabled= 1|0    //开机自启动;

            runlevel= 

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

        uri模块:uri的访问管理        user模块:管理用户账户;

            *name 

            system= yes|no    //yes是系统账户

            uid=

            shell=            group=

            groups=

            comment=

            home=

            move_home=

            remove=   //当state=agent是删除家目录

                ansible all -m user -a "name=user3 system=yes state=present uid=306"

        setup模块:用于获取facts;        group模块:添加或删除组

            *name=  //必须给的参数            state

            system

            gid=

        scipt模块:把本地脚本传递到远程主机后进行执行;

            ansible -m script -a "/path/to/script_file"






YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。

其结构(structure)通过空格来展示,序列(Sequence)里的项用“-”来代表,Map里的键值对用“:”分隔。


Playbook:

Playbook的核心元素:

    Hosts:主机

    Tasks:任务

    variables:

    Templates:包含了模板的文本文件;

    Handlers:由特定条件出发任务;

    Roles:

    

    playbook的基础组件

        Hosts:运行指定任务的目标主机;

        remoute_user:在远程主机上执行任务的用户;

            sudu_user:

        tasks:任务列表

            模块,模块参数;

            格式:

                (1)action:module arguments

                (2)module:arguments

        handlers:

            任务,在特定条件下触发;

            接收到其他任务的通知时被触发;  

        variables:

            (1)facts:可直接调用;

            (2)ansible-playbook命令行中的自定义变量;

                -e VARS,--extra-vars=VARS            

            (3)通过role传递变量;

            (4)Host Inventory

                (1)向不同的主机传递不同的变量;

                    ip/hostname varaiable=value var2=value2

                (2)向组中主机传递相同的变量

                    [groupname:vars]

                    variable=value

            invertory参数:

                用于定义ansible远程连接目标主机时的参数,而非传递给playbook的变量;

                    ansible_ssh_host

                    ansible_ssh_port

                    ansible_ssh_user

                    ansible_ssh_pass

                    ansible_sudo_pass

                ....

        **注意:shell和command模块后直接跟命令即可**


        **某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;**


        **任务可以通过“tags”打标签,而后可在ansible-playbook命令上使用-t指定进行调用;**


    playbook的使用方法:


        ansible-playbook在执行命令时,第一个任务执行完成后执行第二个任务,第二个执行完成后,执行第三个任务;


        ansible-playbook 

            --list-host      //显示执行的主机列表;            

            --check          //在目标主机进行检测可能会发生改变,但并不执行;            

            -t tags          //指明任务                

            ansible-palybook -t instconf web.yml  //进行标签为instconf的项目;

        playbook示例1:编写sample.yaml

            - hosts:            remote_user:root

            tasks:

                - name: create a user user3                  

                  user: name=user3 system=true uid=307

                - name: creare a user user4                  

                  user: name=user4 system=true uid=308

        playbook示例2:编写web.yml  

            - hosts: websrvs              remote_user: root

              tasks:

              - name: install httpd package                yum: name=httpd state=present

              - name: install configure file 

                copy: src=files/httpd.conf dest=/etc/httpd/conf/    //src为相对路径

                tags: instconf

                notify: restart httpd

              - name: start httpd.service 

                serivce: name=httpd state=started

              -name: execute ss command                

                shell: ss -tnl | grep 8080

            - handlers:              

              - name: restart httpd                

                service: name=httpd state=restarted







一.ansible 说明 

ansible 是一款自动化工具,可以完成配置系统、软件发布、高级任务的编排、编排更高级的任务,比如连续部署或零停机时间滚动更新。


二.anisble 安装 

2.1这里希望通过yum方式安装,需要安装EPEL 

下载地址: 


https://admin.fedoraproject.org/mirrormanager/mirrors/EPEL

 

2.2.安装epel: 

rpm -ivh epel-release-latest-7.noarch.rpm

2.3.安装ansible,自动解决依赖关系 

yum install ansible

2.4.安装列表如下: 


ansible、PyYAML、libtomcrypt、libtommath、libyaml、python-babel、python-backports 、python-backports-ssl_match_hostname 、python-httplib2  python-jinja2、python-keyczar、python-markupsafe、python-setuptools、python2-crypto、python2-ecdsa、python2-paramiko、python2-pyasn1、sshpass


2.5.查看ansible版本:


# rpm -qa | grep ansible

ansible-2.2.0.0-4.el7.noarch

spacer.gif


2.6.结构说明


/etc/ansible/ansible.cfg #主配置文件

/etc/ansible/hosts  #认证主机列表

/etc/ansible/roles #角色配置路径

/usr/bin/ansible  #主命令

/usr/bin/ansible-console

/usr/bin/ansible-doc  #ansible帮助文档

/usr/bin/ansible-galaxy

/usr/bin/ansible-playbook  #playbook命令

/usr/bin/ansible-pull

/usr/bin/ansible-vault


ansible主配文件解析


[defaults]


# some basic default values...

#inventory      = /etc/ansible/hosts  #这个事默认库文件位置,脚本,或者存放可通信主机的目录

#library        = /usr/share/my_modules/  #这个事Ansible默认搜寻模块的位置

#module_utils   = /usr/share/my_module_utils/

#remote_tmp     = ~/.ansible/tmp

#local_tmp      = ~/.ansible/tmp

#forks          = 5  #连接主机的并发数

#poll_interval  = 15 #对于Ansible中的异步任务(详见 异步操作和轮询), 这个是设置定义,当具体的poll interval 没有定义时,多少时间回查一下这些任务的状态, 默认值是一个折中选择15秒钟.这个时间是个回查频率和任务完成叫回频率和当任务完成时的回转频率的这种:

#sudo_user      = root

#ask_sudo_pass = True #ask_pass,用来控制Ansible playbook 在执行sudo之前是否询问sudo密码.默认为no

#ask_pass      = True #个可以控制,Ansible 剧本playbook 是否会自动默认弹出弹出密码.默认为no

#transport      = smart

#remote_port    = 22 #ssh连接端口

#module_lang    = C #这是默认模块和系统之间通信的计算机语言,默认为’C’语言.

#module_set_locale = False

#gathering = implicit #控制默认facts收集(远程系统变量). 默认值为’implicit’, 每一次play,facts都会被收集

#gather_subset = all

# gather_timeout = 10

#roles_path    = /etc/ansible/roles #roles 路径指的是’roles/’下的额外目录,用于playbook搜索Ansible roles

#host_key_checking = False #检查主机密钥

# change the default callback

#stdout_callback = skippy

# enable additional callbacks

#callback_whitelist = timer, mail

#task_includes_static = True

#handler_includes_static = True

#error_on_missing_handler = True

#sudo_exe = sudo #如果在其他远程主机上使用另一种方式执行sudo草做, sudo程序的路径可以用这个参数更换,使用命令行标签来拟合标准

#sudo_flags = -H -S -n #当使用sudo支持的时候,传递给sudo而外的标签. 默认值为”-H”, 意思是保留原用户的环境.在有些场景下也许需要添加或者删除 标签,大多数用户不需要修改

#timeout = 10 #SSH超时时间

#remote_user = root #使用/usr/bin/ansible-playbook链接的默认用户名,如果不指定,会使用当前登录的用户名

#log_path = /var/log/ansible.log # 日志文件存放路径

#module_name = command #ansible命令执行默认的模块

#executable = /bin/sh #在sudo环境下产生一个shell交互接口. 用户只在/bin/bash的或者sudo限制的一些场景中需要修改

#hash_behaviour = replace  # 特定的优先级覆盖变量

#private_role_vars = yes

#jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n #允许开启Jinja2拓展模块

#private_key_file = /path/to/file #如果你是用pem密钥文件而不是SSH 客户端或秘密啊认证的话,你可以设置这里的默认值,来避免每一次提醒设置密钥文件位置

#vault_password_file = /path/to/vault_password_file 

#ansible_managed = Ansible managed  #这个设置可以告知用户,Ansible修改了一个文件,并且手动写入的内容可能已经被覆盖.

#display_skipped_hosts = True  # 显示任何跳过任务的状态 ,默认是显示

#display_args_to_stdout = False #显示任何跳过任务的状态 ,默认是显示

#error_on_undefined_vars = False #如果所引用的变量名称错误的话, 将会导致ansible在执行步骤上失败

#system_warnings = True #允许禁用系统运行ansible相关的潜在问题警告

#deprecation_warnings = True #允许在ansible-playbook输出结果中禁用“不建议使用”警告

# command_warnings = False #当shell和命令行模块被默认模块简化的时,Ansible 将默认发出警告



#action_plugins     = /usr/share/ansible/plugins/action  #“行为”是 ansible中的一段代码,用来激活一些事件,例如执行一个模块,一个模版,等等;这是一个以开发者为中心的特性,使得一些底层模块可以从外部不同地方加载

#cache_plugins      = /usr/share/ansible/plugins/cache

#callback_plugins   = /usr/share/ansible/plugins/callback

#connection_plugins = /usr/share/ansible/plugins/connection

#lookup_plugins     = /usr/share/ansible/plugins/lookup

#inventory_plugins  = /usr/share/ansible/plugins/inventory

#vars_plugins       = /usr/share/ansible/plugins/vars

#filter_plugins     = /usr/share/ansible/plugins/filter

#test_plugins       = /usr/share/ansible/plugins/test

#strategy_plugins   = /usr/share/ansible/plugins/strategy


#strategy = free

#bin_ansible_callbacks = False #用来控制callback插件是否在运行 /usr/bin/ansible 的时候被加载. 这个模块将用于命令行的日志系统,发出通知等特性


#nocows = 1 #默认ansible可以调用一些cowsay的特性   开启/禁用:0/1

#cow_selection = default

#cow_selection = random


#nocolor = 1 #输出带上颜色区别, 开启/关闭:0/1


#fact_caching = memory





#retry_files_enabled = False

#retry_files_save_path = ~/.ansible-retry


#no_log = False



#no_target_syslog = False



#allow_world_readable_tmpfiles = False

#var_compression_level = 9

#module_compression = 'ZIP_DEFLATED'

#max_diff_size = 1048576

#merge_multiple_cli_flags = False

# Controls showing custom stats at the end, off by default

#show_custom_stats = True

#inventory_ignore_extensions = ~, .orig, .bak, .ini, .cfg, .retry, .pyc, .pyo


[privilege_escalation]

#become=True

#become_method=sudo

#become_user=root

#become_ask_pass=False


[paramiko_connection]

#record_host_keys=False

#pty=False


[ssh_connection]

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

# control_path_dir = /tmp/.ansible/cp

#control_path_dir = ~/.ansible/cp



# control_path = %(directory)s/%%h-%%r

#control_path =

#pipelining = False


# Control the mechanism for transferring files (old)

#   * smart = try sftp and then try scp [default]

#   * True = use scp only

#   * False = use sftp only

#scp_if_ssh = smart



#transfer_method = smart



#sftp_batch_mode = False


[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



#accelerate_multi_key = yes


[selinux]


#libvirt_lxc_noseclabel = yes


[colors]

#highlight = white

#verbose = blue

#warn = bright purple

#error = red

#debug = dark gray

#deprecate = purple

#skip = cyan

#unreachable = red

#ok = green

#changed = yellow

#diff_add = green

#diff_remove = red

#diff_lines = cyan



[diff]

# Always print diff when running ( same as always running with -D/--diff )

# always = no


# Set how many context lines to show in diff

# context = 3


三.ansible 认证及基本使用

3.1.实验环境说明:

172.16.110.39 ansible

172.16.110.47 client1

3.2.anisble基于ssh认证,这里通过添加主机key认证的方式来进行认证。

服务端

#ssh-keygen -t rsa -P ''

#scp /root/.ssh/id_rsa.pub root@172.16.110.47:/data

#

客户端

#cd /data/

#cat id_rsa.pub >> /root/.ssh/authorized_keys

#chmod 600 /root/.ssh/authorized_keys

#

3.3.运行说明


# ansible -h

Usage: ansible <host-pattern> [options]


3.3.1.运行简单的ping测试


# ansible all -m ping

 [WARNING]: provided hosts list is empty, only localhost is available

 [WARNING]: No hosts matched, nothing to do

 提示,没有提供服务器列表,所以添加列表

主机列表可以ip、域名、分组、正则匹配等方式运行

3.3.2.主机ip列表方式:

# vim /etc/ansible/hosts

[webservers]

10.237.154.25

spacer.gif

ansible all -m ping

spacer.gif

SUCCESS:表示成功

false:表示未进行改变

pong:返回值,表示成功


3.3.3.分组方式运行命令:


vim /etc/ansible/hosts

[webserver]

172.16.110.47


# ansible webserver -a "ls /root"

172.16.110.47 | SUCCESS | rc=0 >>

anaconda-ks.cfg

spacer.gif

出现以上问题说明ssh认证有问题,重新弄一遍。

3.3.5.使用正则列表:


vim /etc/ansible/hosts

[webserver]

172.16.110.4[7:8]


# ansible webserver -a "/sbin/ifconfig ens33 | grep netmask" 

172.16.110.48 | FAILED | rc=1 >>

|: Unknown host

ifconfig: `--help' gives usage information.

172.16.110.47 | FAILED | rc=1 >>

|: Unknown host

ifconfig: `--help' gives usage information.

这里增加了管道,ansible增加管道必须使用shell的模块运行


# ansible webserver -m shell -a "/sbin/ifconfig ens33 | grep netmask"

172.16.110.47 | SUCCESS | rc=0 >>

        inet 172.16.110.47  netmask 255.255.255.0  broadcast 172.16.110.255

172.16.110.48 | SUCCESS | rc=0 >>

        inet 172.16.110.48  netmask 255.255.255.0  broadcast 172.16.110.255

3.4.Inventory 参数的说明,摘自网上


ansible_ssh_host

      将要连接的远程主机名.与你想要设定的主机的别名不同的话,可通过此变量设置.

ansible_ssh_port

      ssh端口号.如果不是默认的端口号,通过此变量设置.

ansible_ssh_user

      默认的 ssh 用户名

ansible_ssh_pass

      ssh 密码(这种方式并不安全,我们强烈建议使用 --ask-pass 或 SSH 密钥)

ansible_sudo_pass

      sudo 密码(这种方式并不安全,我们强烈建议使用 --ask-sudo-pass)

ansible_sudo_exe (new in version 1.8)

      sudo 命令路径(适用于1.8及以上版本)

ansible_connection

      与主机的连接类型.比如:local, ssh 或者 paramiko. Ansible 1.2 以前默认使用 paramiko.1.2 以后默认使用 'smart','smart' 方式会根据是否支持 ControlPersist, 来判断'ssh' 方式是否可行.

ansible_ssh_private_key_file

      ssh 使用的私钥文件.适用于有多个密钥,而你不想使用 SSH 代理的情况.

ansible_shell_type

      目标系统的shell类型.默认情况下,命令的执行使用 'sh' 语法,可设置为 'csh' 或 'fish'.

ansible_python_interpreter

      目标主机的 python 路径.适用于的情况: 系统中有多个 Python, 或者命令路径不是"/usr/bin/python",比如  \*BSD, 或者 /usr/bin/python

      不是 2.X 版本的 Python.我们

不使用 "/usr/bin/env" 机制,因为这要求远程用户的路径设置正确,且要求 "python" 可执行程序名不可为 python以外的名字(实际有可能名为python26).

      与 ansible_python_interpreter 的工作方式相同,可设定如 ruby 或 perl 的路径....

  

示例说明:


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模块目录结构


$ tree roles/

roles/

└── base

    ├── defaults

    ├── files

    │   ├── puppet.conf

    │   ├── yum65.repo

    │   ├── yum67.repo

    │   └── yum.repo

    ├── handlers

    │   └── main.yml

    ├── meta

    ├── tasks

    │   ├── chkconfig.yml

    │   ├── hostname.yml

    │   ├── main.yml

    │   ├── ntpd.yml

    │   ├── puppet.yml

    │   ├── repo.yml

    │   └── route.yml

    ├── templates

    │   ├── hosts.j2

    │   └── static-routes.j2

    └── vars

        └── main.yml

 

8 directories, 16 files


入口文件的site.yml


$ more site.yml 

---

- hosts: all

  remote_user: test

  become: yes

  become_method: sudo

  roles:

        - base




模版文件template


修改主机名

$ more base/templates/hosts.j2 

127.0.0.1   {{ ansible_fqdn }}   localhost localhost.localdomain localhost4 localhost4.localdomain4

::1         {{ ansible_fqdn }}   localhost localhost.localdomain localhost6 localhost6.localdomain6

10.0.0.1 puppet.server

 

添加静态路由,需要重启网络

$ more base/templates/static-routes.j2 

any net 10.0.0.0/8 gw {{ gateway }}

any net 172.0.0.0/8 gw {{ gateway }}

any net 192.168.1.0/24 gw {{ gateway }}


可以在base/vars/main.yml中定义变量,由于环境特殊,我在命令行中使用变量。


yml中定义使用变量的格式如下

 

name:value


task中的入口文件


more base/tasks/main.yml 

---

- include: ntpd.yml

- include: repo.yml

- include: route.yml

- include: hostname.yml

- include: chkconfig.yml

- include: puppet.yml



时间同步

more base/tasks/ntpd.yml 

---

- name: sync datatime

  command: /usr/sbin/ntpdate 202.120.2.101

   

- name: sync hwclock

  command: /sbin/hwclock -w

   

更具不同系统版本配置yum源

more base/tasks/repo.yml 

---

- name: configure RedHat5 yum repo

  copy: force=yes src=yum.repo  dest=/etc/yum.repos.d/rhel-debuginfo.repo owner=root group=root mode=0644

  when: ansible_distribution_major_version == '5'

 

- name: configure RedHat6.5 yum repo

  copy: force=yes src=yum65.repo  dest=/etc/yum.repos.d/rhel-debuginfo.repo owner=root group=root mode=0644

  when: ansible_distribution_version == '6.5'

 

- name: configure RedHat6.7 yum repo

  copy: force=yes src=yum67.repo  dest=/etc/yum.repos.d/rhel-debuginfo.repo owner=root group=root mode=0644

  when: ansible_distribution_version == '6.7'

   

配置路由

more base/tasks/route.yml 

- name: config static route

  template:  force=yes src=static-routes.j2 dest=/etc/sysconfig/static-routes owner=root group=root mode=0644

  notify: restart network

 

批量配置服务器的hostname(动态inventory脚本实现)

more base/tasks/hostname.yml 

---

- name: install facter

  yum: name=facter state=latest

 

- name: install rubygem-json

  yum: name=rubygem-json state=latest

 

- hostname: name={{ hostname }}

 

- name : gather facts again

  setup :

 

- name: config hosts

  template:  force=yes src=hosts.j2 dest=/etc/hosts owner=root group=root mode=0644

  

关闭iptables,sendmail和selinux

more base/tasks/chkconfig.yml 

- name: chkconfig off  iptables

  shell: /sbin/chkconfig iptables off

 

- name: stop iptables

  service: name=iptables state=stopped

 

- name: chkconfig off  sendmail

  shell: /sbin/chkconfig sendmail off

 

- name: stop sendmail

  service:  name=sendmail state=stopped 

   

- name: stop selinux 

  command:  /sbin/setenforce  0

   

初始化节点的puppet

more base/tasks/puppet.yml 

---

- name: install puppet

  yum: name=puppet state=latest

  register: result

  ignore_errors: True

   

- name: puppet config file

  copy: force=yes src=puppet.conf  dest=/etc/puppet/puppet.conf owner=root group=root mode=0644

  when: result.rc==0

 

- name: run puppet

  shell: /usr/bin/puppet agent -t





所需要的rpm包


ansible-2.2.1.0-1.el6.noarch.rpm

libyaml-0.1.3-4.el6_6.x86_64.rpm

python-argparse-1.2.1-2.1.el6.noarch.rpm

python-crypto2.6-2.6.1-2.el6.x86_64.rpm

python-httplib2-0.7.7-1.el6.noarch.rpm

python-jinja2-26-2.6-3.el6.noarch.rpm

python-keyczar-0.71c-1.el6.noarch.rpm

python-six-1.9.0-2.el6.noarch.rpm

PyYAML-3.10-3.1.el6.x86_64.rpm

sshpass-1.05-1.el6.x86_64.rpm

python-crypto2.6-2.6.1-2.el6.x86_64

服务器如果可以出公网可以使用pip或者yum安装ansible 

1.安装ansible


 yum install ansible -y


2.配置ansible,优化配置,提高ansible性能【/etc/ansible/ansible.cfg】


[defaults]

forks          = 150

transport      = paramiko

#使用facter缓存,默认使用内存,支持redis

gathering = implicit

fact_caching_timeout = 86400

fact_caching = jsonfile

fact_caching_connection = /etc/ansible/facts/cache

host_key_checking = False

remote_user = test

deprecation_warnings = False

callback_plugins   = /etc/ansible/callback_plugins

retry_files_enabled = False

[privilege_escalation]

become=True

become_method=sudo

become_user=root

become_ask_pass=False

[paramiko_connection]

[ssh_connection]

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

pipelining = True

[accelerate]

[selinux]

[colors]


优化ssh,提高ansible性能


$ more ~/.ssh/config 

Host * 

 Compression yes 

 ServerAliveInterval 60 

 ServerAliveCountMax 5 

 ControlMaster auto 

 ControlPath ~/.ssh/%r@%h-%p

 ControlPersist 4h


3.启用ansible的callback_plugins 显示ansible-playbook的执行时间


$ more callback_plugins/profile_tasks.py


import datetime

import os

import time

from ansible.plugins.callback import CallbackBase

 

 

class CallbackModule(CallbackBase):

    """

    A plugin for timing tasks

    """

    def __init__(self):

        super(CallbackModule, self).__init__()

        self.stats = {}

        self.current = None

 

    def playbook_on_task_start(self, name, is_conditional):

        """

        Logs the start of each task

        """

 

        if os.getenv("ANSIBLE_PROFILE_DISABLE") is not None:

            return

 

        if self.current is not None:

            # Record the running time of the last executed task

            self.stats[self.current] = time.time() - self.stats[self.current]

 

        # Record the start time of the current task

        self.current = name

        self.stats[self.current] = time.time()

 

    def playbook_on_stats(self, stats):

        """

        Prints the timings

        """

 

        if os.getenv("ANSIBLE_PROFILE_DISABLE") is not None:

            return

 

        # Record the timing of the very last task

        if self.current is not None:

            self.stats[self.current] = time.time() - self.stats[self.current]

 

        # Sort the tasks by their running time

        results = sorted(

            self.stats.items(),

            key=lambda value: value[1],

            reverse=True,

        )

 

        # Just keep the top 10

        results = results[:10]

 

        # Print the timings

        for name, elapsed in results:

            print(

                "{0:-<70}{1:->9}".format(

                    '{0} '.format(name),

                    ' {0:.02f}s'.format(elapsed),

                )

            )

 

        total_seconds = sum([x[1] for x in self.stats.items()])

        print("\nPlaybook finished: {0}, {1} total tasks.  {2} elapsed. \n".format(

                time.asctime(),

                len(self.stats.items()),

                datetime.timedelta(seconds=(int(total_seconds)))

                )

          )

执行的效果如下


  

test connection --------------------------------------------------------- 1.17s

 

Playbook finished: Wed Feb 15 13:09:06 2017, 1 total tasks.  0:00:01 elapsed.


4.编写ansible的动态inventory脚本


$ more inventory.py 

#!/usr/bin/env python

import argparse

import sys

 

try:

    import json

except ImportError:

    import simplejson as json

 

 

def RFile():

    with open('hostlist.txt', 'r+') as f:

        result=[]

        for line in f.readlines():

            host = line.strip().split()

            if host:

                result.append(host)

    return result

 

host_list = RFile()

 

def groupList():

    group_list = []

    for host in host_list:

        group_list.append(host[1])

    print (json.dumps({"all":group_list},indent=4))

 

def hostList(key):

    host_dict = {}

    for host in host_list:

        host_dict[host[1]] = {"ansible_ssh_host": host[1],"ansible_ssh_port":9999, "ansible_ssh_user":"test","ansible_ssh_pass":

"test","hostname":host[0]}

    print (json.dumps(host_dict[key], indent=4))

 

if len(sys.argv) == 2 and (sys.argv[1] == '--list'):

    groupList()

elif len(sys.argv) == 3 and (sys.argv[1] == '--host'):

    hostList(sys.argv[2])

else:

    print "Usage: %s --list or --host <hostname>" % sys.argv[0]

    sys.exit(1)


主机列表如下


more hostlist.txt 

backup01.cn 10.44.245.85

测试playbook:test.yml


$ more test.yml 

- hosts: all

  remote_user: test

  gather_facts: no

  become: yes

  become_method: sudo

  tasks:

    - name: test connection

      ping:

执行结果如下:


$ ansible-playbook -i inventory.py test.yml 

 

PLAY [all] *********************************************************************

 

TASK [test connection] *********************************************************

ok: [10.44.245.85]

 

PLAY RECAP *********************************************************************

10.44.245.85               : ok=1    changed=0    unreachable=0    failed=0   

 

test connection --------------------------------------------------------- 1.17s

 

Playbook finished: Wed Feb 15 13:20:09 2017, 1 total tasks.  0:00:01 elapsed.



ansible几个常用模块及参数的简单演示



file模块使用示例


[root@node1 ~]# ansible-doc -l | grep "^\<file\>"

file     Sets attributes of files 

  

[root@node1 ~]# ansible-doc -s file --> 查看模块特有的参数

 

[root@node1 ~]# ansible all -m file -a "path=/tmp/testansible state=directory" 

--> 在目标主机的/tmp目录下创建testansible目


copy模块使用示例


[root@node1 ~]# ansible all -m copy -a "src=/etc/issue dest=/tmp/testansible"

--> 将/etc/issue 文件复制到 /tmp/testansible 目录下,文件名和源文件名同名

 

[root@node1 ~]# ansible all -m copy -a "content='hello world' dest=/tmp/testansible/first" 

--> 给定内容生成文件 即 /tmp/testansible/first 的文件内容为 "hello world"



yum模块使用示例


[root@node1 ~]# ansible all -m yum -a "name=httpd state=absent" 

--> 卸载httpd程序包

 

[root@node1 ~]# ansible all -m yum -a "name=httpd state=present" 

--> 安装httpd程序包



service模块使用示例


[root@node1 ~]# ansible all -m service -a "name=httpd state=started" 

-->启动httpd服务

 

[root@node1 ~]# ansible all -m service -a "name=httpd state=stopped"

--> 停止httpd服务



获取目标主机上的facts变量(在使用yaml模板语言时,可直接进行引用)


[root@node1 ~]# ansible all -m setup


其他模块及其参数的使用方式和上述的类似

读者可自行查看帮助即可

查看命令帮助的方法:


# ansible-doc -l 


# ansible-doc -s



简单使用示例


node1:192.168.0.106 centos7.2

node2:192.168.0.110 centos7.2



[root@node1 ~]# yum -y install ansible --> 采用yum 安装ansible

[root@node1 ~]# rpm -q ansible  

ansible-2.2.0.0-3.el7.noarch --> 版本为ansible-2.2



[root@node1 ~]# rpm -ql ansible --> 简单查看生成的文件列表

/etc/ansible

/etc/ansible/ansible.cfg

/etc/ansible/hosts

/etc/ansible/roles

/usr/bin/ansible

/usr/bin/ansible-doc

/usr/bin/ansible-playbook



[root@node1 ~]# vim /etc/ansible/hosts --> 定义host inventory

[all]

192.168.0.106

192.168.0.110



[root@node1 ~]# ansible all -m ping --> 测试管理主机是否OK

192.168.0.106 | SUCCESS => {

    "changed": false, 

    "ping": "pong" --> 代表正常

}

192.168.0.110 | SUCCESS => { 

    "changed": false, 

    "ping": "pong"  --> 代表正常

}


简单的命令使用帮助

# ansible <host-pattern> [-f fork] [-m module_name] [-a args]


ansible-doc -l 查看所支持的所有模块 即 -m 后面的参数


ansible-doc -s <模块名> 查看指定模块的参数 即 -a 后面的参数



ansible之playbook介绍


核心元素:

Tasks:任务,由模块定义的操作的列表;

Variables:变量

Templates:模板,即使用了模板语法的文本文件;

Handlers:由特定条件触发的Tasks;

Roles:角色;


playbook的基础组件

hosts:运行指定任务的目标主机

remote_user:在远程主机上已哪个用户身份执行

tasks:任务列表



运行playbook,使用ansible-playbook命令


(1) 检测语法

ansible-playbook  --syntax-check  /path/to/playbook.yaml

 

(2) 测试运行

# ansible-playbook -C /path/to/playbook.yaml

       --list-hosts

       --list-tasks

       --list-tags

 

(3) 运行

# ansible-playbook  /path/to/playbook.yaml

       -t TAGS, --tags=TAGS

       --skip-tags=SKIP_TAGS

       --start-at-task=START_AT

 

(4)查看帮助

ansible-playbook -h



playbook核心元素之 --> tasks 介绍


[root@ansible ~]# vim test1.yaml 

- hosts: centos6

  remote_user: root

  tasks:

   - name: add a group

     group: name=ansgroup1 system=false

   - name: add a user

     user: name=ansuser1 group=ansgroup1  system=false

   - name: restart httpd service

     service: name=httpd state=restarted



[root@ansible ~]# ansible-playbook --syntax-check test1.yaml  --> 语法测试


[root@ansible ~]# ansible-playbook -C test1.yaml  --> 测试执行


[root@ansible ~]# ansible-playbook test1.yaml --> 执行



playbook核心元素之 --> handlers 介绍


Handlers:由特定条件触发的Tasks;


[root@ansible ~]# vim test2.yaml

- hosts: centos7

  remote_user: root

  tasks:

   - name: install httpd

     yum: name=httpd state=latest

   - name: copy config file

     copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf

     notify: restart httpd service   --> 和notify配合使用即可

   - name: start httpd service

     service: name=httpd state=started

  handlers:

   - name: restart httpd service

     service: name=httpd state=restarted


playbook核心元素之 --> variables 介绍


Variables:基本用法


类型:

    内建:(1) facts

    自定义:

        (1) 命令行传递;

            -e VAR=VALUE

        (2) 在hosts Inventory中为每个主机定义专用变量值;

            (a) 向不同的主机传递不同的变量;

                IP/HOSTNAME variable_name=value

            (b) 向组内的所有主机传递相同的变量 ;

                [groupname:vars]

                variable_name=value

        (3) 在playbook中定义

            vars:

              - var_name: value

              - var_name: value

       (4) Inventory还可以使用参数:

            用于定义ansible远程连接目标主机时使用的属性,而非传递给playbook的变量;

                ansible_ssh_host

                ansible_ssh_port

                ansible_ssh_user

                ansible_ssh_pass

                ansible_sudo_pass

                ...

        (5) 在角色调用时传递

            roles:

               - { role: ROLE_NAME, var: value, ...}

 

 

变量调用:

    {{ var_name }}



实例示范


[root@ansible ~]# vim test3.yaml

- hosts: centos6

  remote_user: root

  vars:                

   - first: hello

  tasks:

   - name: first test

     shell: echo {{ first }} > /tmp/first.test

   - name: second test

     shell: echo {{ second }} > /tmp/second.test

   - name: facts

     shell: echo {{ ansible_product_serial }} > /tmp/third.test


playbook核心元素之 --> 模板template 介绍


templates:文件文件,内部嵌套有模板语言脚本(使用模板语言编写)



[root@ansible ~]# ansible-doc -l | grep "^\<template\>" --> template是一个模块


template   Templates a file out to a remote server.


[root@node1 ~]# ansible-doc -s template  --> 查看 template模块的参数

src=

dest=

mode=

onwer=

group=

...


注意:此模拟不能在命令行使用,而只能用于playbook



实际使用范例


[root@ansible ~]# vim test4.yaml

- hosts: centos7

  remote_user: root

  tasks:

   - name: install httpd

     yum: name=httpd state=latest

   - name: copy config file

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

     notify: restart httpd service

   - name: start httpd service

     service: name=httpd state=started

  handlers:

   - name: restart httpd service

     service: name=httpd state=restarted

yaml语法之 条件测试,循环,tags 介绍


条件测试

when语句:在tasks中使用。


[root@ansible ~]# vim test5.yaml

- hosts: centos6-7

  remote_user: root

  tasks:

   - name: install httpd

     yum: name=httpd state=latest

   - name: start centos6 httpd

     shell: service httpd start

     when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6"  --> facts变量

   - name: start centos7 httpd

     shell: systemctl start httpd.service

     when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"

循环:迭代,需要重复执行的任务


对迭代项的引用,固定变量名为 "item",使用with_item属性给定要迭代的元素;


[root@ansible ~]# vim test6.yaml

- hosts: centos7

  remote_user: root

  tasks:

   - name: create groups

     group: name={{ item }} state=present

     with_items:

      - groupx1

      - groupx2

   - name: create users

     user: name={{ item.name }} group={{ item.group }} state=present

     with_items:

      - {name: 'userx1', group: 'groupx1'}

      - {name: 'userx2', group: 'groupx2'}



tags:给指定的任务定义一个调用标识



[root@ansible ~]# vim test7.yaml

- hosts: centos7

  remote_user: root

  tasks:

   - name: install httpd

     yum: name=httpd state=latest

   - name: copy config file

     copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf

     tags: httpdconf

   - name: start httpd service

     service: name=httpd state=started

   - name: print date

     shell: /usr/bin/date

     tags: showdate

playbook核心元素之 --> 角色role


角色:

以特定的层级目录结构进行组织的tasks、variables、handlers、templates、files等;

role_name/

    files/:存储由copy或script等模块调用的文件; 

    tasks/:此目录中至少应该有一个名为main.yml的文件,用于定义各task;

         其它的文件需要由main.yml进行"包含"调用;

    handlers/:此目录中至少应该有一个名为main.yml的文件,用于定义各handler;

       其它的文件需要由main.yml进行"包含"调用;

    vars/:此目录中至少应该有一个名为main.yml的文件,用于定义各variable;

         其它的文件需要由main.yml进行“包含”调用;

     templates/:存储由template模块调用的模板文本;

    meta/:此目录中至少应该有一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关

         系;其它的文件需要由main.yml进行"包含"调用;

    default/:此目录中至少应该有一个名为main.yml的文件,用于设定默认变量;


实例


[root@ansible roles]# pwd

/etc/ansible/roles  --> 配置文件中定义的默认路径

[root@ansible roles]# mkdir nginx

[root@ansible roles]# tree nginx

nginx

├── default

├── files

├── handlers

│   └── main.yml

├── meta

├── tasks

│   └── main.yml

├── templates

│   └── nginx.conf.j2

└── vars

    └── main.yml



[root@ansible roles]# vim nginx/tasks/main.yml

- name: install nginx

  yum: name=nginx state=present

  tags: insngx

- name: install conf file

  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

  tags: ngxconf

  notify: reload nginx service

- name: start nginx service

  service: name=nginx enabled=true state=started



[root@ansible roles]# vim nginx/templates/nginx.conf.j2 

//可以简单修改端口号测试

//在配置文件中引用一个变量



[root@ansible roles]# vim nginx/handlers/main.yml

- name: reload nginx service

  service: name=nginx state=restarted



[root@ansible roles]# vim nginx/vars/main.yml 

ngxport: "8090"  --> 修改nginx监听的端口测试



编写playbook调用角色



[root@ansible roles]# vim nginx.yml  

--> 配置文件中定义的位置(/etc/ansible/ansible.cfg )

- hosts: centos7

  remote_user: root

  roles:

   - nginx


测试


[root@ansible roles]# ansible-playbook nginx.yml 





安装方式:采用epel源安装


a安装epel源:
    yum install wget
    wget dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
    rpm -ivh epel-release-6-8.noarch.rpm
    yum -y install ansible


b安装epel源:
    rpm -ivh http://mirror.serverbeheren.nl/epel/6/x86_64/epel-release-6-8.noarch.rpm
    yum install ansible -y

以上两种epel源都可以使用




ansible是基于ssh通信的,所以需要ssh密码共享,节点服务器192.168.1.155,ansible控制端服务器192.168.1.11


基于ssh与节点通信:


    ssh-keygen -t rsa -P ''
    ssh-copy-id -i .ssh/id_rsa.pub root@192.168.1.155

ansible命令使用


    ansible -m -a 

    -f forks:默认为5个,没有超过可以不用定义

    -m command:命令操作(默认模块)

    -s:以sudo模式

    ansible all -m command -a "date"

    ansible all -m command -a "service httpd status"

    或者直接省略-m command:


    ansible all -a "ls /tmp"




首先定义hosts文件:

vim /etc/ansible/hosts

[web]
192.168.1.155


实例演示:


ansible-doc -s copy

    ansible web -m copy -a "src=/root/ansible.tar.gz dest=/tmp/"

    ansible web -m command -a "ls /tmp"


ansible-doc -s cron
    ansible web -m cron -a 'name="custom job" minute=*/3 hour=* day=* month=* weekday=* job="/usr/sbin/ntpdate 192.168.31.1"'

    ansible web -a "crontab -l"


ansible-doc -s group

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

    ansible web -a "tail -1 /etc/group"


ansible-doc -s user

    ansible all -m user -a "":group:基本组,groups:附加组


ansible-doc -s yum

    ansible web -m yum -a "state=present name=corosync"

    ansible web -a "rpm -qa corosync"


ansible-doc -s service

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

    ansible web -a "chkconfig --list httpd"

    ansible web -m file -a "dest=/tmp/test.txt group=root mode=600 state=touch"


更多模块参考:
    ansible-doc -l:列出所有的模块

    ansible-doc -s module_name:指出指定模块对应的参数


当使用ansible第一次copy时,遇到如下错误:


[root@RS2 log]# ansible web -m copy -a "src=/root/test.sh dest=/tmp"
192.168.31.115 | FAILED! => {
    "changed": false, 
    "checksum": "31d5f2c4016e2081d99dcd52bf1ab19f48db767e", 
    "failed": true, 
    "msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
}
上述秒数应该是提示libselinux-python没有安装上,于是将它安装


[root@RS2 log]# ansible web -m yum -a "name=libselinux-python state=present"


再次copy:


[root@RS2 log]# ansible web -m copy -a "src=/root/test.sh dest=/tmp"

192.168.31.115 | SUCCESS => {
    "changed": true, 
    "checksum": "31d5f2c4016e2081d99dcd52bf1ab19f48db767e", 
    "dest": "/tmp/test.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "7aa31a8e7374035b1869a50b12544605", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 181, 
    "src": "/root/.ansible/tmp/ansible-tmp-1463435307.96-222484590205418/source", 
    "state": "file", 
    "uid": 0
}
于是成功解决错误

简单说几个模块:

模块之一:setup(用来查看远程主机的一些基本信息)


    ansible web -m setup


模块之file:

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

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

    link:创建软链接
    hard:创建硬链接
    touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
    absent:删除目录、文件或者取消链接文件


模块之- template: Templates a file out to a remote server.

             ansible web -m template -a "src=/root/ansible/httpd.yaml dest=/tmp":只能复制file,不能复制目录


模块之copy:既能复制文件,也能复制目录


    [root@RS2 ansible]# ansible web -m template -a "src=/root/ansible/test dest=/tmp"

192.168.1.155 | FAILED! => {
    "changed": false, 
    "failed": true, 
    "msg": "IOError: [Errno 21] Is a directory: u'/root/ansible/test'"
}


[root@RS2 ansible]# ansible web -m copy -a "src=/root/ansible/test dest=/tmp"
192.168.1.155 | SUCCESS => {
    "changed": false, 
    "dest": "/tmp/", 
    "src": "/root/ansible/test"
}

学会模块使用之后就是playbook的编写使用了(基于yaml语言)

playbook:

检测语法错误,并不执行:


[root@RS2 ansible]# ansible-playbook debug.yaml --syntax-check(检测语法)

playbook: debug.yaml

http.yaml
[root@RS2 ansible]# cat httpd.yaml 
- hosts: web
  remote_user: root
  tasks:
    - name: install httpd
      yum: name=httpd state=present
      notify: 
      - start httpd
  handlers:
    - name: start httpd
      service: name=httpd state=started enabled=yes

[root@RS2 ansible]# ansible-playbook httpd.yaml 


PLAY [web] *********************************************************************


TASK [setup] *******************************************************************
ok: [192.168.1.155]


TASK [install httpd] ***********************************************************
changed: [192.168.1.155]


RUNNING HANDLER [start httpd] **************************************************
changed: [192.168.1.155]


PLAY RECAP *********************************************************************
192.168.1.155              : ok=3    changed=2    unreachable=0    failed=0  


在playbook中使用item及with_items    copy multi files to destination

[root@RS2 ansible]# cat template.yaml 

- hosts: web
  remote_user: root
  tasks:
    - name: copy multi file to destination
      template: src=/root/ansible/httpd.yaml dest=/tmp/{{item}}:多个项目同时更新
      with_items:
        - httpd001.yaml
        - httpd002.yaml
        - httpd003.yaml

多项目执行:
    - name: touch files with an optional mode

      file: dest={{item.path}} state=touch mode={{item.mode|default(omit)}}
      with_items:
        - path: /tmp/foo
        - path: /tmp/bar
        - path: /tmp/baz
          mode: "0444"
      
[root@RS2 ansible]# cat loop.yaml
- hosts: web
  remote_user: root
  tasks:
   - name: echo variables
     shell: echo {{ item }}
     with_items: [ 2,3 ]

[root@RS2 ansible]# cat loop.yaml.bak 
- hosts: web
  remote_user: root
  tasks:
   - name: echo variables
     shell: echo {{ item }}
     with_items: 
       - 2
       - 3


when条件使用:

tasks:
  - name: "shutdown Debian flavored systems"
    command: /sbin/shutdown -t now
    when: ansible_os_family == "Debian"
    
tasks:
  - name: "shutdown CentOS 6 and Debian 7 systems"
    command: /sbin/shutdown -t now
    when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or
          (ansible_distribution == "Debian" and ansible_distribution_major_version == "7")


[root@RS2 ansible]# cat delete.yaml 
- hosts: web
  remote_user: root
  tasks:
    - name: delete any file
      shell: rm -f /tmp/httpd.yaml
      when: ansible_os_family == "RedHat":判断节点服务器是否为RedHat系列,是的话就删掉文件


ansible_os_family该值是模块setup中的结果信息

- hosts: web
  remote_user: root
  tasks:
    - name: delete someone file
      file: dest=/tmp/httpd/yaml state=absent
      fatal: [192.168.1.155]: FAILED! => {"changed": false, "failed": true, "msg": 
      "value of state must be one of: file,directory,link,hard,touch,absent, got: abent"}


删除文件两种方式,推荐file:

1、file: dest=/tmp/httpd/yaml state=absent

2、shell: rm -f /tmp/httpd.yaml

引用变量加条件when:


[root@RS2 ansible]# cat peci.yaml 
- hosts: web
  remote_user: root
  vars: 
    peci: true:此处变量可自定义
  tasks:
    - name: judge peci
      shell: echo "hello world"
      when: peci


注册变量:

[root@RS2 ansible]# cat variables.yaml 
- hosts: web
  remote_user: root
  tasks: 
   - name: judge file 
     shell: ls /root/ansible
     register: home_dirs
   - name: copy file
     template: src=/root/ansible/{{ item }} dest=/tmp/{{ item }} 
     with_items: home_dirs.stdout.split()----》注册变量的值


利用变量进行替换,以及when结合register的使用,当register的变量result执行成功,when:result|success就继续安装步骤执行

result|success这也就代表注册变量的返回值是成功的

[root@RS2 ansible]# cat test.yaml 
- hosts: web
  remote_user: root
  vars:
    apache: httpd
  tasks:
   - name: install httpd
     yum: name={{ apache }} state=present
     register: result:将上步骤执行的结果注册到变量result中
   - name: start httpd
     service: name=httpd state=started enabled=yes
     when: result|success:当result变量是成功的话,就执行是service步骤


[root@RS2 ansible]# cat test.yaml 
- hosts: web
  remote_user: root
  vars:
    apache: httpd
  tasks:
   - name: install httpd
     yum: name={{ apache }} state=present
     register: result
   - name: start httpd
     service: name=httpd state=started enabled=yes
     when: result|success
   - name: display time:这一步骤并没有执行,退出了,证明了失败了才会执行
     shell: date
     when: result|failed
TASK [display time] ************************************************************
skipping: [192.168.1.155]

[root@RS2 ansible]# cat test.yaml 
- hosts: web
  remote_user: root
  vars:
    apache: httpd
  tasks:
   - name: install httpd
     yum: name={{ apache }} state=present
     register: result
   - name: start httpd
     service: name=httpd state=started enabled=yes
     when: result|success
   - name: display time
     shell: date
     when: result|failed

[root@RS2 ansible]# vim test.yaml

[root@RS2 ansible]# ansible-playbook test.yaml --syntax-check


playbook: test.yaml
[root@RS2 ansible]# ansible-playbook test.yaml 

PLAY [web] *********************************************************************

TASK [setup] *******************************************************************
ok: [192.168.1.155]

TASK [install httpd] ***********************************************************
fatal: [192.168.1.155]: FAILED! => {"changed": true, "cmd": "ls /root/ansible", "delta": "0:00:00.021731", "end": "2016-07-30 16:58:19.750658", "failed": true, "rc": 2, "start": "2016-07-30 16:58:19.728927", "stderr": "ls: 无法访问/root/ansible: 没有那个文件或目录", "stdout": "", "stdout_lines": [], "warnings": []}

NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit @test.retry

PLAY RECAP *********************************************************************可以看出并没有执行failed错误的那条date命令,表明错误操作就直接不进行下面操作
192.168.1.155              : ok=1    changed=0    unreachable=0    failed=1   


[root@RS2 ansible]# cat test.
test.retry  test.yaml   
[root@RS2 ansible]# cat test.yaml 
- hosts: web
  remote_user: root
  vars:
    apache: httpd
  tasks:
   - name: install httpd
     shell: ls /root/ansible
     register: result
     ignore_errors: True:接入忽略错误,加入了这行后面failed操作步骤继续运行
   - name: start httpd
     service: name=httpd state=started enabled=yes
     when: result|success
   - name: display time
     shell: date
     when: result|failed

[root@RS2 ansible]# ansible-playbook test.yaml 

PLAY [web] *********************************************************************

TASK [setup] *******************************************************************
ok: [192.168.1.155]

TASK [install httpd] ***********************************************************
fatal: [192.168.1.155]: FAILED! => {"changed": true, "cmd": "ls /root/ansible", "delta": "0:00:00.009894", "end": "2016-07-30 17:01:51.789377", "failed": true, "rc": 2, "start": "2016-07-30 17:01:51.779483", "stderr": "ls: 无法访问/root/ansible: 没有那个文件或目录", "stdout": "", "stdout_lines": [], "warnings": []}
...ignoring


TASK [start httpd] *************************************************************上述result是错误结果,所以skip
skipping: [192.168.1.155]


TASK [display time] ************************************************************此处命令成功:ignore_errors: True是加入了这一行
changed: [192.168.1.155]


PLAY RECAP *********************************************************************
192.168.1.155              : ok=3    changed=1    unreachable=0    failed=0  


定义变量,替换文件名,进行copy

[root@RS2 ansible]# cat test1.
test1.retry  test1.yaml   
[root@RS2 ansible]# cat test1.yaml 
- hosts: web
  remote_user: root
  vars:
   src_file: test.yaml
  tasks:
   - name: copy test.yaml to destination
     copy: src=/root/ansible/{{ src_file }} dest=/tmp/{{ src_file }}
     
[root@RS2 ansible]# ansible-playbook test1.yaml 

PLAY [web] *********************************************************************

TASK [setup] *******************************************************************
ok: [192.168.1.155]

TASK [copy test.yaml to destination] *******************************************
changed: [192.168.1.155]

PLAY RECAP *********************************************************************
192.168.1.155              : ok=2    changed=1    unreachable=0    failed=0 


错误样例:
[root@RS2 ansible]# cat test1.yaml 
- hosts: web
  remote_user: root
  vars:
   src_file: /root/ansible/test.yaml
  tasks:
   - name: copy test.yaml to destination
     copy: src={{ src_file }} dest=/tmp/{{ src_file }}


[root@RS2 ansible]# ansible-playbook test1.yaml 


PLAY [web] *********************************************************************

TASK [setup] *******************************************************************
ok: [192.168.1.155]

TASK [copy test.yaml to destination] *******************************************
fatal: [192.168.1.155]: FAILED! => {"changed": false, "checksum": "f0f36e6c39f0fdd58399e8cccaa9dcf30e1cef18", "failed": true, "msg": "Destination directory /tmp//root/ansible does not exist"}

NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit @test1.retry

PLAY RECAP *********************************************************************
192.168.1.155              : ok=1    changed=0    unreachable=0    failed=1   


安装lamp
[root@RS2 ansible]# cat lamp.yaml 
- hosts: web
  remote_user: root
  tasks:
  - name: install php php-mysql httpd
    yum: name={{ item }} state=present
    with_items: 
      - httpd
      - php
      - php-mysql
      - mysql-server
    register: result
  - name: start httpd server
    service: name=httpd state=started enabled=yes
    when: result|success
  - name: start mysql server
    service: name=mysqld state=started enabled=yes
    when: result|success


[root@RS2 ansible]# ansible-playbook lamp.yaml 

PLAY [web] *********************************************************************

TASK [setup] *******************************************************************
ok: [192.168.1.155]

TASK [install php php-mysql httpd] *********************************************
changed: [192.168.1.155] => (item=[u'httpd', u'php', u'php-mysql', u'mysql-server'])

TASK [start httpd server] ******************************************************
changed: [192.168.1.155]

TASK [start mysql server] ******************************************************
changed: [192.168.1.155]

PLAY RECAP *********************************************************************
192.168.1.155              : ok=4    changed=3    unreachable=0    failed=0  

file做文件覆盖到节点目标机:

[root@RS2 tmp]# cat copy.yaml 
- hosts: web
  remote_user: root
  tasks: 
   - name: copy file to destination
     file: src=/tmp/yum.log dest=/tmp/yum.log state=touch


[root@RS2 tmp]# ansible-playbook copy.yaml 

PLAY [web] *********************************************************************

TASK [setup] *******************************************************************
ok: [192.168.1.155]

TASK [copy file to destination] ************************************************
changed: [192.168.1.155]

PLAY RECAP *********************************************************************
192.168.1.155              : ok=2    changed=1    unreachable=0    failed=0   


roles:

roles:在/etc/ansible/roles/下面创建一个role名称(比如nginx为例)

roles内各目录中可用的文件

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

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

templates目录:templates模块会自动在此目录中寻找Jinjia2模板文件:

handlers目录:此目录中应当包含一个main。

yml文件:用于定义此角色用到的各handler:在handler中使用include包含的其他的handler文件也应该位于此目录中:

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

meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系:ansible 1.3及其以后的版本才支持

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


    handlers:目录

    handler/main.yaml
    ---
    - name: start nginx
      service: name=nginx state=started
    - name: reload nginx
      service: name=nginx state=reloaded

    Meta:目录

    Meta/main.yaml
    ---
    dependencies:
      - { roles: ssl }

    templates
    templates/serversforhackers.com.conf:一个配置文件就行

    variables

    vars/main.yml
    ---
    domain: www.my.com
    http_port: 80
    tasks:
    tasks/main.yaml
    ---
    - name: install nginx
      yum: name=nginx state=present
      register: result
      notify: 
       - start nginx
    - name: copy configure file to destination
      template: src=/path/to/serversforhackers.com.conf.j2
      dest=/path/to/serversforhackers.com.conf owner=root group=root
    - name: create web root directory 
      file: dest=/www/html owner=nginx group=nginx state=directory mode=775 recurse=yes
      notify: 
- reload nginx
  
  
实例验证:
[root@RS2 nginx]# cat handlers/main.yaml 
---
- name: start httpd
  service: name=httpd state=started

- name: restart httpd
  service: name=httpd state=restarted


[root@RS2 nginx]# cat tasks/main.yaml 
---
- name: install httpd
  yum: name=httpd state=present
  notify:
   - start httpd
- name: copy the configure file to destination
  template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
  notify: 
   - restart httpd


[root@RS2 nginx]# cat templates/httpd.conf.j2 :也就是httpd.conf配置文件后缀加上j2


[root@RS2 nginx]# cat vars/main.yaml 
---
http_port: 80

[root@RS2 workflow]# cat install_httpd.yaml 
---
- hosts: web
  remote_user: root
  roles:
   - nginx

[root@RS2 ansible]# tree整个目录结果
.
|-- ansible.cfg
|-- hosts
|-- hosts.bak
|-- roles
|   `-- nginx----》角色名
|       |-- files
|       |-- handlers-----》定义后续notify的处理play
|       |   `-- main.yaml
|       |-- meta----》定义依赖
|       |-- tasks-----》定义任务执行play
|       |   `-- main.yaml
|       |-- templates----》定义模板文件
|       |   `-- httpd.conf.j2
|       `-- vars:定义变量
|           `-- main.yaml
`-- workflow-----》工作目录,存放各种playbook来执行角色
    |-- install_httpd.retry
    `-- install_httpd.yaml-----playbook来执行整个roles下的nginx     



【安装】

  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 <-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 的话上面的这种情况你会用的到.


相关内容

    暂无相关文章