YAML

一、概述
YAML是“另一种标记语言(Yet Another Markup Langure)”的外语缩写,它类似于标准通用标记语言的子集xml的数据描述语言,且能够被电脑识别,是一个可读性高并且容易被人类阅读,容易和脚本语言进行交互,用来表达资料序列的编程语言。
特点:
1、可读性好
2、和脚本语言的交互性好
3、使用实现语言的数据类型
4、有一个一致的信息模型
5、易于实现
6、可以基于流来处理
7、表达能力强,扩展性好
二、语法
YAML可以简单表达清单、散列表、哈希表、标量等数据结构,其结构(structure)通过空格来展示,序列(sequence)里的项用 ‘-’ 来代表,Map里的键值对用 ‘:’分割。例如:
name:John
age:41
gender:Male
spouse:
name:Jane
age:37
gender:Female
chilren:
- name: Jimmy
age:17
gender:Male
- name: Jenny
age:13
gender:Female
2.1列表
列表中的所有元素均使用 ‘-’ 打头,例如:
# A list of fruits
- apple
- orange
- banana
2.2字典(dictionary)
字典通过key和value进行标示,例如:
# A employee record
name: xxx
job: xxx
skill: xxx
也可以将key:value放于{} 中进行表示,例如:
---
# A employee record
{ name:xxx,job:xxx,skill:xxx }


Ansible基础元素(变量、Inventory、条件测试、迭代)
一、变量
1.1命名
变量名仅能由字母、数字和下划线组成,且只能以字母开头

1.2facts
facts是由正在通信的远程目标主机发回的信息,这些信息被保存在ansible变量中,要获取指定的远程主机所支持的所有facts,可以使用如下命令进行:
ansible hostname -m setup

1.3 register
把任务的输出定义为变量,然后用于其他任务,示例如下:
tasks:
- shell: /usr/bin/boo
register: foo_result
ingore_error: True

1.4通过命令行传递变量
ansible-playbook test.yaml --extra-vars "hosts=www user=www"

1.5通过roles传递变量
当给一个主机应用角色的时候可以传递变量,然后再角色内使用这些变量,示例如下:
- hosts: webserersservers
roles:
- common
- { role:foo_app,dir:'/webserers/htdocs/a.com',ports:8080 }

二、Inventory
ansible的主要功能在于批量主机操作,为了便捷地使用其中的部分主机,可以在Inventory file中将其分组命名,默认的Inventory file为/etc/ansible/hosts。
Inventory file 可以有多个,且也可以通过Dynamic Inventory来动态生效。
1、Inventory文件格式
Inventory文件遵循INI文件风格,中括号的字符为组名,可以将同一个主机同时归并到不同的组中;此外,当如若目标主机使用了非默认的ssh端口,还可以在主机名称之后用冒号加端口号来注明。
ntp.example.com
[webserers]
linux-node2.example.com:2222
linux-node3.example.com
[dbserers]
linux-node2.example.com
linux-node3.example.com

如果主机名遵循相似的命名模式,还可以使用列表的方式标识各主机。例如:
[webserers]
linux-node[01:50].example.com

2、主机变量
可以在Inventory中定义主机时为其添加变量,以便于在playbook中使用,例如:
[webserers]
linux-node2.example.com http_port=80 Maxclient=808
linux-node3.example.com http_port=8080 Maxclient=909

3、组变量
组变量是指赋予给指定组内所有主机上的playbook中可以使用的变量。例如:
[webserers]
linux-node2.example.com
linux-node3.example.com
[dbserers:vars]
ntp_server=ntp.example.com
nfs_server=nfs.example.com

4、组嵌套
在 Inventory 中,组还可包含其他的组,并且也可以向组中的主机指定变量,不过,这些变量只能在ansible-playbook中使用,而ansible不支持。例如:
[apache]
httpd1.example.com
httpd2.example.com
[nginx]
nginx1.example.com
nginx2.example.com
[webserers:children]
apache
nginx
[webserers:vars]
ntp_server=ntp.example.com

5、Invertory参数
ansible基于ssh连接invertory中指定的远程主机时,还可以通过参数指定其交互方式,这些参数如下所示:
ansible_ssh_port
ansible_ssh_host
ansible_ssh_user
ansible_ssh_pass
ansible_sudo_pass
ansible_connection
ansible_ssh_private_key_file
ansible_shell_type
ansible_python_interpreter


