Ansible的Playbook与 Roles

一、 Playbook的介绍与运用

(一)、介绍

1、laybookad-hoc相比,是一种完全不同的运用ansible的方式,类似与saltstackstate状态文件。ad-hoc无法持久使用,playbook可以持久使用
2、playbook是由一个或多个play组成的列表,play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓的task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联合起来按事先编排的机制完成某一任务

(二)、Playbook的核心元素

Hosts 执行的远程主机列表
Tasks 任务集
Varniables 内置变量或自定义变量在playbook中调用
Templates(模板) 即使用模板语法的文件,比如配置文件等
Handlers 和notity结合使用 由特定条件触发的操作,满足条件方才执行,否则不执行
tags(标签) 指定某条任务执行,用于选择运行playbook中的部分代码

(三)、playbook的YAML基本规则

playbook使用yaml语法格式,后缀可以是yaml,也可以是yml
1、在单一一个playbook文件中,可以连续三个连子号(---)区分多个play。还有选择性的连续三个点好(...)用来表示play的结尾,也可省略
2、次行开始正常写playbook的内容,一般都会写上描述该playbook的功能
3、使用#号注释代码
4、缩进必须统一,不能空格和tab混用
5、缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行实现的
6、YAML文件内容和Linux系统大小写判断方式保持一致,是区分大小写的,k/v 的值均需大小写敏感
7、k/v的值可同行写也可以换行写。同行使用 : 分隔
8、v可以是个字符串,也可以是一个列表
9、一个完整的代码块功能需要最少元素包括 name: task

案例

[root@Ansible ~]# vim jb.yaml

---
- hosts: node
  remote_user: root

  tasks:
  - name: "测试"
    file: name=/home/aaa.txt state=touch

  - name: "创建用户"
    user: name=aaa system=yes shell=/sbin/nologin

  - name: "安装服务"
    yum: name=httpd

  - name: "复制html页面"
    copy: src=/var/www/html/index.html dest=/var/www/html/index.html

  - name: "启动服务"
    service: name=httpd state=started

保存
——————————————————————————————————————————————————————————
  ---------              说明  
---                                        #固定格式
- hosts: node1                             #定义需要执行主机
  remote_user: root                        #远程用户
  tasks:                                   #定义一个任务的开始
  - name: "测试"                           #定义任务的名称
    file: name=/home/aaa.txt state=touch   #调用模块,具体要做的事情

——————————————————————————————————————————————————————————
[root@Ansible ~]# mkdir -p /var/www/html/
[root@Ansible ~]# echo "

playbook 测试

" >>/var/www/html/index.html [root@Ansible ~]# ansible-playbook -C jb.yaml #使用-C进行测试 PLAY [node] ************************************************************************************************** TASK [Gathering Facts] *************************************************************************************** ok: [192.168.2.11] ok: [192.168.2.12] TASK [测试] **************************************************************************************************** changed: [192.168.2.11] changed: [192.168.2.12] TASK [创建用户] ************************************************************************************************** changed: [192.168.2.12] changed: [192.168.2.11] TASK [安装服务] ************************************************************************************************** changed: [192.168.2.11] changed: [192.168.2.12] TASK [复制html页面] ********************************************************************************************** changed: [192.168.2.11] changed: [192.168.2.12] TASK [启动服务] ************************************************************************************************** changed: [192.168.2.11] changed: [192.168.2.12] PLAY RECAP *************************************************************************************************** 192.168.2.11 : ok=6 changed=5 unreachable=0 failed=0 192.168.2.12 : ok=6 changed=5 unreachable=0 failed=0

正式执行命令


[root@Ansible ~]# ansible-playbook jb.yaml          

PLAY [node] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [测试] ****************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

TASK [创建用户] **************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

TASK [安装服务] **************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

TASK [复制html页面] **********************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

TASK [启动服务] **************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

PLAY RECAP ***************************************************************************************************
192.168.2.11               : ok=6    changed=5    unreachable=0    failed=0   
192.168.2.12               : ok=6    changed=5    unreachable=0    failed=0   

 验证访问

Ansible的Playbook与 Roles_第1张图片

 (四)、playbook的参数

