ansible可以批量管理多台主机。通过调用各个功能模块、ssh连接、发送python脚本、远程主机上的一些命令来完成管理各被控端,所以不用给各被管理节点专门安装客户端工具。


不过一般需要事先配置ansible端能基于密钥认证的方式联系各被管理节点。

如果要用密码的方式,要启用主配置文件中的ask_pass  = True,并安装上sshpass软件即可


目录:

一、介绍

二、常用模块介绍

三、playbook

四、roles


ansible_第1张图片


想深入了解的朋友请看这里:http://www.ansible.com.cn/

或这里:http://docs.ansible.com/


一、介绍:

模块化,调用特定的模块来完成特定任务;
基于Python语言实现,由Paramiko, PyYAML和Jinja2三个关键模块>实现;
支持自定义模块
支持playbook: 可以把多个任务编排好,一次性的执行完。
幂等性:多次执行的结果是一样的。


ansible命令的使用方式还是很简单的:

ansible [-f forks] [-m module_name] [-a args]

host_pattern 是来指定主机的,可以是单台主机,也可以是主机组。前提是要在ansible的hosts配置文件中指定。

-f 指定一次批量管理的主机数量。 可以说就是并发管理数量。 与总的数量没有关系。

-m 指定模块。

-a  模块参数


它所有的管理功能都是由各个模块所提供,查看模块使用方法:

ansible-doc [-M module_path] [-l] [-s] [module...]

-M 查看模块的详细信息,要指定模块的路径

-l   列出所有模块。

-s  查看模块使用方式。


安装:

ansible依赖于Python 2.6或更高的版本、paramiko、PyYAML及Jinja2。

编译安装

# yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto
# python setup.py build
# python setup.py install
# mkdir /etc/ansible
# cp -r examples/* /etc/ansible


注意:不同版本的ansible的功能差异可能较大。

我这里就直接yum安装了。

环境:

系统: CentOS Linux release 7.1.1503 (Core)

软件: ansible-1.9.2-1.el7


看一下所生成的文件:

/etc/ansible
/etc/ansible/ansible.cfg          #ansible主配置文件。  一般不用修改,如果想自定义一下,请看上面的网址。
/etc/ansible/hosts                   #主配置文件中所指定的主机清单文件 
/etc/ansible/roles                   #用来定义roles的目录
/usr/bin/ansible                      
/usr/bin/ansible-doc
/usr/bin/ansible-galaxy
/usr/bin/ansible-playbook
.....


首先我们需要在hosts里面定义各被管主机。这个文件被称为inventory文件。

[root@localhost ~]# vim /etc/ansible/hosts      
[wserver]
172.16.40.11
172.16.40.12

[dbserver]
172.16.40.20

这个文件里面都是一些定义主机的例子,我这里把它们注释了,添加了上面几个。

inventory文件遵循INI文件风格,中括号中的是组名,可以用各个组名表示多个主机。 也可以用all来表示所有主机。 当然也可以使用单个主机。同一个主机可以出现在多个组中。

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

如: 172.16.40.11:22022

组还可以包含其它的组,组嵌套。


在这里如果所管理主机的系统版本不一样也没问题,因为ansible会检测主机的系统参数并做出不同的设置。但并不是绝对不会有问题。

每次执行操作会发送python脚本到客户端的   对应用户家目录下的.ansible/tmp目录下面。 具体作用暂时不清楚,可能是用来收集信息、执行任务和调用本地的命令的吧。


二、常用模块介绍:

这里只是常用的部分,详细的可以用ansible-doc来查看。如查看一下user模块。

[root@localhost ~]# ansible-doc -s user

带=号的表示必选项。

http://docs.ansible.com/ansible/modules_by_category.html


user: 用户管理

state={present|absent}   #present表示创建,absent表示删除。
force=yes          #强制删除用户。 一般情况下用户在已登录状态下是不能删除的。相当于userdel -f
remove=yes     #在删除用户的时候,同时删除家目录与mail spool。相当于userdel -r    
system=yes   #创建的系统用户   
uid                #指定uid
shell             #指定shell
password       #用来指定密码,要用已加密的密码。

上面的password后面的密码可以用openssl passwd 来生成。但是好像只能是md5加密的。