例:我们需要先批量创建用户,然后为其中的三台主机部署mysql,另外的三台主机部署apache,这种情况下再用单个的命令去实现就显得不那么简单了,带条件的运维操作如下如图。
YAML
文章图片

可以看到这个简单的场景具备了下面所说的一些特点:
? 流程化——先创建用户,再部署程序;
? 具备条件——某些设备需要部署mysql,某些设备需要部署apache。为了解决这种流程化的运维操作,ansible有了PlayBook这个概念。

Ansible playbooks
playbook是由一个或多个“play”组成的列表,play的主要功能在于将事先归并于一组的主机装扮成实现通过ansible中的task定义好的角色。从根本上将,所谓是task无非是调用ansible中的一个module,将多个play组织在一个playbook中,即可以让他们联同起来按事先编排的机制同唱一台大戏。例如:
- hosts: web
remote_user: root
vars:
- http_ports: 80
- max_client: 256

tasks:
- name: ensure apache is at latest version
yum: name=httpd state=latest
- name: ensure apache is running
service: name=httpd state=started

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



一、playbook基础组件
1、hosts和users
hosts用于指定要执行指定任务的主机,可以是一个或多个由冒号分割的主机组,remote_user则用于指定远程主机上执行任务的用户。例如:
- hosts: webserers
remote_user: root
备注:如果对所有的主机都执行某一命令的时候,可以在hosts: all
不过,remote_user也可用于各task中,也可以通过指定其通过sudo的方式在远程主机上来执行任务。
- hosts: web
remote_user: root
tasks:
- name: test connection
ping:
remote_user: root
sudo:yes


playbook的组成结构
Inventory
modules
ad hoc commands
playbooks:
tasks:任务,即调用模块完成的基本操作
variables:变量
template:模块
handlers:处理器,由某事件发生触发的操作
roles:角色
基本结构:
- hosts: webserers
remote_user: root
tasks:
- task1:
- task2:
2、任务列表和action
play的主体部分是task list。task list中各任务按次序逐个在hosts中指定的所有主机上运行,即在所有主机上完成第一个任务后再开始第二个,在运行自上而下某playbook时,如果中途发生错误,所有已执行任务都有可能回滚,因此,在更正playbook后重新执行一次即可。
每个task都应该有其name,用于playbook的执行结果输出
定义task时可以使用“actions:modules options”或“module”:
tasks:
- name: ensure apache running
service: name=httpd state=started

在众多模块中,只有command和shell模块仅需要给定一个列表而无需使用“key=value”格式。例如:
tasks:
- name: disable selinux
command: /sbin/setenforce 0

tasks:
- name: running this command and ingore the result
shell: /usr/bin/boo || /bin/true
或使用ingnore_error来忽略错误信息
tasks:
- name: running this command and ingore the result
shell: /usr/bin/boo
ingore_error: True

例子:
- hosts: webserers
remote_user: root
tasks:
- name:create nginx group
group: name=nginx system=yes gid=606

- name:crete nginx user
user: name=nginx system=yes uid=604 gid=nginx


3、handlers
用于当关注的某资源发生变化时采取的一定操作。
“notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时都执行指定的操作,取而代之,仅在所有的变化完成后一次性执行的指定操作。在notify中列出的操作叫handler,也即notify中调用handler中定义的操作。
- name: template configuration file
template: src=https://www.it610.com/article/template.j2 dest=/etc/foo.configuration
notify:
- restart memcached
- restart apache

handler是task列表,这些task与前述的task基础上没有本质上的不同:
handlers:
- name:restart memcached
service: name=memcached status=restarted
- name: restart apache
service: name=httpd status=restarted

例子:
- hosts: webserers
remote_user: root
tasks:
- name: install apache
yum: name=httpd status=latest
- name: install configuration file
copy: src=https://www.it610.com/root/httpd.conf dest=/etc/httpd/conf/httdp.conf
- name: start apache
service: name=httpd status=started enable=true
当配置文件发生改变时:
- hosts: webserers
remote_user:root
tasks:
- name: install apache
yum: name=httpd status=latest
- name: install configuration file
copy: src=https://www.it610.com/root/httpd.conf dest=/etc/httpd/conf/httdp.conf
notify:
- restart apache
- name: start apache
service: name=httpd status=started enable=true
handlers:
- name: restart apache
service: name=httpd status=restart