格式
ansible-playbook  ... [options]            
参数 说明
--syntax-check 检测yaml文件的语法
-C(--check) 预测试,不会改变目标主机的任何设置
--limit 主机列表 只针对主机列表中的某个主机或者某个组执行
--list-hosts 列出yaml文件影响的主机列表
--list-tasks 列出playbook文件执行的所有任务
--list-tags 列出playbook文件中所有可用的标签(tags)
-t TAGS (--tags=TAGS) 表示只运行标记此标签的任务
--skip-tags=SKIP_TAGS 表示跳过运行标记此标签的任务,执行其他任务
--start-at-task=START_AT 从指定的任务开始往下运行
--flush-cache 清除fact缓存
--force-handlers 如果任务失败,也要运行handlers
--step 在运行之前确认每个任务
-e 传入变量
-f 指定并发数,默认为5个
-t 指定tags运行,运行某一个或者多个tags。(前提playbook中有定义tags)
-v 显示过程  -vv  -vvv更详细

(五)、Playbook中配置文件

1、 主机与用户

 在一个playbook的开头,最先定义的是要操作的主机和用户


---
- hosts: node
  remote_user: root     

在某一个tasks中定义要执行该任务的远程用户


tasks: 
  - name: run df -h
    remote_user: aaa
    shell: name=df -h   

也可以定义使用sudo授权用户执行该任务


tasks: 
  - name: run df -h
    sudo_user: aaa
    sudo: yes
    shell: name=df -h      

2、tasks任务列表

 每一个task必须有一个名称name,这样在运行playbook时,从其输出的任务执行信息中可以很清楚的辨别是属于哪一个task的,如果没有定义 nameaction的值将会用作输出信息中标记特定的task
每一个playbook中可以包含一个或者多个tasks任务列表,每一个tasks完成具体的一件事,(任务模块)比如创建一个用户或者安装一个软件等,在hosts中定义的主机或者主机组都将会执行这个被定义的tasks


tasks:
  - name:"创建文件" 
    file: path=/tmp/aaa.txt state=touch
  - name: "创建用户"
    user: name=aaa state=present        

3、Handlers(动作)与Notify(触发)

在很多时候当我们某一个配置发生改变,我们需要重启服务,(比如httpd配置文件文件发生改变了)这时候就可以用到handlersnotify了;
(当发生改动时)notify actions会在playbook的每一个task结束时被触发,而且即使有多个不同task通知改动的发生,notify actions知会被触发一次;比如多个resources指出因为一个配置文件被改动,所以apache需要重启,但是重新启动的操作知会被执行一次

  ————————————————————给2.10 服务器拷贝一份配置文件
[root@node1 ~]# cd /etc/httpd/conf/               
[root@node1 conf]# ls                 
httpd.conf  magic
[root@node1 conf]# scp httpd.conf [email protected]:/root/               
The authenticity of host '192.168.2.10 (192.168.2.10)' can't be established.
ECDSA key fingerprint is SHA256:W/vWUUz52EWoxAj6qq8J91ffWH4p8nCvmdGQCmUbRNo.
ECDSA key fingerprint is MD5:b2:4f:b6:ff:94:3a:1e:3d:2e:f8:f4:4e:f5:8c:ca:a9.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.10' (ECDSA) to the list of known hosts.
[email protected]'s password: 
httpd.conf                                                                  100%   11KB  15.1MB/s   00:00    

[root@Ansible ~]# ls ht*            
httpd.conf

编写jb.yaml文件


[root@Ansible ~]# vim jb.yaml               #修改之前的文件也可以在重新创建一个文件
---
- hosts: node
  remote_user: root
  vars:
    http_port: 88
  tasks:
  - name: "修改完成后的httpd配置文件"
    template: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
    notify:
      - restart httpd

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

保存
——————————————————————————————————————————————
说明:这里只要对httpd.conf配置文件作出了修改(修改了端口号),修改后需要重启生效
在tasks中定义了restart httpd这个action,然后在handlers中引用上面tasks中定义的notify

 修改ansible上的httpd.conf文件


[root@Ansible ~]# vim httpd.conf +42            
...
.......
Listen {{http_port}}        
...........
.......

先使用-C 进行测试


