码迷,mamicode.com
首页 > 其他好文 > 详细

轻量级自动化运维工具ansible之二:playbook详解

时间:2016-05-04 06:38:13      阅读:1944      评论:0      收藏:0      [点我收藏+]

标签:ansible   playbook   

  在介绍playbook之前,我们先了解一下YAML语言,因为playbook是用YAML语言编写的


一、YAML

  1、YAML是一种可读性高的用来表达资料序列的语言,其语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。所有的yaml文件都以"---"开头表示开始一个document,所有的列表元素以"-"开头,键值对用":",后面的空格是必须的下面是一个示例:

    ---   #打头符可省略

    - name: John Smith

      age: 41

      gender: Male

      spouse:

        name: Jane Smith

        age: 37

        gender: Female

      children:

        - name: Jimmy Smith

         age: 17

         gender: Male

        - name: Jenny Smith

         age 13

         gender: Female

    YAML文件扩展名通常为.yaml或.yml,如example.yaml

  2、list

    列表的所有元素均使用“-”打头,例如:

      # A list of tasty fruits

      - Apple

      - Orange

      - Strawberry

  3、dictionary

    字典通过key与valuef进行标识,例如:

      # An employee record

      name: Example Developer

      job: Developer

      skill: Elite

    也可以将key:value放置于{}中进行表示,例如:

      # An employee record

      {name: Example Developer, job: Developer, skill: Elite}