4、使用ansible的注意事项
- hosts: web
remote_user: root
vars:
- dir: /root/aaa/
tasks:
- name: copy file
copy: src=https://www.it610.com/root/ceshi/updatecode.sh dest={{ dir }}
- name: aa
copy: src=https://www.it610.com/alidata/www/tuiguang/index.php dest={{ dir }}



备注:
①在每一个冒号后面必须要有一个空格
②必须要给每一个任务其一个名字,如果在同一个名字下出现几个相同的任务,只会执行最后一个
③vars是定义变量,变量可以有多个,里面调用变量是采用jinjia2模板
④yaml语言是通过层级区分不同的任务

⑤在每一个主机前面必须一个 -,而且要顶格


二、如何在playbook中使用变量
1、定义变量(变量名:变量值)
vars:
- service:httpd
- package:httpd
调用:
name = {{ service }}
name = {{ package }}

2、ansible所获得的变量也可以定义
获取变量方法:ansible+ip(192.168.88.133) -m setup
例子:
- hosts:webserers
remote_user:root
tasks:
- name: copy file
copy: content="{{ ansible_all_ipv4_address }}" dest=/tmp/var.ans

3、在inventory中定义变量(/etc/ansible/hosts)
[webserers]
192.168.88.134 testvar=88.134
192.168.88.136 testvar=88.136
调用方法:
copy: content="{{ ansible_all_ipv4_address }},{{ testvar }}" dest=/tmp/var.ans

4、在playbook使用条件测试
如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用条件测试
when语句
在task后添加when子句即可使用条件测试,when语句支持jinja2表达式语法。例如
tasks:
- name: shutdown Debian flavored system
command: /sbin/shutdown -h now
when: ansible_os_family == "Debian"
when语句还可以使用jinja2的大多"filter",例如要忽略此前某语句的错误,并基于此结果(faild或者success)运行后面指定的语句,可使用类似的如下形式
tasks:
- command: /bin/false
register: result
ignore_error: True
- command:/bin/something
when:result/faild
- command: /bin/something_else
when:result/success
- command: /bin/something_else
when: result/skipped

此外,when语句还可以使用facts或者playbook中定义的变量
例如:如果对方主机名是node2.example.com,才创建user10用户,否则不创建
- hosts: all
remote_user: root
vars:
- username:user10
tasks:
- name: create {{ username }} user
user: name={{ username }}
when: ansile_fqdn == "node2.example.com"

5、迭代(即循环)重复执行同类的task时使用
当有需要重复性执行的任务时,可以使用迭代机制,其使用格式为将需要迭代的内容定义为 item变量引用,并通过 with_items语句来指明迭代的元素列表即可,例如:
- name: add serveral users
user:name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
- testuser3

上面的语句功能等同于下面的语句:
- name: add user testuser1
user: name=testuser1 state=present groups=wheel
- name: add user testuser2
user: name=testuser2 state=present groups=wheel
- name: add user testuser3
user: name=testuser3 state=present groups=wheel

事实上,with_items中还可以使用元素为hashes。例如:
- name: add serveral users
user: name={{ item.user }} groups={{ item.group }} state=present
with_items:
- { name:'testuser1',group:'wheel' }
- { name:'testuser2',group:'wheel' }
- { name:'testuser3',group:'wheel' }

6、模板元素(一般以 .j2命名)
把经常发生变化的元素改成变量

7、tags标签
在playbook中可以为某个或某些任务定义一个"标签",在执行此playbook命令使用--tags 选项能实现仅指定的task而非所有的
运行方式:ansible-playbook+文件名(.yaml)+ --tags="自定义标签名"
特殊的tags:always
tags:
- always

三、roles
ansible自1.2版本后引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handles等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷地include 它们的一种机制。角色一般基于主机构建服务的场景中,但也可以用于构建守护进程场景中。
一个roles的案例如下所示:
site.yml
webserers.yml
dbserers.yml
roles/
common/
file/
template/
tasks/
handlers/
vars/
meta/
webserers/
file/
template/
tasks/
handlers/
vars/
meta/
在playbook中,可以这样使用roles:
- hosts:webserers
roles:
- common
- webserers
也可以向roles传递参数,如:
- hosts:webserers
roles:
- common
- { role:foo_app,dir:'/dir/a',port:5000 }
- { role:foo_app,dir:'/dir/b',port:5001 }
甚至可以使用条件式使用roles,如:
- hosts:webserers
roles:
- { role:foo_app,when:"ansible_os" == "centos" }




【YAML】

    推荐阅读