[root@Ansible ~]# ansible-playbook -C jb.yaml             

PLAY [node] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [修改完成后的httpd配置文件] ***************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

RUNNING HANDLER [restart httpd] ******************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

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

正式执行


[root@Ansible ~]# ansible-playbook jb.yaml        

PLAY [node] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [修改完成后的httpd配置文件] ***************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

RUNNING HANDLER [restart httpd] ******************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

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

访问测试

Ansible的Playbook与 Roles_第2张图片

(六)、Playbook中的变量

环境说明:这里设置了三个组,一个node1组和一个node2组,node为前两个组的集合


[root@Ansible ~]# vim /etc/ansible/hosts              
..............
......
[node1]
192.168.2.11
[node2]
192.168.2.12

[node:children]
node1
node2

1、命令行指定变量

执行playbook时候通过参数-e传入变量,这样传入的变量在整个playbook中都可以被调用,属于全局变量


[root@Ansible ~]# vim jb.yaml               
---
- hosts: node
  remote_user: root

  tasks:
    - name: "测试变量"
      yum: name={{ bl }}
           

保存

  ————————————————     执行playbook 指定bl的值

[root@Ansible ~]# ansible-playbook -e 'bl=psmisc' jb.yaml                

PLAY [node] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [测试变量] **************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

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

2、hosts文件中定义变量

/etc/ansible/hosts文件中定义变量,可以针对每个主机定义不同的变量,也可以定义一个组的变量,然后直接在playbook中直接调用。

注意:组中定义的变量没有单个主机中的优先级高


[root@Ansible ~]# vim /etc/ansible/hosts
............
....
[node1]
192.168.2.11 bl=/opt/bbb      #定义单个主机的变量

[node2]
192.168.2.12 bl=/opt/bbb      #定义单个主机的变量

[node:children]
node1
node2
[node:vars]                   #定义整个组的统一变量
bl=/opt/aaa

保存

[root@Ansible ~]# vim jb.yaml              
---
- hosts: node
  remote_user: root

  tasks:
    - name: "测试变量"
      file: name={{ bl }} state=directory             #使用变量 bl 是否存在文件bbb,不存在就创建bbb

测试

[root@Ansible ~]# ansible-playbook jb.yaml                         

PLAY [node] *************************************************************************************************************************************************************************

TASK [Gathering Facts] **************************************************************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [测试变量] *************************************************************************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

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

——————————————————————————————————————————————————————————————————————
[root@node1 opt]# ls
bbb

3、playbook文件中定义变量

编写playbook时,直接在里面定义变量,然后直接引用,可以定义多个变量

注意:如果在执行playbook时,又通过-e参数指定变量的值,那么会以-e参数指定的为准


[root@Ansible ~]# vim /etc/ansible/hosts                     
.......
[node1]
192.168.2.11

[node2]
192.168.2.12

[node:children]
node1
node2

保存
————————————————————————————————————————
[root@Ansible ~]# vim jb.yaml              
---
- hosts: node
  remote_user: root
  vars:            #定义变量
    bl: tree       #变量1
    zz: /opt/ccc   #变量2
  tasks:
    - name: "安装terr"
      yum: name={{ bl }} state=installed
    - name: "检查文件是否存在,不存在就创建"
      file: name={{ zz }} state=directory

保存

执行playbook剧本

[root@Ansible ~]# ansible-playbook jb.yaml 

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [安装terr] *********************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

TASK [检查文件是否存在,不存在就创建] ************************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

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

————————————————————————————————————————————————————————————————————

[root@node1 opt]# tree /opt                  
/opt
├── bbb
└── ccc

2 directories, 0 files

 注意:如果执行时候又重新指定了变量的值,那么会已重新指定的为准


[root@Ansible ~]# ansible-playbook -e "zz=/opt/ccc2" jb.yaml                  

4、调用setup模块获取变量

setup模块默认是获取主机信息的,有时候在playbook中需要用到,所以可以直接调用。常用的参数可以查看上一个文献 :https://blog.csdn.net/KW__jiaoq/article/details/122483776


[root@Ansible ~]# vim jb.yaml                   
---
- hosts: node
  remote_user: root
  tasks:
    - name: "setup模块"
      file: name={{ ansible_fqdn }}_log state=touch