二、playbook详解

   playbook(剧本)是ansible管理配置、部署应用和编排的文件,可用来描述你想在被控主机上执行的策略或者一组任务等。

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

   playbook使用YAML语言编写,文件名以.yaml或.yml结尾。此外playbook和模板文件(template)还可使用jinja2语法语法实现高级功能。


  1、playbook的基本组成

      targets:指定要执行playbook的远程主机组

      variables:定义playbook运行时需要使用的变量

      tasks:要执行的任务

      handlers:处理器,在某些条件下被触发的操作


    一个简单的示例:

      vim httpd.yml

      - hosts: websrvs

       remote_user: root

       vars:

         remote_conffile_path: /etc/httpd/conf/httpd.conf

       tasks:

       - name: install httpd

        yum: name+httpd state=latest

        when: ansible_pkg_mgr == "yum"

       - name: configration file

        tags: conf

        copy: src=/root/httpd.conf dest={{ remote_conffile_path }}  

        notify: restart httpd

       - name: start httpd

        service: name=httpd enabled=yes state=started

       handlers:

       - name: restart httpd

        service: name=httpd state=restarted


  2、playbook各基础组件说明

    ⑴hosts和users

      hosts用于指定要执行指定任务的主机,其可以是一个或多个由逗号分隔主机组;remote_user则用于指定远程主机上的执行任务的用户。如上面示例中的

        - hosts: websrvs

         remote_user: root

      remote_user不仅可用于全局,也可用于各task中,还可指定其通过sudo的方式在远程主机上执行任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户。

        - hosts: websrvs

         remote_user: magedu

         tasks:

         - name: test connection

          ping:

          sudo: yes


    ⑵任务列表和action

       play的主体部分是task list。task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。如果中途发生错误,所有已执行任务都将回滚,因此,在更正playbook后重新执行一次即可。

       task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。

       每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出。

       定义task的可以使用“action: module options”或“module: options”的格式,推荐使用后者以实现向后兼容例如:

          tasks:

          - name: make sure apache is running

           service: name=httpd state=running

       在众多模块中,只有command和shell模块仅需要给定一个列表而无需使用“key=value”格式,例如:

          tasks:

          - name: disable selinux

           command: /sbin/setenforce 0

        如果命令或脚本的退出码不为零(默认情况下,退出码不为零即表示执行失败,任务会立即中止,后续任务不再执行),可以使用如下方式替代:

          tasks:

          - name: run this command and ignore the result

           shell: /usr/bin/somecommand || /bin/true(表示一定会成功)

          或者使用ignore_errors来忽略错误信息:

          tasks:

          - name: run this command and ignore the result

           shell: /usr/bin/somecommand

           ignore_errors: True


    ⑶handlers:用于当关注的资源发生变化时采取一定的操作。

       “notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。

          - name: template configuration file

           template: src=/root/template.j2 dest=/etc/foo.conf

           notify:

           - restart memcached

           - restart apache

       handler是task列表,这些task与前述的task并没有本质上的不同。

          handlers:

          - name: restart memcached

           service: name=memcached state=restarted

          - name: restart apache

           service: name=apache state=restarted

    ⑷变量

        变量名仅能由字母、数字和下划线组成,且只能以字母开头。

        在playbook中定义变量的格式:

          - host websrvs

           vars:

             variable:value

        如何调用变量:{{ variable }}

        在inventory中定义的变量,可在playbook中直接调用

        每个被控节点在接收并运行管理命令之前,会将本主机相关信息(称为facts,这些信息保存于变量中)如操作系统版本,ip地址,cpu数量等报告给ansible主机。这些变量信息通过 ansible <host-pattern> -m setup 获取,我们可在playbook中调用这些变量。

        当给一个主机应用角色的时候可以传递变量,然后在角色内使用这些变量,示例如下:

     - hosts: webservers

            roles:

            - common

            - { role: foo_app_instance, dir: ‘/web/htdocs/a.com‘, port: 8080 }

        另外,在运行playbook的时候也可以传递一些变量,示例:

           ansible-playbook test.yml --extra-vars "hosts=www user=magedu"


  4、条件测试

      如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提,这时就要用到条件测试。

      when语句:

        在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法。例如:

          tasks:

          - name: "shutdown Debian flavored systems"

           command: /sbin/shutdown -h now

           when: ansible_os_family == "Debian"

        when语句中还可以使用Jinja2的大多“filter”,例如要忽略此前某语句的错误并基于其结果(failed或者sucess)运行后面指定的语句,可使用类似如下形式:

          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

        此外,when语句中还可以使用facts或playbook中定义的变量。


  5、迭代

      当有需要重复性执行的任务时,可以使用迭代机制。其使用格式为将需要迭代的内容定义为item变量引用,并通过with_items语句来指明迭代的元素列表即可。例如:

        - name: add several users

         user: name={{ item }} state=present groups=wheel

         with_items:

         - testuser1

         - testuser2

      上面语句的功能等同于下面的语句:

        - name: add user testuser1

         user: name=testuser1 state=present groups=wheel

        - name: add user testuser2

         user: name=testuser2 state=present groups=wheel

      事实上,with_items中可以使用元素还可以是hashes,例如:

        - name: add several users

         user: name={{ item.name }} state=present groups={{ item.groups }}

         with_items:

         - { name: ‘testuser1‘, groups: ‘wheel‘ }

         - { name: ‘testuser2‘, groups: ‘root‘ }


  6、tags(标签)

      tags用于让用户选择运行playbook中的某个或某些任务。虽然ansible具有幂等性,会跳过没有变化的部分,但是,有些代码为测试其确实没有发生变化,也会耗费很长时间。我们将playbook中的指定任务打上标签,在运行playbook时指定标签名称,这样就不用运行全部代码了。

      playbook中可定义多个标签,且可重名。

      示例:

        - name: configration file

         copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf    

         notify: restart httpd

         tags: conf

      运行指定标签的任务:ansible-playbook httpd.yml -t conf

  7、运行playbook

      ansible-playbook <filename.yml> ... [options]

      例:ansible-playbook httpd.yml

  

  8、案例:使用ansible对websrvs组的两台主机做httpd的高可用

    以下node1为ansible节点,node2和node3为被控节点,已被添加至主机组websrvs。这里假设两个被控节点上已安装好httpd服务程序,且已建立双机互信。

[root@node1 ~]# vim /etc/ansible/hosts

[websrvs]
192.168.30.20
192.168.30.13
[dbsrvs]
192.168.30.14
[root@node1 ~]# ls hb_conf   #准备好需要的文件
authkeys  ha.cf  haresources
[root@node1 ~]# vim heartbeat.yml   #创建playbook

