备注:文章事例部分代码会出现不对齐的情况,使用时,请注意格式对齐!!
第4 章 playbook和roles
4.1 ansible-playbook常用命令说明
ansible-playbook --help
Usage: ansible-playbook playbook.yml
Options:
-e EXTRA_VARS,--extra-vars=EXTRA_VARS # 设置额外的变量,格式为key/value。-e "key=KEY",
# 如果是文件方式传入变量,则-e "@param_file"
--flush-cache # 清空收集到的fact信息缓存
--force-handlers # 即使task执行失败,也强制执行handlers
--list-tags # 列出所有可获取到的tags
--list-tasks # 列出所有将要被执行的tasks
-t TAGS,--tags=TAGS # 以tag的方式显式匹配要执行哪些tag中的任务
--skip-tags=SKIP_TAGS # 以tag的方式忽略某些要执行的任务。被此处匹配的tag中的任务都不会执行
--start-at-task=START_AT_TASK # 从此task开始执行playbook
--step # one-step-at-a-time:在每一个任务执行前都进行交互式确认
--syntax-check # 检查playbook语法
4.2 playbook的内容
4.2.1 hosts和remoter_user
对于playbook中的每一个play,使用hosts选项可以定义要执行这些任务的主机或主机组,还可以使用remote_user指定在远程主机上执行任务的用户,实际上remote_user是ssh连接到被控主机上的用户,自然而然执行命令的身份也将是此用户。
--- #标识
- hosts: control-node #将要执行任务的主机,已经在hosts文件中定义好了,可是单个主机或主机组
remote_user: root #在目标主机上执行任务时的用户身份
vars:
- pkg: httpd
tasks:
- name: "install httpd package."
yum: name={{ pkg }} state=installed
4.2.2 notify和handler
ansible每个任务的changed=true或changed=false。ansible在捕捉到changed=true时,可以触发notify组件(如果定义了该组件),而notify是一个组件,并非一个模块,它可以直接定义action,其主要目的是调用handler。在需要被监控的任务(tasks)中定义一个notify,只有当这个任务被执行时,才会触发notify对应的handlers去执行相应操作。特别需要注意:handlers下的name名称必须要和它对应的notify名称相同!否则不会执行!!
举例如下:
--- #标识
- hosts: control-node
remote_user: root
vars:
- pkg: httpd
tasks:
- name: "install httpd package."
yum: name={{ pkg }} state=installed
- name: "copy httpd configure file to remote host."
copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: restart httpd
- name: "boot httpd service."
service: name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted
在使用handlers的过程中,需要注意下面几点
1、handlers只有在其所在的任务被执行完时,它才会被运行;如果一个任务中定义了notify调用Handlers,但由于条件判断等原因,该任务未被执行,则Handlers同样不会被执行。
2、 handlers只会在Play的末尾运行一次;如果想在一个Playbook的中间运行handlers,则需要使用meta模块来实现,例如:-meta: flush_handlers。
3、 可以直接在Handlers中使用notify选项,实现Handlers调用Handlers。
4、可以使用listen关键字,在一个tasks任务中一次性notify多个handler。即将多个handler分为"一组",使用相同的"组名"即可,当notify对应的值为"组名"时,"组"内的所有handler都会被notify。
5、如果一个Play在运行到调用handlers的语句之前失败了,那么这个handlers将不会被执行。但是可以使用mega模块的--force-handlers选项来强制执行handlers,即使在handlers所在Play中途运行失败也能执行。需要注意:--force-handlers参数主要针对即使playbook执行失败,也要执行代码块成功了的handlers(即执行成功的task任务), 如果代码块本身执行失败(即执行失败的task任务),那么它所对应的handlers应当不会被执行!
场景1:headlers在所有tasks任务被执行完时才执行:
--- #标识
- hosts: test_host
remote_user: root
become: yes
become_method: sudo
tasks:
- name: make file task1
file: path=/opt/task1.txt state=touch
notify: task1
- name: make file task2
file: path=/opt/task2.txt state=touch
notify: task2
handlers:
- name: task1
file: path=/opt/task1.txt mode=777 owner=root group=root
- name: task2
file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes
场景2:使用meta模块,headlers会在它所对应的task任务执行完后立即被触发并执行,即在playbook的中间环节运行:
--- #标识
- hosts: test_host
remote_user: root
become: yes
become_method: sudo
tasks:
- name: make file task1
file: path=/opt/task1.txt state=touch
notify: task1
- meta: flush_handlers
- name: make file task2
file: path=/opt/task2.txt state=touch
notify: task2
handlers:
- name: task1
file: path=/opt/task1.txt mode=777 owner=root group=root
- name: task2
file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes
场景3:Handlers调用Handlers:
--- #标识
- hosts: test_host
remote_user: root
become: yes
become_method: sudo
tasks:
- name: make file task1
file: path=/opt/task1.txt state=touch
notify: task1
- name: make file task2
file: path=/opt/task2.txt state=touch
handlers:
- name: task1
file: path=/opt/task1.txt mode=777 owner=root group=root
notify: task2
- name: task2
file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes
注意:上面执行的顺序是:make file task1 > make file task2 > task1 > task2
也可以改成下面的方式:实现Handlers调用Handlers:
--- #标识
- hosts: test_host
remote_user: root
become: yes
become_method: sudo
tasks:
- name: make file task1
file: path=/opt/task1.txt state=touch
notify: task1
handlers:
- name: task1
file: path=/opt/task1.txt mode=777 owner=root group=root
notify: task2
- name: task2
file: path=/opt/task2.txt state=touch
notify: task3
- name: task3
file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes
注意:上面的执行顺序是:make file task1 > task1 > task2 > task3
场景4:使用listen关键字(需要注意:listen的名称要和notify名称保持一致),在一个tasks任务中一次性notify多个handler:
--- #标识
- hosts: test_host
remote_user: root
become: yes
become_method: sudo
tasks:
- name: make file task1
file: path=/opt/task1.txt state=touch
notify: group1_handler
handlers:
- name: task1
listen: group1_handler
file: path=/opt/task1.txt mode=777 owner=root group=root
- name: task2
listen: group1_handler
file: path=/opt/task1.txt src=/opt/task1.txt dest=/opt/heihei state=link force=yes
- name: task3
listen: group1_handler
shell: echo "this is test,haha...." >> /opt/task1.txt
场景5:使用--force-handlers选项来强制执行handlers(ansible-playbook XXX.yaml --force-handlers):
必须要注意的是:--force-handlers参数主要针对即使playbook执行失败,也要执行代码块成功了的handlers(即执行成功的task任务), 如果代码块本身执行失败(即执行失败的task任务),那么它所对应的handlers应当不会被执行!
--- #标识
- hosts: test_host
remote_user: root
become: yes
become_method: sudo
tasks:
- name: make file task1
file: path=/opt/task1.txt state=touch
notify: task1
- name: make file task2
file: path=/opt/kevin/task2.txt state=touch
notify: task2
handlers:
- name: task1
file: path=/opt/task1.txt mode=777 owner=root group=root
- name: task2
shell: ln -s /opt/task1.txt /opt/task2.txt
4.2.3 tags任务标签
tags可以看作是ansible的任务控制,ansible的标签(Tags)功能可以给角色(Roles)、文件、单独的任务,甚至整个Playbook打上标签,然后利用这些标签来指定要运行Playbook中的个别任务,或不执行指定的任务。如果有一个很大的playbook剧本,而只想运行playbook其中的某个或部分task任务,而不是运行playbook中所有的任务,这个时候tags是最佳选择。
一、可以通过两种方式根据"tags"过滤任务:
1、 在命令行上,使用或选项"--tags或 --skip-tags",后面使用空格或"="都可以。
2、在ansible配置设置中,使用和选项"TAGS_RUN或TAGS_SKIP";
3、可以使用"--list-tags"查看playbook中有哪些tags会被执行;
二、系统内置的tags有以下几个:
always: 除非--skip-tags指定这个标签,否则该标记为always的task一直都会执行。"--tags always"只执行标记了always的tasks;
never: 除非--tags指定了这个标签,否则该标记为never的task一直都不会执行。"--tags never"执行标记了always和never的tasks;
tagged: --tags tagged表示执行所有有tags标签的tasks任务,但不包括tags标签是never的tasks任务;--skip-tags tagged表示所有有tags标签的tasks任务都跳过,即不会执行。
untagged: --tags untagged表示执行所有没有tags标签的tasks任务和tags标签为always的tasks任务;--skip-tags untagged效果相反!
all:--tags all表示执行所有的tags标签为非never的task,包括有tags标签和无tags标签的tasks。
三、 tags标签配置语法有下面三种:
语法一:
tags:
- tag_test
语法二:
tags: tag_test
语法三:
tags: ['tag_test']
官方示例如下:
[root@localhost ansible]# vim example.yml
--- #标识
- hosts: all
remote_user: root
gather_facts: no
tasks:
- yum: name={{ item }} state=installed
with_items:
- httpd
- memcached
tags:
- packages
- template: src=templates/src.j2 dest=/etc/foo.conf
tags:
- configuration
此时如果希望只run其中的某个task,则run的时候指定tags即可。可以运行多个tags,中间使用逗号隔开;也可以运行单个tags。
[root@localhost ansible]# ansible-playbook example.yml --tags "configuration,packages"
[root@localhost ansible]# ansible-playbook example.yml --tags configuration
[root@localhost ansible]# ansible-playbook example.yml --tags packages
或者
[root@localhost ansible]# ansible-playbook example.yml --tags="configuration,packages"
[root@localhost ansible]# ansible-playbook example.yml --tags=configuration
[root@localhost ansible]# ansible-playbook example.yml --tags=packages
相反,也可以使用--skip-tags跳过某个task任务。
[root@localhost ansible]# ansible-playbook example.yml --skip-tags configuration
或者
[root@localhost ansible]# ansible-playbook example.yml --skip-tags=configuration
四、内置的特殊tags的用法
[root@localhost ansible]# cat haha.yaml
--- #标识
- hosts: test_host
remote_user: root
gather_facts: no
tasks:
- name: task1
file: path=/opt/task1.txt state=touch
tags: make_task1
- name: task2
file: path=/opt/task2.txt state=touch
tags:
- always
- name: task3
file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes
tags: ['link_task3']
执行1:如下,虽然tags指定了执行标签为make_task1的任务,但是由于任务2的标签有关键字always,所以任务2也会被执行,这就是always的作用![root@localhost ansible]# ansible-playbook haha.yaml --tags=make_task1
五、tags标签可以和role 结合使用
[root@localhost ansible]# cat test.yml
--- #标识
roles:
- { role: webserver, port: 5000, tags: [ 'web', 'foo' ] }
六、tags和include结合使用
[root@localhost ansible]# cat test.yml
--- #标识
- include: kevin.yml tags=web,foo
查看一下具体实例:再来看看一个include结合tags的示例:通过指定标签(tags),来说明是安装tomcat7还是tomcat8
[root@localhost ansible]# cat tomcat.yml
--- #标识
- include: install_tomcat7.yml
tags: tomcat7
- include: install_tomcat8.yml
tags: tomcat8
[root@localhost ansible]# cat install_tomcat7.yml
--- #标识
- name: "复制文件到远程主机"
copy:
src={{ item.src }}
dest={{ item.dest }}
with_items:
- src: jdk-7u79-linux-x64.rpm
dest: /usr/local/src/
- src: java17.sh
dest: /etc/profile.d/
- name: "安装jdk"
yum:
name: /usr/local/src/jdk-7u79-linux-x64.rpm
state: present
- name: "重新加载环境变量"
shell: "source /etc/profile.d/java17.sh"
- name: "复制tomcat文件到远程服务器并解压"
unarchive:
src=apache-tomcat-7.0.64.zip
dest=/data/
copy=yes
owner=staplesapp
group=admin
- name: "对解压后的文件重命名"
shell: mv /data/apache-tomcat-7.0.64 /data/tomcat7
- name: "对tomcat进行相关配置"
shell: find /data/tomcat7/bin -name "*.sh" | xargs chmod +x
- name: "启动tomcat"
shell: 'nohup /data/tomcat7/bin/startup.sh &'
[root@localhost ansible]# cat install_tomcat8.yml
--- #标识
- name: "复制文件到远程主机"
copy:
src={{ item.src }}
dest={{ item.dest }}
with_items:
- src: jdk-8u111-linux-x64.rpm
dest: /usr/local/src/
- src: java18.sh
dest: /etc/profile.d/
- name: "安装jdk"
yum:
name: /usr/local/src/jdk-8u111-linux-x64.rpm
state: present
- name: "配置java环境变量"
shell: "source /etc/profile.d/java18.sh"
- name: "安装tomcat"
unarchive:
src=apache-tomcat-8.0.30.tar.gz
dest=/data/
copy=yes
owner=staplesapp
group=admin
- name: "对解压后的文件重命名"
shell: mv /data/apache-tomcat-8.0.30 /data/tomcat8
- name: "启动tomcat"
shell: 'nohup /data/tomcat8/bin/startup.sh &'
下面开始执行命令:
安装tomcat7:
[root@localhost ansible]# ansible-playbook tomcat.yml --tags tomcat7
安装tomcat8:
[root@localhost ansible]# ansible-playbook tomcat.yml --tags tomcat8
特别注意:
在ansible2.8版本之后将会删除include语法,更改为import_playbook。如果还使用include语法也可以,只不过ansible-playbook执行结果中会有告警信息:"DEPRECATION WARNING]:'include' for playbook includes. You should use 'import_playbook' instead. This feature will be removed in version 2.8. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg."。所以,最好将上面tomcat.yml文件中的include语法改成import_playbook,如下:
[root@localhost ansible]# cat tomcat.yml
--- #标识
- import_playbook: install_tomcat7.yml
tags: tomcat7
- import_playbook: install_tomcat8.yml
tags: tomcat8
4.2.4 include用法
如果想在playbook中重复使用任务列表,则可以使用include文件来执行此操作。 使用include的任务列表是定义系统将要实现的角色的好方法。注意事项:ansible2.8版本之后include语法变成了import_playbook。如果还是使用include,虽然不会影响执行结果,只不过在执行过程会有告警信息。
示例1:通过Include,可以在playbook中引用另一个playbook或者tasks
[root@localhost ansible]# cat install_MysqlAndPhp.yml
--- #标识
- yum:
name: mysql
state: present
- yum:
name: php-fpm
state: present
[root@localhost ansible]# cat lamp.yml
--- #标识
- hosts: test_host
remote_user: root
gather_facts: no
tasks:
- include: install_MysqlAndPhp.yml
- yum:
name: httpd
state: present
[root@localhost ansible]# cat lnmp.yml
--- #标识
- hosts: test_host
remote_user: root
gather_facts: no
tasks:
- include: install_MysqlAndPhp.yml
- yum:
name: nginx
state: present
示例2: 可以在handler中引用include
[root@localhost ansible]# cat test_include.yml
--- #标识
- hosts: test_host
remote_user: root
gather_facts: no
tasks:
- file:
path: /opt/ttt
state: touch
notify: test include handlers
handlers:
- name: test include handlers
include: include_handler.yml
[root@localhost ansible]# cat include_handler.yml
--- #标识
- - debug:
msg: "task1 of handlers"
- debug:
msg: "task2 of handlers"
- debug:
msg: "task3 of handlers"
示例3: when在include中使用
[root@localhost ansible]# cat /etc/ansible/hosts
[db]
192.168.24.10
[app]
192.168.24.11
[root@localhost ansible]# cat install_client.yml
--- #标识
- hosts: '` hosts `'
user: ansible
sudo: yes
sudo_user:root
roles:
- install_client
[root@localhost ansible]# cat roles/install_client/tasks/main.yml
--- #标识
- include: db.yml
when: "hosts == 'db'"
- include: app.yml
when: "hosts == 'app'"
[root@localhost ansible]# cat roles/install_client/tasks/db.yml
--- #标识
- name: Touchdb file
shell: touch /tmp/db.txt
[root@localhost ansible]# cat roles/install_client/tasks/app.yml
--- #标识
- name: Touchdb file
shell: touch /tmp/db.txt
执行命令:
[root@localhost ansible]# ansible-playbook -i hosts install_client.yml --extra-vars "hosts=db"
[root@localhost ansible]# ansible-playbook -i hosts install_client.yml --extra-vars "hosts=app"
4.2.5 role用法
角色(roles)是用于层次性,结构化地组织playbook,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中、并可以便捷地include他们的一种机制。
一、role的层级目录结构
role是以特定的层级目录结构进行组织的tasks、variables、handlers、templates、files等;
roles/
role_name/:定义的role的名字
file/: 用于存放copy或script等模块调用的函数
tasks/: 用于定义各种task,此目录一定要有main.yml;其他文件需要main.yml包含调用
handlers/: 用于定义各种handlers,此目录一定要有main.yml;其他文件需要main.yml包含调用
vars/: 用于定义variables,此目录一定要有main.yml;其他文件需要main.yml包含调用
templates/:存储由template模块调用的模板文本;
meta/: 定义当前角色的特殊设定及其依赖关系,此目录中至少应该有一个名为main.yml的文件;其它的文件需要由main.yml进行"包含"调用;
default/: 此目录中至少应该有一个名为main.yml的文件,用于设定默认变量;
以一个项目的role目录结构举例:
site.yml
webservers.yml
mariadb.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
mariadb/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
目录解释:
yml文件:用于定义此角色用到的各handler:在handler中使用include包含的其他的handler文件也应该位于此目录中;
files目录:存放由copy或script等模块调用的文件;
templates目录:templates模块会自动在此目录中寻找Jinja2模板文件;
tasks目录:至少应该包含一个名为main.yml的文件,其定义了此角色的任务列表;此文件可以使用include包含其他的位于此目录中的task文件;
handlers目录:此目录中应当包含一个main;
vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量;
meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;ansible 1.3及其以后的版本才支持
default目录:为当前角色设定默认变量时使用此目录;应当包含一个main.yml文件;
二、 在playbook中调用role
在playbook中调用role的方式有三种,如下:
第一种:
- hosts: HOSTS
remote_user: root
roles:
- ROLE_NAME1
- ROLE_NAME2
第二种:除了字典第一个元素指明调用的role,后面是传递给role的变量
- hosts: HOSTS
remote_user: root
roles:
- { role: ROLE_NAME1, VARIABLE1: VALUE1, ... }
第三种:when指明role调用的条件
- hosts: HOSTS
remote_user: root
roles:
- { role: ROLE_NAME1, when: CONDITIONS }
三、举例使用ansible-playbook实现如下功能配置:
1、group: 创建用户组nginx
2、user: 创建用户nginx
3、yum: 安装nginx
4、template: 配置文件更新nginx.conf
5、service: 启动nginx
[root@localhost ~]# cat /etc/ansible/ansible.cfg|grep roles_path
roles_path = /etc/ansible/roles:/root/ansible/roles
[root@localhost ~]# mkdir ansible/roles/nginx -p
[root@localhost ~]# cd ansible/roles/nginx
[root@localhost nginx]# mkdir {tasks,templates}
[root@localhost nginx]# cd tasks
[root@localhost tasks]# vim group.yml
- name: create group nginx
group: name=nginx gid=80
[root@localhost tasks]# vim user.yml
-name: create user nginx
user: name=nginx uid=80 group=nginx system=yes shell=/sbin/nologin
[root@localhost tasks]# vim install.yml
- name: install package
yum: name=nginx
[root@localhost tasks]# vim start.yml
- name: start service
service: name=nginx state=started enabled=yes
[root@localhost tasks]# vim restart.yml
- name: restart service
service: name=nginx state=restarted
[root@localhost tasks]# vim templ.yml
- name: copy conf
template: src=nginx.conf.j2 dest=/etc/nginx/conf/nginx.conf
[root@localhost tasks]# vim main.yml
- include: group.yml
- include: user.yml
- include: install.yml
- include: templ.yml
- include: start.yml
[root@localhost tasks]# cd ../templates && ls
nginx.conf.j2
[root@localhost tasks]# cd /root/ansible
[root@localhost ansible]# vim nginx_role.yml
- hosts: websrvs
remote_user: root
roles:
- role: nginx
执行命令:
[root@localhost ansible]# ansible-playbook nginx_role.yml
4.2.6 playbook中的变量设置
变量的优先级
1、 extra vars变量(在命令行中使用 -e);优先级最高
2、playbook中的变量;优先级第二
3、 在inventory中定义的连接变量(比如ansible_ssh_user);优先级第三
4、 大多数的其他变量(命令行转换,play中的变量,include的变量,role的变量等);优先级第四
5、 在inventory定义的其他变量;优先级第五
6、有系统发现的facts;优先级第六
7、 "role默认变量",这个是最默认的值,很容易丧失优先权。优先级最小。
另外:在inventory清单列表里定义的变量:单个主机定义的变量优先级高于主机组定义的变量。ansible使用inventory定义变量的优先级顺序从高到低为:
1、 host_vars下定义变量
2、 inventory中单个主机定义变量
3、 group_vars下定义变量
4、 inventory中组定义变量
YAML陷阱
YAML语法要求如果值以{{ foo }}开头的话,那么就需要将整行用双引号包起来,这是为了确认你不是想声明一个YAML字典。
- hosts: app_servers
vars:
app_path: "{{ base_path }}/data/web"
一、在playbook剧本中定义变量
在playbook中定义变量需要用到Ansible的vars模块,可以将所有需要用到的变量统一在vars模块下定义,定义格式需要遵循YAML语言格式:
vars:
- var1: value1
- var2: value2
- var3: value3
- ....: .....
示例如下:
[root@ss-server ansible]# cat playbook.yml
--- #标识
- hosts: kevin
remote_user: root
vars:
- dir1: /root/Ansible
- dir2: /root/Ansible/test1
- dir3: /root/Ansible/test2
tasks:
- name: Create New Folder
file: name={{ dir1 }} state=directory
- name: Create New Folder
file: name={{ dir2 }} state=directory
- name: Create New Folder
file: name={{ dir3 }} state=directory
二、通过roles角色定义变量
在Ansible的roles中定义变量,需要将变量及值的键值对形式写到roles的vars目录下的main.yml文件中,同样适用YAML语言格式,格式如下:
var1: value1
var2: value2
var3: value3
请注意:通过Roles定义的变量只适用于当前roles。
三、使用Facts获取的信息
Facts通过访问远程系统获取相应的信息[root@ss-server ansible]# ansible web -m setup
关闭信息收集的方法如下:
[root@ss-server ansible]# cat test.yml
--- # 标识
- hosts: web
gather_facts: no
四、register注册变量
变量的另一个主要用途是在运行命令时,把命令结果存储到一个变量中,不同模块的执行结果是不同的。register方式主要用于在task之间传递变量。
[root@ss-server ansible]# cat /root/register.yml
--- #标识
- hosts: web
tasks:
- shell: echo hello world
register: say_hi
- debug: var=say_hi.stdout
- debug: var=sya_hi['stdout']
五、借助with_items叠加变量
迭代:当有需要重复性执行的任务时,可以使用迭代机制:
1、对迭代项的引用,固定变量名为“item”
2、要在task中使用with_items给定要迭代的元素列表
3、列表格式:
字符串或字典
#例如1:
--- #标识
- hosts: localhost
remote_user: root
tasks:
- name: test #
shell: echo "{{item}}"
with_items:
- haha
- heihei
- hehe
register: hi_var
- debug: var=hi_var.results[0].stdout
- debug: var=hi_var.results[1].stdout
- debug: var=hi_var.results[2].stdout
#例如2:yum模块安装多个程序包
[root@localhost mariadb]# vim tasks/main.yml
--- #标识
- name: Install MariaDB package
yum: name={{ item }} state=installed
with_items:
- mariadb-server
- mariadb
- MySQL-python
- libselinux-python
- libsemanage-python
#例如3:迭代嵌套子变量(字典)
[root@localhost ansible]# vim tasks/main.yml
--- #标识
- hosts: all
remote_user: root
tasks:
- name: add some groups
group: name={{ item }} state=present
with_items:
- group1
- group2
- group3
- name: add some users
user: name={{ item.name }} group={{ item.group }} state=present
with_items:
- { name: 'user1', group: 'group1' }
- { name: 'user2', group: 'group2' }
- { name: 'user3', group: 'group3' }
六、内置变量
ansible除了inventory中内置的一堆不可被引用的设置类变量,还有几个全局都可以引用的内置变量,主要有以下几个:
inventory_hostname、inventory_hostname_short、groups、group_names、hostvars、play_hosts、inventory_dir和ansible_version。
#获取内置变量信息
[root@ss-server ansible]# ansible web -m debug -a 'msg="{{inventory_hostname}} & {{inventory_hostname_short}}"'
七、hostvars 变量
--- #标识
- hosts: centos7
tasks:
- debug: msg="{{hostvars['192.168.8.130'].ansible_eth0.ipv4.address}}"
直接在playbook中定义变量,举例如下:
[root@ss-server ansible]# cat testvar.yml
--- #标识
- hosts: web
remote_user: root
vars_files:
- vars.yml
tasks:
- name: install package
yum: name= {{ var1 }}
- name: create file
file: name=/data/{{ var2 }}.log state=touch
[root@ss-server ansible]# cat vars.yml
var1: httpd
var2: vsftpd
[root@ss-server ansible]# ansible-play -C testvar.yml
八、列表变量、循环变量、字典变量
1)ansible的变量不仅可以是单个的值,也可以为列表,即ansible传列表作为变量。如下示例:
[root@ss-server ansible]# vim test.yml
--- #标识
- hosts: web
gather_facts: no
vars:
- list: [1,2,3]
tasks:
- name: echo
debug: msg="{{ list }}"
2)循环列表
[root@ss-server ansible]# vim test.yml
--- #标识
- hosts: test_host
gather_facts: no
vars:
- list: [1,2,3]
tasks:
- name: this is loop
debug: msg="{{ item }}"
with_items: '{{list}}'
loop 关键字表示循环,去读循环体里的变量固定使用{{item}},item是个字典对象item.key=value。
需要注意:下面test.yml文件中的"loop"关键字 改为 "with_items"关键字,效果是一样的!
ansible的循环用法:在ansible 2.5版本之前,大多数人习惯使用"with_X"风格的关键字操作循环,
从ansible 2.6版本开始,官方开始推荐使用"loop"关键字代替"with_X"风格关键字。
[root@ss-server ~]# cat /etc/ansible/test.yml
--- #标识
- name: this is test
hosts: test_host
connection: local
gather_facts: no
vars:
my_list:
- a
- b
- c
- 1
tasks:
- name: debug loop output
debug:
msg: "The {{index}} one is {{item}}"
loop: "{{my_list}}" # 或者使用with_items: "{{my_list}}" 或者 with_list: "{{my_list}}"
loop_control:
index_var: index
3)字典变量
注意:在变量中使用循环时,vars下必须要有"-",符号"-"为循环体块的标志!!
[root@ss-server ansible]# vim test.yml
--- #标识
- hosts: test_host
gather_facts: no
vars:
- lists:
list1: [1,2,3]
list2: [4,5]
tasks:
- name: loop
debug: msg="{{ item }}"
with_items: '{{lists["list1"]}}'
九、inventory
cat /etc/ansible/hosts
[web]
192.168.8.131 httpd_port=81
192.168.8.132 httpd_port=82
来源:51CTO
作者:love8度幸福
链接:https://blog.51cto.com/8355320/2474182