1、laybook与ad-hoc相比,是一种完全不同的运用ansible的方式,类似与saltstack的state状态文件。ad-hoc无法持久使用,playbook可以持久使用
2、playbook是由一个或多个play组成的列表,play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓的task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联合起来按事先编排的机制完成某一任务
Hosts | 执行的远程主机列表 |
Tasks | 任务集 |
Varniables | 内置变量或自定义变量在playbook中调用 |
Templates(模板) | 即使用模板语法的文件,比如配置文件等 |
Handlers 和notity结合使用 | 由特定条件触发的操作,满足条件方才执行,否则不执行 |
tags(标签) | 指定某条任务执行,用于选择运行playbook中的部分代码 |
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 ... [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的开头,最先定义的是要操作的主机和用户
---
- 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
每一个task必须有一个名称name,这样在运行playbook时,从其输出的任务执行信息中可以很清楚的辨别是属于哪一个task的,如果没有定义 name,action的值将会用作输出信息中标记特定的task
每一个playbook中可以包含一个或者多个tasks任务列表,每一个tasks完成具体的一件事,(任务模块)比如创建一个用户或者安装一个软件等,在hosts中定义的主机或者主机组都将会执行这个被定义的tasks
tasks:
- name:"创建文件"
file: path=/tmp/aaa.txt state=touch
- name: "创建用户"
user: name=aaa state=present
在很多时候当我们某一个配置发生改变,我们需要重启服务,(比如httpd配置文件文件发生改变了)这时候就可以用到handlers和notify了;
(当发生改动时)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
访问测试
环境说明:这里设置了三个组,一个node1组和一个node2组,node为前两个组的集合
[root@Ansible ~]# vim /etc/ansible/hosts
..............
......
[node1]
192.168.2.11
[node2]
192.168.2.12
[node:children]
node1
node2
执行
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
在/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
编写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
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
为了方便管理将所有的变量统一放在一个独立的变量
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文件中,执行时如果想执行某一个任务,那么可以给每个任务集进行打标签,这样在执行的时候可以通过-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
template模板为我们提供了动态配置服务,使用jinja2语言,里面支持多种条件判断、循环、逻辑运算、比较操作等。其实说白了也就是一个文件,和之前配置文件使用copy一样,只是使用copy,不能根据服务器配置不一样进行不同动态的配置。这样就不利于管理
说明:
1、多数情况下都将template文件放在和playbook文件同级的templates目录下(手动创建),这样playbook文件中可以直接引用,会自动去找这个文件。如果放在别的地方,也可以通过绝对路径去指定
2、模板文件后缀名为 .j2
条件测试:如果需要根据变量、
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
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:
通过使用
for
,if
可以更加灵活的生成配置文件等需求,还可以在里面根据各种条件进行判断,然后生成不同的配置文件、或者服务器配置相关等
案例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;
}
ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令引入即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷的include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。主要使用场景代码复用度较高的情况下
目录说明 | ||
---|---|---|
roles | 所有的角色必须放在roles目录下,这个目录可以自定义位置,默认的位置在/etc/ansible/roles | |
project | 具体的角色项目名称,比如nginx、tomcat、php | |
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文件,用于定义此角色的特殊设定及其依赖关系 |
通过
ansible roles
安装配置httpd
服务,此处的roles
使用默认的路径/etc/ansible/roles
[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
vars/main.yml
[root@Ansible roles]# vim httpd/vars/main.yml
port: 8080
user: aaa
group: aaa
保存
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 }}
......
...
保存
[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
handlers
,handlers/main.yml
[root@Ansible roles]# vim httpd/handlers/main.yml
- name: restart httpd
service: name=httpd state=restarted
保存
httpd_roles.yml
文件调用httpd角色
[root@Ansible roles]# vim httpd_roles.yml
---
- hosts: node
remote_user: root
roles:
- role: httpd
保存
[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
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
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 中如果有些模板或者文件,就得写绝对路径了