[root@localhost ~]# openssl passwd --help
Usage: passwd [options] [passwords]
where options are
-crypt             standard Unix password algorithm (default)
-1                 MD5-based password algorithm
.....

例:

[root@localhost ~]# openssl passwd -1 
Password: 
Verifying - Password: 
$1$.0isU960$NDoCtqtkDBa2q9TQJYQml1

[root@localhost ~]# ansible all -m user -a 'name=test1 password="$1$.0isU960$NDoCtqtkDBa2q9TQJYQml1"'
172.16.40.11 | success >> {
    "changed": true,                                                                                                                        
    "comment": "",                                                                                                                          
    "createhome": true,                                                                                                                     
    "group": 1007,                                                                                                                          
    "home": "/home/test1",                                                                                                                  
    "name": "test1",                                                                                                                        
    "password": "NOT_LOGGING_PASSWORD",                                                                                                     
    "shell": "/bin/bash",                                                                                                                   
    "state": "present",                                                                                                                     
    "system": false,                                                                                                                        
    "uid": 1007                                                                                                                             
} 
.....

删除:

[root@localhost ~]# ansible all -m user -a 'name=test1 state=absent'


group: 组管理

  action: group
      gid                    # Optional `GID' to set for the group.
      name=             # Name of the group to manage.
      state                 # Whether the group should be present or not on the remote host.
      system             # If `yes', indicates that the group created is a system group.

与user差不多,而且参数也就只有这几个。


cron:  管理cron计划任务

      day                    # Day of the month the job should run ( 1-31, *, */2, etc )
      hour                   # Hour when the job should run ( 0-23, *, */2, etc )
      job                    # The command to execute. Required if state=present.
      minute                 # Minute when the job should run ( 0-59, *, */2, etc )
      month                  # Month of the year the job should run ( 1-12, *, */2, etc )
      name=                  # Description of a crontab entry.
      state                  # Whether to ensure the job is present or absent.
      user                   # The specific user whose crontab should be modified.
      weekday                # Day of the week that the job should run ( 0-6 for Sunday-Saturday, *, etc )
      .....

只要使用过cron,我想也不用过多解释吧。state与上面的模块一个意思,时间参数不写表示*。

name用来描述任务,andible也用它来识别各个添加的任务,才能用来删除不同的任务。

如果有name相同的任务,会覆盖。


例:

[root@localhost ~]# ansible wserver -m cron -a 'name=sync_time minute=*/5 job="/sbin/ntpdate 172.16.0.1 > /dev/null;/sbin/hwclock -w"'

连到一台主机看一下crontab。

[root@localhost ~]# crontab -l
*/15 * * * * /sbin/ntpdate 172.16.0.1 > /dev/null;/sbin/hwclock > /dev/null    #这个是原来就有的。
#Ansible: sync_time                #这个就是我们刚添加的。
*/5 * * * * /sbin/ntpdate 172.16.0.1 > /dev/null;/sbin/hwclock -w

删除:

[root@localhost ~]# ansible wserver -m cron -a 'name=sync_time state=absent'


例: 添加每2天的2:30备份/etc目录到/var/backup下。

[root@localhost ~]# ansible wserver -m cron -a 'name=etc_tar minute=30 hour=2 day=*/2 job="/bin/tar -Jcf /var/backup/`/bin/date "+\\%Y\\%m\\%d-\\%H\\%M"`.tar.xz /etc"'

查看一下:

#Ansible: etc_tar
30 2 */2 * * /bin/tar -Jcf /var/backup/`/bin/date +\%Y\%m\%d-\%H\%M`.tar.xz /etc


ping: 探测主机是否在线

[root@localhost ~]# ansible all -m ping

这个模块没有参数,只是用来探测主机是否在线的。


file: 文件管理

path=            #表示文件路径,必选项。
mode            #表示设置权限
owner            #属主  
group             #属组
state=directory      #创建目录或修改目录权限。
state=touch            #创建文件或修改文件权限。
state=file                 #修改文件权限。
state=link                #创建文件的符号链接。src=源文件   path=链接文件
state=absent           #删除文件或目录。

创建目录是递归创建的,也就是会自动创建所需的目录。 而文件或链接文件都不行。


例:创建目录。