保存

执行

[root@Ansible ~]# ansible-playbook jb.yaml            

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [setup模块] ********************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

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

——————————————————————
[root@node1 ~]# ls *_log
node1_log

4、独立的变量YAML文件中定义

为了方便管理将所有的变量统一放在一个独立的变量YAML文件中,Playbook文件直接引用文件调用变量即可


[root@Ansible ~]# vim bl.yaml        #变量文件
a1: vsftpd
a2: opthhh
保存

[root@Ansible ~]# vim jb.yaml             
---
- hosts: node
  remote_user: root
  vars_files:                        #引用变量文件
    - ./bl.yaml                        #指定变量文件的path(这里可以是绝对路径,也可以是相对路径)
  tasks:
    - name: "安装ftp"
      yum: name={{ a1 }}
    - name: "检查文件"
      file: name=/opt/{{ a2 }}_log state=touch
保存

执行


[root@Ansible ~]# ansible-playbook jb.yaml                           

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [安装ftp] **********************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

TASK [检查文件] ***********************************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

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

(七)、Playbook中标签的使用

 一个playbook文件中,执行时如果想执行某一个任务,那么可以给每个任务集进行打标签,这样在执行的时候可以通过-t选择指定标签执行,还可以通过--skip-tags选择除了某个标签外全部执行等


[root@Ansible ~]# vim jb.yaml                            
---
- hosts: node
  remote_user: root
  tasks:
    - name: "安装httpd"
      yum: name=httpd state=installed
      tags: AZ
    - name: "启动httpd"
      service: name=httpd state=started
      tags: start
    - name: "重启httpd"
      service: name=httpd state=restarted
      tags: restart

保存

正常执行剧本


[root@Ansible ~]# ansible-playbook jb.yaml            

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [安装httpd] ********************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [启动httpd] ********************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [重启httpd] ********************************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

PLAY RECAP ************************************************************************************************************************
192.168.2.11               : ok=4    changed=1    unreachable=0    failed=0   
192.168.2.12               : ok=4    changed=1    unreachable=0    failed=0   

使用 -t 选项指定执行


[root@Ansible ~]# ansible-playbook -t restart jb.yaml                      
 
PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [重启httpd] ********************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

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

通过--skip-tags选项排除不执行的tags


[root@Ansible ~]# ansible-playbook --skip-tags restart jb.yaml                    

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [安装httpd] ********************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [启动httpd] ********************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

PLAY RECAP ************************************************************************************************************************
192.168.2.11               : ok=3    changed=0    unreachable=0    failed=0   
192.168.2.12               : ok=3    changed=0    unreachable=0    failed=0   

(八)、Playbook中模板的使用

template模板为我们提供了动态配置服务,使用jinja2语言,里面支持多种条件判断、循环、逻辑运算、比较操作等。其实说白了也就是一个文件,和之前配置文件使用copy一样,只是使用copy,不能根据服务器配置不一样进行不同动态的配置。这样就不利于管理
说明:
1、多数情况下都将template文件放在和playbook文件同级的templates目录下(手动创建),这样playbook文件中可以直接引用,会自动去找这个文件。如果放在别的地方,也可以通过绝对路径去指定
2、模板文件后缀名为 .j2

1、template的when

条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句执行,在task中使用jinja2的语法格式、
when语句:在task后添加when子句即可使用条件测试;when语句支持jinja2表达式语法

案例

1、准备两个文件


[root@Ansible ~]# ls *.txt             
1.txt.j2  2.txt.j2

2、修改playbook文件,通过setup模块获取系统版本去判断


[root@Ansible ~]# vim jb.yaml                                
---
 - hosts: node
   remote_user: root

   tasks:
     - name: "判断"
       template: src=/root/1.txt.j2 dest=/root/
       when: ansible_distribution_major_version == "6"
     - name: "判断"
       template: src=/root/2.txt.j2 dest=/root/
       when: ansible_distribution_major_version == "7"

保存

执行剧本


[root@Ansible ~]# ansible-playbook jb.yaml                    

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [判断] *************************************************************************************************************************
skipping: [192.168.2.12]
skipping: [192.168.2.11]

