上篇文章Ansible 入门指南 - 安装及 Ad-Hoc 命令使用介绍的额是 Ad-Hoc 命令方式,本文将介绍 Playbook
方式。html
Playbook
译为「剧本」,以为还挺恰当的。mysql
Playbook
译为「剧本」,以为还挺恰当的。那么 play
那我就译为 「场景」吧。playbook 由一个或多个 ‘plays’ 组成.它的内容是一个以 ‘plays’ 为元素的列表linux
能够为 playbook 中的每个 play,个别地选择操做的目标机器是哪些,以哪一个用户身份去完成要执行的步骤(called tasks)git
$ ansible-playbook -h Usage: ansible-playbook [options] playbook.yml [playbook2 ...] Runs Ansible playbooks, executing the defined tasks on the targeted hosts.
在指定的目标主机上执行定义好的 tasks
。github
playbook.yml
常包含下面几个关键字:web
hosts
:为主机的IP,或者主机组名,或者关键字allremote_user
: 以哪一个用户身份执行。vars
: 变量tasks
: playbook的核心,定义顺序执行的动做 action
。每一个action
调用一个ansbile module
。action
语法: module: module_parameter=module_value
module
有yum
、copy
、template
等,module
在 ansible 的做用,至关于 bash 脚本中yum
,copy
这样的命令。name
,这样在运行 playbook 时,从其输出的任务执行信息中能够很好的辨别出是属于哪个 task 的handers
: 是 playbook 的 event ,默认不会执行,在 action 里触发才会执行。屡次触发只执行一次。一个简单的示例:
deploy.yml
的功能为 web 主机部署 apache, 其中包含如下部署步骤:sql
--- - hosts: centos vars: httpd_port: 8080 max_clients: 200 remote_user: root tasks: - name: ensure apache is at the latest version yum: name=httpd state=present - name: Write the configuration file template: src=templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf notify: - restart apache ignore_errors: False - name: Write the default index.html file template: src=templates/index.html.j2 dest=/var/www/html/index.html ignore_errors: False - name: ensure apache is running service: name=httpd state=started handlers: - name: restart apache service: name=httpd state=restarted
运行ansible-playbook deploy.yml
便可执行。shell
taks
参数实际上是有不一样写法的,当参数比较少时,可用key=value
的方式apache
tasks: - name: make sure apache is running service: name=httpd state=running
当tasks
参数比较多时,为了美观和不易出错,用 yml
的字典传参比较好:编程
tasks: - name: make sure apache is running service: name: httpd state: running
task中每一个action会调用一个module,在module中会去检查当前系统状态是否须要从新执行。
action
会获得返回值 changed
;action
获得返回值ok
module 的执行状态的具体判断规则由各个 module 本身决定和实现的。例如,”copy” module的判断方法是比较文件的checksum,代码以下:
下面这条命令,指定 inventory 文件,列出 hosts 列表,并不会去执行定义的 tasks,观察 host 是否配置正确颇有用:
ansible-playbook -i inventory/slave_init.yml execute_slave_init.yml --list-hosts
ansible-playbook playbook.yml --verbose
ansible-playbook playbook.yml -f 10
playbook 中使用到了 become
,执行playbook
时能够加上--ask-become-pass
参数:
ansible-playbook deploy.yml --ask-become-pass
#
表示注释,从这个字符一直到行尾,都会被解析器忽略---
. 这是 YAML 格式的一部分, 代表一个文件的开始.键: 值
的形式组成(这个冒号后面必须是一个空格)foo: "{{ variable }}"
。参考
其实在一个Playbook文件中还能够有针对两组server进行不一样的操做,例如给web安装http服务器,和给lb安装mysql放在一个文件中:
--- #安装apache的play - hosts: web remote_user: root tasks: - name: ensure apache is at the latest version yum: pkg=httpd state=latest # 安装mysql server的play - hosts: lb remote_user: root tasks: - name: ensure mysqld is at the latest version yum: pkg=mariadb state=latest
上面例子中针对每一组 server 的全部操做就组成一个 play,通常一个 playbook 中只包含一个 play,play 的内容称为 tasks,即任务。
参考:
handlers与tasks不一样,tasks会默认的按定义顺序执行每个task,handlers则不会,它须要在tasks中被调用,才有可能被执行。
Handlers will only be fired for tasks which report a changed state.
只有当 task 执行状态显示是 changed 时,handler 动做才会被触发
Tasks中的任务都是有状态的,changed或者ok。 在Ansible中,只在task的执行状态为 changed
的时候,才会执行该task调用的handler。
在全部的task列表执行以后执行,若是有多个task notify同一个handler,那么 handlers 也只执行一次。
若是你在tasks中修改了apache的配置文件。须要重起apache。此外还安装了apache的插件。那么还须要重起apache。像这样的应该场景中,重起apache就能够设计成一个handler.
当一个文件的内容被改动时,重启两个 services:
- name: template configuration file template: src=template.j2 dest=/etc/foo.conf notify: - restart memcached - restart apache
notify
下列出的便是 handlers.name
)来引用。handlers: - name: restart memcached service: name=memcached state=restarted - name: restart apache service: name=apache state=restarted
此外,还有个注意点:
handlers
定义的顺序是1>2>3
,notify 的顺序是3>2>1
,实际执行顺序:1>2>3
.总结,Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操做.除此之外不多用到。
参考
playbook 中经常使用的集中变量:
在 playbook 中,经过关键字 vars
自定义变量,用 {{}}
引用变量。
经过 vars_files
关键字指定了变量文件:
--- - hosts: centos vars: httpd_port: 80 vars_files: - ./vars_servers.yml remote_user: root tasks: - debug: msg: "http_port: {{httpd_port}}" - debug: msg: "x86 passwd: {{x86.password}}" - debug: msg: "arm passwd: {{arm.password}}" # 也能够用 arm['password'] 表示
专门存放变量的文件:
# vars_servers.yml x86: password: 123 arm: password: 456
ansible 经过 module setup 收集主机的系统信息,这些收集到的系统信息叫作 facts
,这些facts
能够直接以变量的形式使用。
哪些 facts
变量能够引用的?经过以下命令行调用setup module
能够查看:
ansible all -m setup -u root
能够看到它输出的变量信息有不少!
复杂的facts
变量的使用能够用以下两种形式:
{{ ansible_ens3["ipv4"]["address"] }}
{{ ansible_ens3.ipv4.address }}
ansible_hostname
指定的 host 名称ansible_default_ipv4.address
主机真实的 ipv4 地址,小网IP--- - hosts: all user: root tasks: - name: echo system shell: echo {{ ansible_os_family }} - name install ntp on Debian linux apt: name=git state=installed when: ansible_os_family == "Debian" - name install ntp on redhat linux yum: name=git state=present when: ansible_os_family == "RedHat"
在 playbook 中,若是不收集系统信息,那么上面的变量就不能再 playbook 中使用了,可是有时候关闭会加快执行的效率:
- hosts: all gather_facts: no
将某个 task 执行的结果「注册」为一个变量。后面的 action 就可使用它
--- - hosts: centos tasks: - name: ls /tmp shell: ls -l /tmp register: result ignore_errors: True - name: echo result when rc==5 shell: echo "{{result}}" when: result.rc == 5 - name: debug show stdout debug: msg: "{{result.stdout}}"
「注册变量」常常和debug module
一块儿使用,这样能够得到 action 更多的输出信息,帮助调试。
参考
set_facts
的模块--- - hosts: "{{hosts}}" remote_user: "{{user}}"" tasks: - debug: msg="{{hosts}}""
命令输入变量:
ansible-playbook extra_learn.yml --extra-vars "{'hosts':'x86','user':‘’michael'}" # or ansible-playbook extra_learn.yml --extra-vars "hosts=x86 user=michael"
when
:条件判断,相似编程语言中的 if
loop
:循环,相似编程语言中的 while
block
:将几个 task
组成一块代码,便于针对一组操做进行异常处理等例如,在某个特定版本的系统上装包,或者只在磁盘空间满了的文件系统上执行清理操做。这些操做在Playbook中用when语句实现。
主机为Debian Linux马上关机
tasks: - name: "shutdown Debian flavored systems" command: /sbin/shutdown -t now when: ansible_os_family == "Debian"
根据action的执行结果,来决定接下来执行的action。
tasks: - command: /bin/false register: result ignore_errors: True - command: /bin/something when: result|failed - command: /bin/something_else when: result|success - command: /bin/still/something_else when: result|skipped
远程中的系统变量facts变量做为when的条件,用“|int”还能够转换返回值的类型:
--- - hosts: web tasks: - debug: msg="only on Red Hat 7, derivatives, and later" when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
为了保持简洁,重复的任务能够用如下简写的方式:
- name: add several users user: name="{{ item }}" state=present groups=wheel with_items: - michael - qq
若是你在变量文件中或者 ‘vars’ 区域定义了一组YAML列表,你也能够这样作:
vars: userlist: ["micahel", "qq"] tasks: -name: add several user user: name: "{{ item }}" state: present groups: wheel with_items: "{{userlist}}"
使用 with_items
用于迭代的条目类型不只仅支持简单的字符串列表.若是你有一个哈希列表,那么你能够用如下方式来引用子项:
- name: add several users user: name="{{ item.name }}" state=present groups="{{ item.groups }}" with_items: - { name: 'michael', groups: 'wheel' } - { name: 'qq', groups: 'root' }
这个例子不只演示了 with_dict
用法,还使用循环安装了 RPM 包
--- - hosts: centos vars: users: michael: name: michael xiang phone: 123 qq: name: qq huang phone: 456 rpms: - httpd - lrzsz - vim - git tasks: - name: print phone records debug: msg="User {{item.key }} is {{ item.value.name }} {{item.value.phone}}" with_dict: "{{ users }}" - name: install rpms yum: name="{{item}}" state=installed with_items: "{{rpms}}"
with_fileglob
能够以非递归的方式来模式匹配单个目录中的文件.以下面所示:
tasks: # first ensure our target directory exists - file: dest=/etc/fooapp state=directory # copy each file over that matches the given pattern - copy: src=\{\{ item \}\} dest=/etc/fooapp/ owner=root mode=600 with_fileglob: - /playbooks/files/fooapp/*
参考
多个action组装成块,能够根据不一样条件执行一段语句 :
tasks: - block: - yum: name=\{\{ item \}\} state=installed with_items: - httpd - memcached - template: src=templates/src.j2 dest=/etc/foo.conf - service: name=bar state=started enabled=True when: ansible_distribution == 'CentOS' become: true become_user: root