[root@localhost ~]# ansible wserver -m file -a 'path=/var/backup/ state=directory'
[root@localhost ~]# ansible wserver -m file -a 'path=/tmp/6/7/8/9  state=directory'

例:创建链接文件。把etc目录链接至/tmp/etc。

[root@localhost ~]# ansible wserver -m file -a 'path=/tmp/etc src=/etc  state=link'


copy: 复制文件

content          #代替src,设置文件中的内容为指定的内容。如果目标文件不存在,则自动创建随机名称文件。
                                   #如果原来文件有数据,则覆盖。  暂时不知道有什么用。
src                    #源文件路径。
owner              #属主。
group                #属组。
mode                #权限。   
dest=                 #目标路径。
backup              #覆盖文件之前,先备份。 yes/no


例: 把/etc/nginx目录复制到远程主机的/etc/下面。

[root@localhost ~]# ansible wserver -m copy -a 'src=/etc/nginx dest=/etc/'


例:复制本地的/home/star/httpd.conf文件到远程主机的/etc/httpd/conf/目录下,并修改权限。

ansible wserver -m copy -a 'src=/home/star/httpd.conf owner=root group=root mode=644 dest=/etc/httpd/conf/'


例: 修改远程主机的/var/listen文件内容为, 第一行listen=80 第二行listen=8080

[root@localhost ~]# ansible wserver -m copy -a 'content="listen=80\nlisten=8080\n" dest=/var/listen'

查看一下远程主机的这个文件:

[root@localhost ~]# ssh 172.16.40.11 'cat /var/listen'
listen=80
listen=8080


template:模板复制文件

也是用来复制数据的,只不过文件中的数据可以用变量替换,为不同的主机附加不同的变量,会把文件中定义的变量在发送之前转换为给对应主机所定义的变量的值,也就可以实现不同的主机所复制的文件中的数据是不同的。

而同组中主机定义不同的变量可以通过定义主机变量来实现

主机变量:定义在inventory中的主机之后的变量

如:

/etc/ansible/hosts文件中的主机后面加上变量。

[wserver]
172.16.40.11 port=8800
172.16.40.12 port=8888

要复制的源文件中引用变量可以这样: Listen ` port `

但我这里好像说当前版本中template不支持命令行使用

[root@localhost ~]# ansible wserver -m template -a 'src=/home/star/http.conf dest=/etc/httpd/conf'
172.16.40.11 | FAILED => in current versions of ansible, templates are only usable in playbooks
172.16.40.12 | FAILED => in current versions of ansible, templates are only usable in playbooks

一会儿在playbooks的时候再来说明template模块。 其它变量也在那里说明。


yum: yum安装软件,也有apt,zypper。

conf_file         #设定远程yum安装时所依赖的配置文件。如配置文件没有在默认的位置。
disable_gpg_check    #是否禁止GPG checking,只用于`present' or `latest'。
disablerepo   #临时禁止使用yum库。 只用于安装或更新时。
enablerepo    #临时使用的yum库。只用于安装或更新时。
name=            #所安装的包的名称
state               #present安装, latest安装最新的, absent 卸载软件。
update_cache  #强制更新yum的缓存。


例:安装httpd。

这里只是说明一下conf_file的用法,yum的仓库文件没有在/etc/yum.repos.d/目录下的话。

[root@localhost ~]# ansible wserver -m yum -a 'name=httpd state=present conf_file="/root/local.repo"'


如果库本来是禁止使用的,就要用enablerepo来临时使用这个库。

这里的yum库文件已经在/etc/yum.repos.d/目录下了,不需要conf_file指定配置文件了。

[root@localhost html]# ansible wserver -m yum -a 'name=httpd state=present enablerepo=local'

这里的库ID 就是local.


卸载:

[root@localhost html]# ansible wserver -m yum -a 'name=httpd state=absent'

注意:返回的数据的    "changed": true, 


安装包组,只要在名称前面加上@就可以了。

如:安装开发工具的包组:

[root@localhost html]# ansible dbserver -m yum -a 'name="@Development Tools" state=present'


service: 服务程序管理