TASK [判断] *************************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

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

————————————————————————————————————

[root@node1 ~]# ls [1-9]*       
2.txt.j2

[root@node2 ~]# ls [1-9]*         
2.txt.j2

 在例如:

---
- hosts: all
  remote_user: root
  vars:
    - listen_port: 88

  tasks:
    - name: "安装Httpd"
      yum: name=httpd state=installed
    - name: Config System6 Httpd
      template: src=httpd6.conf.j2 dest=/etc/httpd/conf/httpd.conf
      when: ansible_distribution_major_version == "6"   #判断系统版本,为6便执行上面的template配置6的配置文件
      notify: Restart Httpd
    - name: Config System7 Httpd
      template: src=httpd7.conf.j2 dest=/etc/httpd/conf/httpd.conf
      when: ansible_distribution_major_version == "7"   #判断系统版本,为7便执行上面的template配置7的配置文件
      notify: Restart Httpd
    - name: Start Httpd
      service: name=httpd state=started

  handlers:
    - name: Restart Httpd
      service: name=httpd state=restarted

2、template之with_items

with_items迭代,当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为item,要在task中使用with_items给定要迭代的元素列表

案例1

————————————————————通过with_items安装多个不同软件————————————
[root@Ansible ~]# vim jb.yaml            
---
- hosts: node
  remote_user: root

  tasks:
    - name: "批量安装"
      yum: name={{ item }} state=installed    #引用item获取值
      with_items:                             #定义with_items
        - httpd
        - vsftpd
        - psmisc

保存
————————————————————————————  上面tasks的写法等同于

---
- hosts: node
  remote_user: root

  tasks:
    - name: "安装"
      yum: name=httpd state=installed
    - name: "安装"
      yum: name=vsftpd state=installed
    - name: "安装"
      yum: name=psmisc state=installed

————————————————————————————————————————————————————
[root@Ansible ~]# ansible-playbook jb.yaml             #验证

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [批量安装] ***********************************************************************************************************************
ok: [192.168.2.11] => (item=[u'httpd', u'vsftpd', u'psmisc'])
ok: [192.168.2.12] => (item=[u'httpd', u'vsftpd', u'psmisc'])

PLAY RECAP ************************************************************************************************************************
192.168.2.11               : ok=2    changed=0    unreachable=0    failed=0   
192.168.2.12               : ok=2    changed=0    unreachable=0    failed=0   

案例2

————————————通过嵌套子变量创建用户并加入不同的组————————

[root@Ansible ~]# vim jb.yaml                                    
---
 - hosts: node
   remote_user: root

   tasks:
     - name: "创建用户组"
       group: name={{ item }} state=present
       with_items:
         - group1
         - group2
         - group3

     - name: "创建用户并加入组"
       user: name={{ item.name }} group={{ item.group }} state=present
       with_items:
         - { name: 'a3', group: 'group1' }
         - { name: 'a2', group: 'group2' }
         - { name: 'a1', group: 'group3' }

保存

[root@Ansible ~]# ansible-playbook jb.yaml                      

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [创建用户组] **********************************************************************************************************************
changed: [192.168.2.12] => (item=group1)
changed: [192.168.2.11] => (item=group1)
changed: [192.168.2.11] => (item=group2)
changed: [192.168.2.12] => (item=group2)
changed: [192.168.2.11] => (item=group3)
changed: [192.168.2.12] => (item=group3)

TASK [创建用户并加入组] *******************************************************************************************************************
changed: [192.168.2.12] => (item={u'group': u'group1', u'name': u'a3'})
changed: [192.168.2.11] => (item={u'group': u'group1', u'name': u'a3'})
changed: [192.168.2.11] => (item={u'group': u'group2', u'name': u'a2'})
changed: [192.168.2.12] => (item={u'group': u'group2', u'name': u'a2'})
changed: [192.168.2.11] => (item={u'group': u'group3', u'name': u'a1'})
changed: [192.168.2.12] => (item={u'group': u'group3', u'name': u'a1'})

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

————————————————————————————————————————————   验证

