设为首页 收藏本站
查看: 1706|回复: 0

[经验分享] Ansible系列(三):YAML语法和playbook写法

[复制链接]

尚未签到

发表于 2018-1-2 21:43:12 | 显示全部楼层 |阅读模式
  本文目录:
  1.1 初步说明
  1.2 列表
  1.3 字典
  1.4 分行写
  1.5 向模块传递参数
  1.6 playbook和play的关系
  1.7 playbook中什么时候使用引号
  ansible的playbook采用yaml语法,它简单地实现了json格式的事件描述。yaml之于json就像markdown之于html一样,极度简化了json的书写。在学习ansible playbook之前,很有必要把yaml的语法格式、引用方式做个梳理。

1.1 初步说明
  以一个简单的playbook为例,说明yaml的基本语法。
  

---  
- 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文件一样。但即使没有使用---开头,也不会有什么影响。

  •   yaml中使用"#"作为注释符,可以注释整行,也可以注释行内从"#"开始的内容。

  •   yaml中的字符串通常不用加任何引号,即使它包含了某些特殊字符。但有些情况下,必须加引号,最常见的是在引用变量的时候。具体见后文。

  •   关于布尔值的书写格式,即true/false的表达方式。其实playbook中的布尔值类型非常灵活,可分为两种情况:

  • 模块的参数: 这时布尔值作为字符串被ansible解析。接受yes/on/1/true/no/off/0/false,这时被ansible解析。例如上面示例中的update_cache=yes。
  •   非模块的参数: 这时布尔值被yaml解释器解析,完全遵循yaml语法。接受不区分大小写的true/yes/on/y/false/no/off/n。例如上面的gpgcheck=no和enabled=True。
      建议遵循ansible的官方规范,模块的布尔参数采用yes/no,非模块的布尔参数采用True/False。


1.2 列表
  使用"- "(减号加一个或多个空格)作为列表项,也就是json中的数组。yaml的列表在playbook中极重要,必须得搞清楚它的写法。
  例如:
  

- 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中某项是一个动作、一个对象或一个实体时,一般都定义成列表的形式。见下文。

1.3 字典
  官方手册上这么称呼,其实就是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"
  
}
  
]
  
}
  
]
  

  


1.4 分行写
  playbook中有3种方式进行续行。


  • 在"key: "的后面使用大于号。
  • 在"key: "的后面使用竖线。这种方式可以像脚本一样写很多行语句。
  • 多层缩进。
  例如,下面的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
  

  


1.5 向模块传递参数
  模块的参数一般来说是key=value格式的,有3种传递的方式:


  • 直接写在模块后,此时要求使用"key=value"格式。这是让ansible内部去解析字符串。因为可分行写,所以有多种写法。
  • 写成字典型,即"key: value"。此时要求多层缩进。这是让yaml去解析字典。
  • 使用内置属性args,然后多层缩进定义参数列表。这是让ansible明确指定用yaml来解析。
  例如:
  

---  
- 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
  

  


1.6 playbook和play的关系
  一个playbook中可以包含多个play。每个play都至少包含有tasks和hosts这两项,还可以包含其他非必须项,如vars,vars_files,remote_user等。tasks中可以通过模块调用定义一系列的action。只不过,绝大多数时候,一个playbook都只定义一个play。
  所以,大致关系为:


  • playbook: [play1,play2,play3]
  • play: [hosts,tasks,vars,remote_user...]
  • tasks: [module1,module2,...]
  也就是说,每个顶级列表都是一个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 }}'
  

  


1.7 playbook中什么时候使用引号
  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"'
  

  

  回到系列文章大纲:http://www.cnblogs.com/f-ck-need-u/p/7048359.html

转载请注明出处:http://www.cnblogs.com/f-ck-need-u/p/7113610.html

注:若您觉得这篇文章还不错请点击下右下角的推荐,有了您的支持才能激发作者更大的写作热情,非常感谢!

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-430956-1-1.html 上篇帖子: Ansible系列(五):各种变量定义方式和变量引用 下篇帖子: Ansible之playbooks
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表