- hosts: websrvs
  remote_user: root
  tasks:
  - name: ensure heartbeat latest version
    yum: name=heartbeat state=present
  - name: authkeys
    copy: src=/root/hb_conf/authkeys dest=/etc/ha.d/ mode=600
    notify: restart heartbeat
  - name: ha.cf
    copy: src=/root/hb_conf/ha.cf dest=/etc/ha.d/
    notify: restart heartbeat
    tags: conf   #打标签
  - name: haresources
    copy: src=/root/hb_conf/haresources dest=/etc/ha.d/
    notify: restart heartbeat
  handlers:
  - name: restart heartbeat
    service: name=heartbeat state=restarted

[root@node1 ~]# ansible-playbook heartbeat.yml    #运行playbook

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [192.168.30.20]
ok: [192.168.30.13]

TASK [ensure heartbeat latest version] *****************************************
changed: [192.168.30.20]
changed: [192.168.30.13]

TASK [authkeys] ****************************************************************
changed: [192.168.30.13]
changed: [192.168.30.20]

TASK [ha.cf] *******************************************************************
changed: [192.168.30.13]
changed: [192.168.30.20]

TASK [haresources] *************************************************************
changed: [192.168.30.20]
changed: [192.168.30.13]

RUNNING HANDLER [restart heartbeat] ********************************************
changed: [192.168.30.13]
changed: [192.168.30.20]

PLAY RECAP *********************************************************************
192.168.30.13              : ok=6    changed=5    unreachable=0    failed=0   
192.168.30.20              : ok=6    changed=5    unreachable=0    failed=0
#验证
[root@node2 ~]# ls /etc/ha.d
authkeys  ha.cf  harc  haresources  rc.d  README.config  resource.d  shellfuncs
[root@node2 ~]# ll /etc/ha.d/authkeys 
-rw------- 1 root root 680 May  3 20:07 /etc/ha.d/authkeys
[root@node2 ~]# service heartbeat status
heartbeat OK [pid 7595 et al] is running on node2 [node2]...
[root@node2 ~]# ip addr show
...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:bd:68:23 brd ff:ff:ff:ff:ff:ff
    inet 192.168.30.20/24 brd 192.168.30.255 scope global eth0
    inet 192.168.30.100/24 brd 192.168.30.255 scope global secondary eth0
    inet6 fe80::20c:29ff:febd:6823/64 scope link 
       valid_lft forever preferred_lft forever
[root@node2 ~]# service httpd status
httpd (pid  8049) is running...
[root@node1 ~]# vim hb_conf/ha.cf   #修改主配置文件
...
mcast eth0 225.1.1.5 694 1 0   #更改心跳信息的组播地址
[root@node1 ~]# ansible-playbook heartbeat.yml -t conf   #只执行指定标签的任务

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [192.168.30.13]
ok: [192.168.30.20]

TASK [ha.cf] *******************************************************************
changed: [192.168.30.20]
changed: [192.168.30.13]

RUNNING HANDLER [restart heartbeat] ********************************************
changed: [192.168.30.20]
changed: [192.168.30.13]

PLAY RECAP *********************************************************************
192.168.30.13              : ok=3    changed=2    unreachable=0    failed=0   
192.168.30.20              : ok=3    changed=2    unreachable=0    failed=0
[root@node2 ~]# netstat -unl
...                         
udp        0      0 225.1.1.5:694               0.0.0.0:*