[root@Ansible ~]# ansible node -m shell -a 'tail -3 /etc/passwd'             
192.168.2.12 | SUCCESS | rc=0 >>
a3:x:1000:1000::/home/a3:/bin/bash
a2:x:1001:1001::/home/a2:/bin/bash
a1:x:1002:1002::/home/a1:/bin/bash

192.168.2.11 | SUCCESS | rc=0 >>
a3:x:1000:1000::/home/a3:/bin/bash
a2:x:1001:1001::/home/a2:/bin/bash
a1:x:1002:1002::/home/a1:/bin/bash

[root@Ansible ~]# ansible node -m shell -a 'tail -3 /etc/group'                
192.168.2.11 | SUCCESS | rc=0 >>
group1:x:1000:
group2:x:1001:
group3:x:1002:

192.168.2.12 | SUCCESS | rc=0 >>
group1:x:1000:
group2:x:1001:
group3:x:1002:

3、 template之for if

通过使用 forif 可以更加灵活的生成配置文件等需求,还可以在里面根据各种条件进行判断,然后生成不同的配置文件、或者服务器配置相关等

案例1:

1、编写剧本

[root@Ansible ~]# vim jb.yml                             
---
 - hosts: node
   remote_user: root
   vars:
     nginx_port:
       - 81
       - 82
       - 83

   tasks:
     - name: "测试"
       template: src=nginx.conf.j2 dest=/opt/nginx.conf
保存

————————————————————————————————————————————
2、模板文件编写

[root@Ansible ~]# vim nginx.conf.j2                #新建一个nginx.conf.j2文件                
{% for port in nginx_port %}
server{
     listen: {{ port }};                           #循环playbook文件中定义的变量,依次赋值给port
     server_name: localhost;
}
{% endfor %}

保存
————————————————————————————————————————————    执行
[root@Ansible ~]# ansible-playbook jb.yml                            

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [测试] *************************************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

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

——————————————————————查看生成结果
[root@node1 ~]# cat /opt/nginx.conf                         
server{
     listen: 81;
     server_name: localhost;
}
server{
     listen: 82;
     server_name: localhost;
}
server{
     listen: 83;
     server_name: localhost;
}

案例2

1、编写剧本
[root@Ansible ~]# vim jb.yml               
---
 - hosts: node
   remote_user: root
   vars:
     nginx_vhosts:
       - w1:
         listen: 8081
         server_name: "www.qq.com"
         root: "/var/www/nginx/w1"
       - w2:
         listen: 8082
         server_name: "www.qq2.com"
         root: "/var/www/nginx/w2"
       - w3:
         listen: 8083
         server_name: "www.qq3.com"
         root: "/var/www/nginx/w3"

   tasks:
     - name: "测试"
       template: src=nginx.conf.j2 dest=/opt/nginx.conf
保存
——————————————————————————————————————————————————————————
2、模板文件编写
[root@Ansible ~]# vim nginx.conf.j2                            
{% for pz in nginx_vhosts %}                  #pz循环的值(可自定义)
server{
     listen: {{ pz.listen }};
     server_name: {{ pz.server_name }};
     root: {{ pz.root }};
}
{% endfor %}

保存

[root@Ansible ~]# ansible-playbook jb.yml                  

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [测试] *************************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

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

——————————————————————————————————————————————————————
                            查看生成结果
[root@node1 ~]# cat /opt/nginx.conf
server{
     listen: 8081;
     server_name: www.qq.com;
     root: /var/www/nginx/w1;
}
server{
     listen: 8082;
     server_name: www.qq2.com;
     root: /var/www/nginx/w2;
}
server{
     listen: 8083;
     server_name: www.qq3.com;
     root: /var/www/nginx/w3;
}

案例3

for 循环中再嵌套 if 判断,让生成的配置文件更加灵活

1、修改剧本
[root@Ansible ~]# vim jb.yml                 
---
 - hosts: node
   remote_user: root
   vars:
     nginx_vhosts:
       - w1:
         server_name: "www.qq.com"
         root: "/var/www/nginx/w1"
       - w2:
         listen: 8082
         root: "/var/www/nginx/w2"
       - w3:
         listen: 8083
         server_name: "www.qq3.com"
         root: "/var/www/nginx/w3"

   tasks:
     - name: "测试"
       template: src=nginx.conf.j2 dest=/opt/nginx.conf

