sapser's blog

Standing on the shoulders of Giants

ansible学习之四:Playbooks

Jul 21, 2014 • ansible


ansible的playbook就如同salt的state,一个playbook就是一个YAML文件,所以playbook文件一般都以.yml结尾,写playbook不需要复杂的YAML语法,所以也不用单独去学YAML语法。此外playbook和模板文件(template模块)还使用jinja2语法语法实现高级功能(后面逐一讲到),不光这里,jinja2语法很多地方都会用到,比如python大部分web框架的模板系统,所以可以去单独学一下。

一个playbook文件由一个或多个play组成,每个play定义了在一个或多个远程主机上执行的一系列的task,其中每个task一般就是调用一个ansible的模块,如调用copy模块复制文件到远程主机或调用shell模块执行命令。

例子:只带有一个play的playbook文件test.yml

---               #任何playbook文件(其实就是yaml文件)都要以这个开头
- hosts: webservers         #对webservers主机组下的所有主机进行操作
  vars:           #为该play定义两个变量
    http_port: 80
    max_clients: 200
  remote_user: sapser       #连接到远程主机的用户
  sudo: yes       #以sudo模式运行该play
  sudo_user: root           #sudo到哪个用户,默认为root,如果sudo到该用户需要密码,则在执行ansible-playbook的时候指定-K选项来输入sudo密码
  tasks:          #开始定义task
  - name: ensure apache is at the latest version            #这既是每个task的说明也是每个task的名字
    yum: pkg=httpd state=latest    
    tags:         #给该task打一个标签
      - last_http
  - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
    notify:       #提供watch功能,这里当apache配置文件改变时,就调用handlers中名为"restart apache"的task来重启apache
    - restart apache
  - name: ensure apache is running
    service: name=httpd state=started
  handlers:       #notify通知这里的task执行,谨记:定义在handlers下的task只有在notify触发的时候才会执行
    - name: restart apache
      service: name=httpd state=restarted

执行该playbook文件:

$ ansible-playbook test.yml

就是这么简单,然后就是等待ansible去webservers组下的所有远程主机执行上面定义的tasks,输出也非常容易看懂,通过红黄绿三种颜色标明了不同的执行结果,红色表示有task执行失败,黄色表示改变了远程主机状态。

playbook中的每个play首先要定义的就是该play要在哪些主机上执行,如上面示例的

---
- hosts: webservers

可以指定单个主机、单个组或以:分割的多个主机或组,具体见ansible学习之三:Host Patterns

sudo: yes表示远程主机要以sudo权限执行tasks,不光可以对整个play生效,还可以针对单个task生效(remote_user指令也一样):

---
- hosts: webservers
  remote_user: root
  tasks:
    - shell: cmd
      remote_user: user1

    - service: name=nginx state=started
      sudo: yes       #只sudo运行该task
      sudo_user: user2     #sudo到user2用户,如果sudo需要密码记得为ansible-playbook命令提供"-K"选项

tasks由一系列task组成,多个task按照顺序执行,默认所有匹配主机都执行完一个task后才会移动到下一个task执行,默认如果所有主机都执行某个task失败,则ansible会中断执行流程并打印错误消息,这里都是说的默认,也就是说这些行为都是可自定义的,以后会讲到这些主题。

上面提到过一个task其实就是执行一个模块,ansible中的模块是幂等的(idempotent),也就是说多次执行同一个task,只有在状态发生改变后才会真的去执行,通过下面的例子讲解:

tasks:
  - name: make sure apache is running
    service: name=httpd state=started

该task用于保证apache服务器处于运行状态,如果我多次执行该task且apache一直处于运行状态的话,则该task其实什么都不会做。这样做的好处就是你可以随意执行你的playbook文件,不用担心改变远程主机上的内容(除非状态有变化必须要修改)。这里要特别提一下commandshell模块,这两个模块都是用于在远程主机上执行命令,每次调用这两个模块都会重新执行一遍命令,一般来说不会有什么影响,不过ansible也提供了creates参数来将这两个模块实现idempotent。

handlers是和notify指令搭配使用的,作用是当一个task执行修改了远程主机状态时就通知(notify)一个handlers中的task执行,一般用在修改了远程服务的配置文件然后调用handlers中的对应task去重启该服务,例子如下:

tasks:
  - name: template configuration file
    template: src=template.j2 dest=/etc/foo.conf
    notify:
      - restart memcached
      - restart apache
handlers:
  - name: restart memcached
    service:  name=memcached state=restarted
  - name: restart apache
    service: name=apache state=restarted

这里只有模板文件template.j2发生了变化,也就是真正修改了远程主机的/etc/foo.conf文件后,才会触发handlers中的两个task执行,其他情况handlers中的task都是不会运行的。

如果一行太长可以分开多行写:

tasks:
  - name: Copy ansible inventory file to client
    copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts
            owner=root group=root mode=0644


最后附上ansible-playbook命令参数:

Usage: ansible-playbook playbook.yml

Options:
  -u REMOTE_USER, --user=REMOTE_USER           ssh连接的用户名,ansible.cfg中可以配置
  -k, --ask-pass        提示输入ssh登录密码,当使用密码验证登录的时候用
  -s, --sudo            sudo运行
  -U SUDO_USER, --sudo-user=SUDO_USER          sudo到哪个用户,默认为root
  -K, --ask-sudo-pass   提示输入sudo密码,当不是NOPASSWD模式时使用
  -T TIMEOUT, --timeout=TIMEOUT                ssh连接超时时间,默认10秒
  -C, --check           指定该参数后,执行playbook文件不会真正去执行,而是模拟执行一遍,然后输出本次执行会对远程主机造成的修改
  -c CONNECTION         连接类型(default=smart)
  -D, --diff            如果file和template模块改变,会显示改变的内容,应该和--check一起
  -e EXTRA_VARS, --extra-vars=EXTRA_VARS       设置额外的变量如:key=value or YAML/JSON,以空格分隔变量,或用多个-e
  -f FORKS, --forks=FORKS                      fork多少个进程并发处理,默认5
  -i INVENTORY, --inventory-file=INVENTORY     指定hosts文件路径,默认default=/etc/ansible/hosts
  -l SUBSET, --limit=SUBSET       指定一个pattern,对- hosts:匹配到的主机再过滤一次
  --list-hosts          只打印有哪些主机会执行这个playbook文件,不是实际执行该playbook
  --list-tasks          列出该playbook中会被执行的task
  -M MODULE_PATH, --module-path=MODULE_PATH    模块所在路径,默认/usr/share/ansible/
  --private-key=PRIVATE_KEY_FILE      私钥路径
  --start-at-task=START_AT            start the playbook at the task matching this name
  --step                同一时间只执行一个task,每个task执行前都会提示确认一遍
  --syntax-check        只检测playbook文件语法是否有问题,不会执行该playbook
  -t TAGS, --tags=TAGS  当play和task的tag为该参数指定的值时才执行,多个tag以逗号分隔
  --skip-tags=SKIP_TAGS 当play和task的tag不匹配该参数指定的值时,才执行
  -v, --verbose         verbose mode (-vvv for more, -vvvv to enable connection debugging)


上一篇:ansible学习之三:Host Patterns

下一篇:ansible学习之五:Roles and Include Statements