arguments            #命令行提供额外的参数
enabled                 #设置开机启动。
name=                  #服务名称
runlevel                #开机启动的级别,一般不用指定。
sleep                     #在重启服务的过程中,是否等待。如在服务关闭以后等待2秒再启动。
state                      #started启动服务, stopped停止服务, restarted重启服务, reloaded重载配置。

启动httpd服务:

[root@localhost html]# ansible all -m service -a 'name=httpd state=started'

设置开机启动:

[root@localhost ~]# ansible all -m service -a 'name=httpd enabled=yes'

重启服务:

[root@localhost ~]# ansible all -m service -a 'name=httpd sleep=2 state=restarted'


command: 直接执行命令,默认模块,可以不用指定。

显示所有主机时间:

[root@localhost ~]# ansible all -a 'date'
172.16.40.20 | success | rc=0 >>
Thu Feb 11 16:04:37 CST 2016

172.16.40.12 | success | rc=0 >>
Thu Feb 11 16:04:37 CST 2016

172.16.40.11 | success | rc=0 >>
Thu Feb 11 16:04:37 CST 2016


这个模块与shell差不多,但是不能执行管道类的操作,如:

ansible_第2张图片

还有点不同是,command是在当前shell所执行的命令,而shell是在子shell中执行的命令。但是在被控端和管理端用pstree查看进程的时候,却也没发现不一样的。这个说法现在是有点不明白。


shell: 直接执行命令,参数一般也用不到。

这个可以执行管道类的命令,如:

ansible_第3张图片


script:发送脚本到各被管理节点,并执行。同样不需要参数。

[root@localhost ~]# ansible all -m script -a 'test.sh'

直接在-a 后面指定脚本即可。


selinux: 管理selinux。

conf     #指定应用selinux的配置文件。
state=enforcing|permissive|disabled           #对应于selinux配置文件的SELINUX。
policy=targeted|minimum|mls        #对应于selinux配置文件的SELINUXTYPE

关闭selinux:

[root@localhost ~]# ansible all -m selinux -a 'state=disabled'

在selinux处于enforceing状态下的时候好像只能用permissive。

在state非disabled的情况下必须要指定policy。


setup:获取指定主机的facts。

facts是由正在通信的远程目标主机发回的信息,这些信息被保存在ansible变量中。

[root@localhost ~]# ansible 172.16.40.11 -m setup

 返回很多对应主机的信息,在后面的操作中可以根据不同的信息来做不同的操作。如redhat系列用yum安装,而debian系列用apt来安装软件。



三、playbook。

playbook就是一个用yaml语法把多个模块堆起来的一个文件而已。

yaml: http://www.yaml.org


3.1: 结构介绍

playbooks核心元素:
Tasks            定义任务
Variables      定义变量
Templates      定义模板
Handlers        Notify 处理
Roles


除了核心元素以外还有额外的元素,而每个元素也包含了独有的元素。

YAML参考了多种语言,其中就有python。所以在写playbook的时候,段落缩进很重要。

看一下下面这个例子,最外围就是主要的元素,而各个主元素里面还有各个子元素。


每一个-开始表示一个列表的开始,到下一个-之前结束,也可以说这之间就是一个项目,一出戏。

各个列表之间是没有关系的,我们只要区分开也就不混乱了。tasks里面就是模块的使用了,所以整体来说结构还是很直观的。

        - hosts: 172.16.100.68        #定义主机
          vars:                      #定义变量
               var1: value
               var2: value
          tasks:                    #定义任务
               - name:           #任务名称。
                                        #这里就可以开始用模块来执行具体的任务了。
               - name:

               - name:

          handlers:             #定义触发通知所作的操作。里面也是跟tasks一样,用模块定义任务。
               - name:

          remote_user:             #远程主机执行任务时的用户。一般都是root,一般也不用指定。
        - hosts: 172.16.100.69
          vars:
          tasks:
          handlers:
          remote_user:


-表示一个列表的开始,一个列表表示一个独立的整体结构,而列表里面的元素(表项)是由字典组成的,字典中存储的就是各个要定义的键值。如:tasks是字典的键,里面的各部分是值。只不过这部分同时又是列表。

vars是用来定义变量的,所以里面的各变量都是字典而不是列表。只不过vars是字典的键,里面的两项是字典的值,而这个值同样也是字典。

网上有的说每一个-表示一个表项。不过意思差不多,只不过最外围加了一个列表而已。不过这样好乱啊。