保存
——————————————————————————————————————————————————————————————
2、模板文件编写        
说明:这里添加了判断,如果listen没有定义的话,默认端口使用8888,如果server_name有定义,那么生成的配置文件中才有这一项

[root@Ansible ~]# vim nginx.conf.j2              
{% for pz in nginx_vhosts %}
server{
     {% if pz.listen is defined %}
     listen: {{ pz.listen }};
     {% else %}
     listen: 8080;
     {% endif %}
     {% if pz.server_name is defined %}
     server_name: {{ pz.server_name }};
     {% endif %}
     root: {{ pz.root }};
}
{% endfor %}

保存
——————————————————————————————————————————————————————
 
[root@Ansible ~]# ansible-playbook jb.yml                     

PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [测试] *************************************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

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

————————————————————————————————————————————————————————————————————————————————————
                   查看生成结果

[root@node1 ~]# cat /opt/nginx.conf
server{
          listen: 8080;
               server_name: www.qq.com;
          root: /var/www/nginx/w1;
}
server{
          listen: 8082;
               root: /var/www/nginx/w2;
}
server{
          listen: 8083;
               server_name: www.qq3.com;
          root: /var/www/nginx/w3;
}



二、 Roles的介绍及应用

(一)、Roles简介

ansible1.2版本引入的新特性,用于层次性、结构化地组织playbookroles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令引入即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷的include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。主要使用场景代码复用度较高的情况下

(二)、Roles目录结构

Ansible的Playbook与 Roles_第3张图片

目录说明
roles 所有的角色必须放在roles目录下,这个目录可以自定义位置,默认的位置在/etc/ansible/roles
project 具体的角色项目名称,比如nginxtomcatphp
files 用来存放由copy模块或script模块调用的文件
templates 用来存放jinjia2模板,template模块会自动在此目录中寻找jinjia2模板文件

tasks

main.yml 此目录应当包含一个main.yml文件,用于定义此角色的任务列表,此文件可以使用include包含其它的位于此目录的task文件
handlers main.yml 此目录应当包含一个main.yml文件,用于定义此角色中触发条件时执行的动作
vars main.yml 此目录应当包含一个main.yml文件,用于定义此角色用到的变量
defaults main.yml 此目录应当包含一个main.yml文件,用于为当前角色设定默认变量
meta main.yml 此目录应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系

(三)、Roles案例

通过ansible roles安装配置httpd服务,此处的roles使用默认的路径/etc/ansible/roles

1、创建目录


[root@Ansible ~]# cd /etc/ansible/roles/               
[root@Ansible roles]# mkdir -p httpd/{handlers,tasks,templates,vars}                  
[root@Ansible roles]# tree .             
.
└── httpd
    ├── handlers
    ├── tasks
    ├── templates
    └── vars

5 directories, 0 files  

2、变量文件准备vars/main.yml


[root@Ansible roles]# vim httpd/vars/main.yml            
port: 8080
user: aaa
group: aaa

保存

3、配置文件模板准备templates/httpd.conf.j2


[root@Ansible roles]# cp /root/httpd.conf ../roles/httpd/templates/httpd.conf.j2                                                                    

 ——————————         #调用上面定义的变量
[root@Ansible roles]# vim httpd/templates/httpd.conf.j2             
......
 42 Listen {{ port }}
.....
..
 66 User {{ user }}
 67 Group {{ group }}
......
...

保存

4、任务剧本编写,创建用户、创建组、安装软件、配置、启动等


[root@Ansible roles]# cat httpd/tasks/{group.yml,user.yml,install.yml,config.yml,start.yml,main.yml}             
——————————————————————————————————————————————————————     group.yml

 - name: "创建用户组"
   group: name=aaa gid=60 system=yes

——————————————————————————————————————————————————————     user.yml

 - nsme: "创建用户"
   user: name=aaa uid=60 system=yes shell=/sbin/nologin

——————————————————————————————————————————————————————     install.yml

 - name: "安装httpd"
   yum: name=httpd state=installed

——————————————————————————————————————————————————————     config.yml

 - name: "传输修改完的配置"
   template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
   notify: restart httpd

