Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.htmlhtml
ansible的playbook采用yaml语法,它简单地实现了json格式的事件描述。yaml之于json就像markdown之于html同样,极度简化了json的书写。在学习ansible playbook以前,颇有必要把yaml的语法格式、引用方式作个梳理。mysql
以一个简单的playbook为例,说明yaml的基本语法。nginx
---
- hosts: 192.168.100.59,192.168.100.65
remote_user: root
pre_tasks:
- name: set epel repo for Centos 7 yum_repository: name: epel7 description: epel7 on CentOS 7 baseurl: http://mirrors.aliyun.com/epel/7/$basearch/ gpgcheck: no enabled: True tasks: # install nginx and run it - name: install nginx yum: name=nginx state=installed update_cache=yes - name: start nginx service: name=nginx state=started post_tasks: - shell: echo "deploy nginx over" register: ok_var - debug: msg="{{ ok_var.stdout }}"
yaml文件以---
开头,以代表这是一个yaml文件,就像xml文件在开头使用<?xml version="1.0" encoding="utf-8"?>
宣称它是xml文件同样。但即便没有使用---
开头,也不会有什么影响。sql
yaml中使用"#"做为注释符,能够注释整行,也能够注释行内从"#"开始的内容。shell
yaml中的字符串一般不用加任何引号,即便它包含了某些特殊字符。但有些状况下,必须加引号,最多见的是在引用变量的时候。具体见后文。json
关于布尔值的书写格式,即true/false的表达方式。其实playbook中的布尔值类型很是灵活,可分为两种状况:centos
update_cache=yes
。非模块的参数: 这时布尔值被yaml解释器解析,彻底遵循yaml语法。接受不区分大小写的true/yes/on/y/false/no/off/n。例如上面的gpgcheck=no
和enabled=True
。数组
建议遵循ansible的官方规范,模块的布尔参数采用yes/no,非模块的布尔参数采用True/False。markdown
使用"- "(减号加一个或多个空格)做为列表项,也就是json中的数组。yaml的列表在playbook中极重要,必须得搞清楚它的写法。post
例如:
- zhangsan - lisi - wangwu
还支持内联写法:使用中括号。
[zhangsan,lisi,wangwu]
它们等价于json格式的:
[
"zhangsan",
"lisi",
"wangwu"
]
再例如:
- 班名: 初中1班
人数: 35
班主任: 隔壁老张
今天的任务: 扫操场
- 班名: 初中2班
人数: 38
班主任: 隔壁老王
今天的任务: 搬桌子
具体在ansible playbook中,列表所描述的是局部环境,它不必定要有名称,不必定要从同一个属性开始,只要使用"- ",它就表示圈定一个范围,范围内的项都属于该列表。例如:
---
- name: list1 # 列表1,同时给了个名称
hosts: localhost # 指出了hosts是列表1的一个对象
remote_user: root # 列表1的属性
tasks: # 仍是列表1的属性
- hosts: 192.168.100.65 # 列表2,可是没有为列表命名,而是直入主题
remote_user: root
sudo: yes
tasks:
惟一要注意的是,每个playbook中必须包含"hosts"和"tasks"项。更严格地说,是每一个play的顶级列表必须包含这两项。就像上面的例子中,就表示该playbook中包含了两个play,每一个play的顶级列表都包含了hosts和tasks。其实绝大多数状况下,一个playbook中都只定义一个play,因此只有一个顶级列表项。顶级列表的各项,其实能够将其看做是ansible-playbook运行时的选项。
另外,playbook中某项是一个动做、一个对象或一个实体时,通常都定义成列表的形式。见下文。
官方手册上这么称呼,其实就是key=value的另外一种写法。使用"冒号+空格"分隔,即key: value
。它通常看成列表项的属性。
例如:
- 班名: 初中1班
人数:
总数: 35
男: 19
女: 16
班主任:
大名: 隔壁老张
这厮多大: 39
这厮任教多少年: 15
今天的任务: 扫操场
- 班名: 初中2班
人数:
总数: 38
男: 19
女: 19
班主任:
大名: 隔壁老王
这厮多大: 30
喜调戏女老师: True
今天的任务: 搬桌子
未完成任务怎么办:
- 继续搬,直到完成
- 写反省
具体到playbook中,通常"虚拟性"的内容均可以经过字典的方式书写,而实体化的、动做性的、对象性的内容则应该定义为列表形式。
---
- hosts: localhost # 列表1
remote_user: root
tasks:
- name: test1 # 子列表,下面是shell模块,是一个动做,因此定义为列表,只不过加了个name
shell: echo /tmp/a.txt
register: hi_var
- debug: var=hi_var.stdout # 调用模块,这是动做,因此也是列表
- include: /tmp/nginx.yml # 一样是动做,包含文件
- include: /tmp/mysql.yml
- copy: # 调用模块,定义为列表。但模块参数是虚拟性内容,应定义为字典而非列表
src: /etc/resolv.conf # 模块参数1
dest: /tmp # 模块参数2
- hosts: 192.168.100.65 # 列表2
remote_user: root
vars:
nginx_port: 80 # 定义变量,是虚拟性的内容,应定义为字典而非列表
mysql_port: 3306
vars_files:
- nginx_port.yml # 没法写成key/value格式,且是实体文件,所以定义为列表
tasks:
- name: test2
shell: echo /tmp/a.txt
register: hi_var # register是和最近一个动做绑定的
- debug: var=hi_var.stdout
从上面示例的copy模块能够得出,模块的参数是虚拟性内容,也能使用字典的方式定义。
字典格式的key/value,也支持内联格式写法:使用大括号。
{大名: 隔壁老王,这厮多大: 30,喜调戏女老师: True}
{nginx_port: 80,mysql_port: 3306}
这等价于json格式的:
{
"大名": "隔壁老王",
"这厮多大": 30,
"喜调戏女老师": "True" }
{
"nginx_port": 80,
"mysql_port": 3306 }
再结合其父项,因而转换成json格式的内容:
"班主任": {
"大名": "隔壁老王",
"这厮多大": 30,
"喜调戏女老师": "True"
}
"vars": {
"nginx_port": 80,
"mysql_port": 3306
}
再加上列表项(使用中括号),因而:
[
{
"hosts": "192.168.100.65",
"remote_user": "root",
"vars": { "nginx_port": 80, "mysql_port": 3306 },
"vars_files": [ "nginx_port.yml" ],
"tasks": [ { "name": "test2", "shell": "echo /tmp/a.txt", "register": "hi_var" }, { "debug": "var=hi_var.stdout" } ] }
]
playbook中有3种方式进行续行。
例如,下面的3中方法。
---
- hosts: localhost
tasks:
- shell: echo 2 >>/tmp/test.txt
creates=/tmp/haha.txt # 比模块shell缩进更多
- shell: > # 在"key: "后使用大于号
echo 2 >>/tmp/test.txt
creates=/tmp/haha.txt
- shell: | # 指定多行命令
echo 2 >>/tmp/test.txt
echo 3 >>/tmp/test.txt
args:
creates: /tmp/haha.txt
模块的参数通常来讲是key=value格式的,有3种传递的方式:
例如:
---
- hosts: localhost
tasks:
- yum: name=unix2dos state=installed # key=value直接传递
- yum:
name: unxi2dos
state: installed # "key: value"字典格式传递
- yum:
args: # 使用args传递
name: unix2dos
state:installed
但要注意,当模块的参数是free_form
时,即格式不定,例如shell和command模块指定要执行的命令,它没法写成key/value格式,此时不能使用上面的第二种方式。也就是说,下面第一个模块是正确的,第二个模块是错误的,由于shell模块的命令"echo haha"是自由格式的,没法写成key/value格式。
---
- hosts: localhost
tasks:
- yum:
name: unxi2dos
state: installed
- shell:
echo haha
creates: /tmp/haha.txt
因此,调用一个模块的方式就有了多种形式。例如:
---
- hosts: localhost
tasks:
- shell: echo 1 >/tmp/test.txt creates=/tmp/haha.txt
- shell: echo 2 >>/tmp/test.txt
creates=/tmp/haha.txt
- shell: echo 3 >>/tmp/test.txt
args:
creates: /tmp/haha.txt
- shell: >
echo 4 >>/tmp/test.txt
creates=/tmp/haha.txt
- shell: |
echo 5.1 >>/tmp/test.txt
echo 5.2 >>/tmp/test.txt
args:
creates: /tmp/haha.txt
- yum:
name: dos2unix
state: installed
一个playbook中能够包含多个play。每一个play都至少包含有tasks和hosts这两项,还能够包含其余非必须项,如vars,vars_files,remote_user等。tasks中能够经过模块调用定义一系列的action。只不过,绝大多数时候,一个playbook都只定义一个play。
因此,大体关系为:
也就是说,每一个顶级列表都是一个play。例如,下面的playbook中包含了两个play。
---
- name: list1
hosts: localhost
remote_user: root
tasks:
- hosts: 192.168.100.65
remote_user: root
sudo: yes
tasks:
须要注意,有些时候play中使用了role,可能看上去没有tasks,这是由于role自己就是整合playbook的,因此没有也不要紧。但没有使用role的时候,必须得包含hosts和tasks。例如:
---
- hosts: centos
remote_user: root
pre_tasks:
- name: config the yum repo for centos 7
yum_repository:
name: epel
description: epel
baseurl: http://mirrors.aliyun.com/epel/7/$basearch/
gpgcheck: no
when: ansible_distribution_major_version == "7"
- name: config the yum repo for centos 6
yum_repository:
name: epel
description: epel
baseurl: http://mirrors.aliyun.com/epel/6/$basearch/
gpgcheck: no
when: ansible_distribution_major_version == "6"
roles:
- nginx
post_tasks:
- shell: echo 'deploy nginx/mysql over'
register: ok_var
- debug: msg='{{ ok_var.stdout }}'
playbook中定义的都是些列表和字典。绝大多数时候,都不须要使用引号,但有两个特殊状况须要考虑使用引号。
大括号要使用引号包围,是由于不使用引号时会被yaml解析成内联字典。例如要使用大括号引用变量的时候,以及想输出大括号符号的时候。
---
- hosts: localhost
tasks:
- shell: echo "{{inventory_hostname}}:haha"
冒号尾随空格时要使用引号包围,是由于它会被解析为"key: value"的形式。并且包围冒号的引号还更严格。例以下面的debug模块中即便使用了引号也是错误的。
---
- hosts: localhost
tasks:
- shell: echo "{{inventory_hostname}}:haha"
register: hello
- debug: msg="{{hello.stdout}}: heihei"
由于它把{{...}}当成key,heihei当成value了。所以,必须将整个debug模块的参数都包围起来,显式指定这一段是模块的参数。但这样会和原来的双引号冲突,所以使用单引号。
---
- hosts: localhost
tasks:
- shell: echo "{{inventory_hostname}}:haha"
register: hello
- debug: 'msg="{{hello.stdout}}: heihei"'
可是,若是将shell模块中的冒号后也尾随上空格,即写成echo "{{inventory_hostname}}: haha"
,那么shell模块也会报错。所以也要使用多个引号,正确的以下:
---
- hosts: localhost tasks: - shell: 'echo "{{inventory_hostname}}: haha"' register: hello - debug: 'msg="{{hello.stdout}}: heihei"'