这里跟使用没有关系,如果感觉混乱就不用管了。了解一下python的话也就容易理解了。


结构差不多也就是这样了,来补充点:
各字典项的键冒号与值之间要有空格。  如:hosts: abc

字典项要与-之间有空格。表示在结构内。并不是说Hosts特殊要在-的后面。 它也可以在下面的一行开始。如:

-
  hosts:
  tasks:


-表示列表的开始,后面的hosts跟下面的vars之类的都是同一级。不过要注意前面都要有两个空格的缩进,表示在此结构内。就好像是第一级结构为- ,  每二级结构与第一级结构之间要用空格隔开。


3.2:变量

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

变量种类:
1、facts:由远程主机发回的主机属性信息,这些信息被保存在ansible变量中;无须定义,可直接调用;
2、自定义变量:
        2.1、通过命令行传递: ansible-playbook  指令后面指定变量:--extra-vars "var1= var2=" ,简写 -e “vars="

        2.2、通过roles传递
        2.3、主机变量:定义在inventory中的主机之后的变量
        2.4、组变量:定义在inventory中的组上的变量。如:

[wserver]
172.16.40.11 port=8800
172.16.40.12 port=8888

[wserver:vars]
port=80

[dbserver]
172.16.40.20

[dbserver:vars]
port=3306


       2.5、在playbook的vars元素下面定义变量.

3.3 使用:

实现目标:

1、wserver组主机安装httpd。

2、复制本机已配置好的httpd配置文件到各主机。

3、启动httpd,并设置开机启动。

[root@localhost ~]# vim httpd.yml

- hosts: wserver
  remote_user: root
  tasks:
        - name: install httpd
          yum: name=httpd state=present
        - name: copy httpd configuration
          copy: src=/root/httpd dest=/etc/
        - name: start httpd
          service: name=httpd state=started
        - name: boot httpd start
          service: name=httpd enabled=yes

ansible_第4张图片

执行过程。用ansible-playbook来执行playbook文件。文件扩展名随意,我这里习惯用yml了。

ansible_第5张图片

***表示发生变化,绿色表示未变化,红色表示错误。 ok=5  changed=4 表示完成了5个,其中4个发生变化。


查看httpd是否启动:

[root@localhost ~]# ansible wserver -m shell -a 'ss -tnlp'            #直接查看信息,但多了以后。。。
[root@localhost ~]# ansible wserver -m shell -a 'ss -tnlp' | grep httpd | wc -l     #可以直接用wc来计数。

是否开机启动:

[root@localhost ~]# ansible wserver -m shell -a 'systemctl status httpd'
或者:
[root@localhost ~]# ansible wserver -m shell -a 'systemctl status httpd' | grep enabled | wc -l

条件判断

如果要管理有主机中有不同系列的系统,这里只是做个比喻。正常情况下应该连系统版本都是相同的。

比如有一台ubuntu的主机,因为它的软件管理用的是apt-get。在ansible里面是用apt模块来操作的。而且配置文件也不一样,软件的名称也不一样,服务脚本也不一样。额,复杂了好像。

只要在一个任务的最后加上when就可以了,意思是说只有当后面的条件满足的时候才执行此任务。

条件变量就是facts类的变量。可以用ansible 主机 -m setup来查看,上面模块部分也说了。可以用ansible_os_family这个变量。

wKioL1a8j0yQcyfaAAASa_qPiYc681.png

wKiom1a8jvCyT6tPAAATtIJtQMI735.png


httpd.yml

- hosts: wserver
  remote_user: root
  tasks:
        - name: install httpd redhat
          yum: name=httpd state=present
          when: ansible_os_family == "RedHat"
        - name: copy httpd configuration
          copy: src=/root/httpd dest=/etc/
          when: ansible_os_family == "RedHat"

        - name: install apache2 debian
          apt: name=apache2 state=present
          when: ansible_os_family == "Debian"
        - name: copy apache2 configuration
          copy: src=/root/apache2 dest=/etc/
          when: ansible_os_family == "Debian"

        - name: start httpd
          service: name=httpd state=started
          when: ansible_os_family == "RedHat"
        - name: boot httpd start
          service: name=httpd enabled=yes
          when: ansible_os_family == "RedHat"


        - name: start apache2
          service: name=apache2 state=started
          when: ansible_os_family == "Debian"
        - name: boot apache2 start
          service: name=apache2 enabled=yes
          when: ansible_os_family == "Debian"