——————————————————————————————————————————————————————     start.yml

 - name: "启动http"
   service: name=httpd state=started enabled=yes

——————————————————————————————————————————————————————     main.yml

 - include: group.yml
 - include: user.yml
 - include: install.yml
 - include: config.yml
 - include: start.yml

5、编写重启httpd的handlershandlers/main.yml


[root@Ansible roles]# vim httpd/handlers/main.yml                          
 - name: restart httpd
   service: name=httpd state=restarted

保存

6、编写主的httpd_roles.yml文件调用httpd角色


[root@Ansible roles]# vim httpd_roles.yml            
---
 - hosts: node
   remote_user: root
   roles:
     - role: httpd

保存     

7、整体的一个目录结构查看


[root@Ansible roles]# tree .                           
.
├── httpd
│   ├── handlers
│   │   └── main.yml
│   ├── tasks
│   │   ├── config.yml
│   │   ├── group.yml
│   │   ├── install.yml
│   │   ├── main.yml
│   │   ├── start.yml
│   │   └── user.yml
│   ├── templates
│   │   └── httpd.conf.j2
│   └── vars
│       └── main.yml
└── httpd_roles.yml

5 directories, 10 files       

8、测试playbook语法是否正确


[root@Ansible roles]# ansible-playbook -C httpd_roles.yml                          
 [WARNING]: Ignoring invalid attribute: nsme

 [WARNING]: Found variable using reserved name: port


PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [httpd : 创建用户组] **************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

TASK [httpd : user] ***************************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

TASK [httpd : 安装httpd] ************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [httpd : 传输修改完的配置] ***********************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

TASK [httpd : 启动http] *************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

RUNNING HANDLER [httpd : restart httpd] *******************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

PLAY RECAP ************************************************************************************************************************
192.168.2.11               : ok=7    changed=5    unreachable=0    failed=0   
192.168.2.12               : ok=7    changed=5    unreachable=0    failed=0   

9、测试没有问题,正式执行playbook


[root@Ansible roles]# ansible-playbook httpd_roles.yml                          
 [WARNING]: Ignoring invalid attribute: nsme

 [WARNING]: Found variable using reserved name: port


PLAY [node] ***********************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [192.168.2.11]
ok: [192.168.2.12]

TASK [httpd : 创建用户组] **************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

TASK [httpd : user] ***************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

TASK [httpd : 安装httpd] ************************************************************************************************************
ok: [192.168.2.12]
ok: [192.168.2.11]

TASK [httpd : 传输修改完的配置] ***********************************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

TASK [httpd : 启动http] *************************************************************************************************************
changed: [192.168.2.12]
changed: [192.168.2.11]

RUNNING HANDLER [httpd : restart httpd] *******************************************************************************************
changed: [192.168.2.11]
changed: [192.168.2.12]

PLAY RECAP ************************************************************************************************************************
192.168.2.11               : ok=7    changed=5    unreachable=0    failed=0   
192.168.2.12               : ok=7    changed=5    unreachable=0    failed=0   

(四)、总结

1、编写任务(task)的时候,里面不需要写需要执行的主机,单纯的写某个任务是干什么的即可,装软件的就是装软件的,启动的就是启动的。单独做某一件事即可,最后通过 main.yml 将这些单独的任务安装执行顺序 include 进来即可,这样方便维护且一目了然

2、定义变量时候直接安装 k:v 格式将变量写在 vars/main.yml 文件即可,然后 task 或者 template 直接调用即可,会自动去 vars/main.yml 文件里面去找

3、定义 handlers 时候,直接在 handlers/main.yml 文件中写需要做什么事情即可,多可的话可以全部写在该文件里面,也可以像 task 那样分开来写,通过 include 引入一样的可以。在 task 调用 notify 时直接写与 handlers 名字对应即可(二者必须高度一直)

4、模板文件一样放在 templates 目录下即可, task 调用的时后直接写文件名字即可,会自动去到 templates 里面找。注意:如果是一个角色调用另外一个角色的单个 task 时后,那么 task 中如果有些模板或者文件,就得写绝对路径了

你可能感兴趣的:(Ansible的Roles,Ansible剧本,Playbook,Playbook与Roles)