三、roles

   ansilbe自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。

   一个roles的目录结构示例:

     site.yml

     webservers.yml

     fooservers.yml

     roles/

        common/

         files/ 

         templates/

         tasks/ 

         handlers/

         vars/

         meta/

       webservers/

         files/

         templates/

         tasks/

         handlers/

         vars/

         meta/

   在playbook中,可以这样使用roles:

      - hosts: webservers

       roles:

       - common

       - webservers

   可以向roles传递参数,如:

      - hosts: webservers

       roles:

       - common

       - { role: some_role, dir: ‘/opt/a‘, port: 5000 }

       - { role: some_role, dir: ‘/opt/b‘, port: 5001 }

    也可以条件式地使用roles,例如:

      - hosts: webservers

       roles:

       - { role: some_role, when: "ansible_os_family == ‘RedHat‘" }


  1、创建role的步骤

     ①创建以roles命名的目录;

     ②在roles目录中分别创建以各角色名称命名的目录,如webservers、dbservers等;

     ③在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建;

     ④在playbook文件中,调用各角色;


  2、role内各目录中可用的文件

     tasks目录:至少应该包含一个名为main.yml的文件,其定义了此角色的任务列表;此文件可以使用include包含其它的位于此目录中的task文件;

     files目录:存放由copy或script等模块调用的静态文件;

     templates目录:template模块会自动在此目录中寻找Jinja2模板文件;

     handlers目录:此目录中应当包含一个main.yml文件,用于定义此角色用到的各handler;此文件可以使用include包含其它的位于此目录中的handler文件;

     vars目录:至少有一个main.yml文件,用于定义此角色用到的变量;

     meta目录:至少有一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;ansible 1.3及其以后的版本才支持;

     default目录:为当前角色设定默认变量时使用此目录;应当包含一个main.yml文件;


四、案例—使用ansible搭建LAMP环境,要求如下:

    ①两台web服务器,一台mysql数据库服务器,php作为httpd的模块

    ②在php服务器上部署独立博客站点wordpress

    ③要求两台web服务器使用不同的端口,设置不同的最大连接数


  1、设计方案

技术分享


  2、添加被控主机,并定义主机变量

     vim /etc/ansible/hosts

[root@node1 ~]# vim /etc/ansible/hosts

[websrvs]
192.168.30.20 http_port=80 http_maxclients=300
192.168.30.13 http_port=8080 http_maxclients=200

[dbsrvs]
192.168.30.14

  3、配置ssh基于密钥认证

[root@node1 ~]# ssh-keygen -t rsa
...
[root@node1 ~]# ssh-copy-id -i .ssh/id_rsa.pub root@192.168.30.14
...
[root@node1 ~]# ssh root@192.168.30.14 ‘hostname‘
node4
#以同样的方式将公钥文件复制到其它被控节点

  4、创建各级目录,准备好需要的各种文件和模板

[root@node1 ~]# mkdir -p roles/{web,php,mysql,wordpress}/{files,templates,tasks,handlers,vars}
[root@node1 ~]# ls roles
mysql  php  web
[root@node1 ~]# ls roles/web/
files  handlers  tasks  templates  vars
[root@node1 ~]# cp httpd.conf roles/web/templates/template.j2
[root@node1 ~]# vim roles/web/templates/template.j2
[root@node1 ~]# cp -r wordpress roles/wordpress/files/
[root@node1 ~]# cp wp-config-sample.php roles/wordpress/files/wp-config.php
[root@node1 ~]# vim roles/wordpress/files/wp-config.php 

<?php
/** 
 * WordPress 基础配置文件。
 *
 * 本文件包含以下配置选项:MySQL 设置、数据库表名前缀、密匙、
 * WordPress 语言设定以及 ABSPATH。如需更多信息,请访问
 * {@link http://codex.wordpress.org/zh-cn:%E7%BC%96%E8%BE%91_wp-config.php
 * 编辑 wp-config.php} Codex 页面。MySQL 设置具体信息请咨询您的空间提供商。
 *
 * 这个文件用在于安装程序自动生成 wp-config.php 配置文件,
 * 您可以手动复制这个文件,并重命名为“wp-config.php”,然后输入相关信息。
 *
 * @package WordPress
 */

// ** MySQL 设置 - 具体信息来自您正在使用的主机 ** //
/** WordPress 数据库的名称 */
define(‘DB_NAME‘, ‘wpdb‘);

/** MySQL 数据库用户名 */
define(‘DB_USER‘, ‘tuser‘);

/** MySQL 数据库密码 */
define(‘DB_PASSWORD‘, ‘tpass‘);

/** MySQL 主机 */
define(‘DB_HOST‘, ‘localhost‘);

/** 创建数据表时默认的文字编码 */
define(‘DB_CHARSET‘, ‘utf8‘);

[root@node1 ~]# cp my.cnf roles/mysql/files/


轻量级自动化运维工具ansible之二:playbook详解

标签:ansible   playbook   

原文地址:http://9124573.blog.51cto.com/9114573/1769887

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!