ansible_第6张图片

执行效果:

ansible_第7张图片

ansible_第8张图片

这里因为apache2的配置文件没有修改,与安装完成所生成的配置一模一样,通过检验发现一样就不会再复制了。所以是绿色的字。

有没有发现这样麻烦的不是一星半点啊。


再贴一个删除这些软件的:

- hosts: wserver
  remote_user: root
  tasks:
        - name: stop httpd
          service: name=httpd state=stopped
          when: ansible_os_family == "RedHat"
        - name: erase httpd
          yum: name=httpd state=absent
          when: ansible_os_family == "RedHat"
        - name: erase /etc/httpd
          file: path=/etc/httpd state=absent
          when: ansible_os_family == "RedHat"

        - name: stop apache2
          service: name=apache2 state=stopped
          when: ansible_os_family == "Debian"
        - name: erase apache2
          apt: name=apache2 state=absent purge=yes
          when: ansible_os_family == "Debian"
        - name: erase /etc/apache2
          file: path=/etc/apache2 state=absent
          when: ansible_os_family == "Debian"


标签:

有时候只想用这个文件中的复制配置文件的功能,而不想再每一项都检查,虽然也没什么问题。

- hosts: wserver
  remote_user: root
  tasks:
        - name: install httpd redhat
          yum: name=httpd state=present

        - name: copy httpd configuration
          copy: src=/root/httpd dest=/etc/
          tags: config                                                #加了一个tags.

        - name: start httpd
          service: name=httpd state=started

        - name: boot httpd start
          service: name=httpd enabled=yes

ansible_第9张图片

我这里的httpd给重新安装了,所以配置文件是不同的,才会显示changed。不然会是绿色的ok。

现在只执行了config标符所指定的任务了。 我这里忘了把hosts文件中的172.16.40.1去掉了。

那么复制完配置文件以后应该重载配置文件才对。可是就算再添加一个任务,因为我们指定了标签也不会执行。那么就可以用handlers啦。


handlers:

也是task任务,但只有其关注的条件满足时,才会被触发执行。这里的条件其实就是发生修改。

如果我们复制配置文件和远程主机上的一样,那就不会触发了。

- hosts: wserver
  remote_user: root
  tasks:
        - name: install httpd redhat
          yum: name=httpd state=present

        - name: copy httpd configuration
          copy: src=/root/httpd dest=/etc/
          notify: reload httpd                            #添加了一行这个。用以触发名称为reload httpd的handlers。
          tags: config

        - name: start httpd
          service: name=httpd state=started

        - name: boot httpd start
          service: name=httpd enabled=yes
  handlers:
        - name: reload httpd
          service: name=httpd state=reloaded

现在配置文件没有修改之前:

ansible_第10张图片

修改之后:

ansible_第11张图片


templates:
用于生成文本文件(配置文件);模板文件中可使用jinja2表达式,表达式要定义在` `,也可以简单地仅执行变量替换;我们这里也只来演示一下变量替换的。

如我想给不同的主机的配置文件所监听的端口不一样。

可以通过主机变量,定义/etc/ansible/hosts文件:

[wserver]
172.16.40.11 port=8800
172.16.40.12 port=8888

修改要复制过去的配置文件,

httpd.conf

Listen {{ port }}        #httpd的配置文件,listen用来监听端口。在复制之前ansible会把{{ port }}替换为对应主机所设置的变量值。

现在的playbook文件:为了节省篇幅,我这里把现在用不到都删了。而因为是修改端口,所以把reload改成了restart。

- hosts: wserver
  remote_user: root
  tasks:
        - name: template httpd configuration
          template: src=/root/httpd/conf/httpd.conf dest=/etc/httpd/conf/         #src好像不能再指目录了。
          notify: restart httpd

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

ansible_第12张图片

一台主机监听在8800,一台主机监听在8888。


迭代:

如果想要批量创建多个用户怎么办,当然用script模块最简单了,不过这里也只是来说明一下问题而已:

在task中调用内置的item变量;在某个task后面使用with_items语句来定义元素列表;

- hosts: wserver
  remote_user: root
  tasks:
        - name: create test user
          user: name={{ item }} state=present
          with_items:
                - test1
                - test2
                - test3
                - test4

ansible_第13张图片

ansible_第14张图片


而上面所指定item还可以有子集, 可以用字典来表示item中的各个键值,而不只是用表示单个值。

如:

- hosts: wserver
  remote_user: root
  tasks:
        - name: create test user
          user: name={{ item.user }} group={{ item.group }} state=present
          with_items:
                - { user: "test10", group: "root" }
                - { user: "test11", group: "root" }
                - { user: "test12", group: "root" }

ansible_第15张图片

ansible_第16张图片


一直没有介绍vars自定义变量,这里我们来看一下。

ansible_第17张图片

ansible_第18张图片

这样想创建什么用户,就可以直接修改vars里面的变量就可以。


四、roles。

roles只是把任务给分离出去了。只要在playbook文件中调用此role就可执行这些任务。

如我们定义了一个很复杂的任务,但是要用在另外的主机组或只想用于单台主机的时候就要修改这个文件,总修改也不是办法。 可以复制多份,但有时候也不够灵活。

所以就可以用role把任务主体分离出来,只在playbook中写一些额外的东西,如变量,主机等等。


roles用于实现“代码复用”。

roles以特定的层次型格式组织起来playbook中的各主元素(vars, tasks, handlers)。每一个主元素都以一个目录来表示。


各目录如下:

files:此角色中用到的所有文件均放置于此目录中; 对应于copy模块。
templates:Jinja2模板文件存放位置;  对应于template模块。
tasks:任务列表文件;里面可以有多个文件,但至少有一个叫做main的文件;
handlers:处理器列表文件;里面可以有多个文件,但至少有一个叫做main的文件;
vars:变量字典文件;里面可以有多个文件,但至少有一个叫做main的文件;
meta:此角色的特殊设定及依赖关系;


在/etc/ansible/roles/目录下面的目录就是各个单独的rule。调用的时候直接调用目录名称。

[root@localhost createweb]# pwd
/etc/ansible/roles/createweb
[root@localhost createweb]# ls
files  handlers  meta  tasks  templates  vars
[root@localhost createweb]# tree -L 2
.
├── files                    #存放copy用到的文件。
│   ├── config
│   ├── httpd
│   ├── index.php
│   ├── iptables.bak.conf
│   └── rc.local
├── handlers             #定义handlers。
│   └── main
├── meta
├── tasks                    #定义任务。
│   └── main
├── templates           #存放template模块用到的文件。
│   └── httpd.conf
└── vars                     #定义变量。
    └── main


如我这里的tasks/main文件:

效果就是:安装httpd,创建所需要的网页目录,创建日志目录,复制所有配置文件,复制php测试页面。并启动httpd。

- name: install httpd
  yum: name=httpd state=present
- name: install php
  yum: name=php state=present
- name: install mod_ssl
  yum: name=mod_ssl state=present

#create http_page file
- name: create directory
  file: state=directory path={{ http_page_path_www }}
  file: state=directory path={{ http_page_path_myadm }}

#create log_file directory
- name: create log directory
  file: state=directory path={{ http_log_path_www }}
  file: state=directory path={{ http_log_path_myadm }}

- name: copy all web config
  copy: src=httpd dest=/etc/
  notify: restart httpd

- name: copy php_test file
  copy: src=index.php dest=/web/vhosts/www/
  copy: src=index.php dest=/web/vhosts/myadm/

- name: start httpd and enabled
  service: name=httpd state=started enabled=yes

handlers/main

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

vars/main  

http_port: 8000

http_log_path_www: /var/log/httpd/www
http_log_path_myadm: /var/log/httpd/myadm

http_page_path_www: /web/vhosts/www
http_page_path_myadm: /web/vhosts/myadm


定义playbook:

- hosts: wserver
  roles:
       - createweb


我这个的执行结果在远程主机上有点问题。不过大体上也就是这种结构,在playbook的roles里面还可以定义很参数,这里就先不介绍了,以后有时间再来改改。


谢谢浏览,如有错误还请指出。j_0022.gif