ansible playbooks

10.ansible playbooks
10.1简介
(1)playbook是由一个或多个“play”组成的列表
(2)play的主要功能在于将事先归并为一组的主机装扮成事先通过anaible中task定义好的角色。从根本上来将,所谓task无非是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联通起来按事先编排的机制同唱一台大戏。
10.2组成结构
Inventory
Modules
Ad hoc commands
Playbooks
Tasks:任务,即调用模块完成的某操作
Variables:变量
Templates:模板
Handlers:处理器,由某时间触发执行的操作
10.3 playbook
基础组件包括:Tasks、Variables、Templates、Handlers、Roles
10.3.1hosts和users
(1)playbook中每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。
(2)Hosts用于指定要执行指定任务的主机,其可以是一个或多个由冒号分割主机组:
(3)remote_user则用于指定远程主机上的执行任务的用户。如上面实例中的
-hosts:webnodes
remote_user:root
不过,remote_user也可用于各task中,也可以通过指定其通过sudo的方式在远程主机上执行任务,其可以用于play全局或某任务:此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户

  • hosts:webnodes //定义一个主机组
    remote_user:zhang //定义登录时的用户身份
    tasks: //定义任务,可以有多个
  • name: test connection //任务名称
    gather_facts: false 这个参数指定了在以下任务执行前,是否先执行setup模块获取主机相关信息,这在后面的task会使用到task获取的信息,如果不需要,则选项为false,默认开启
    ping: //动作
    remote_user:zhang //在这可以使用自己定义的,相当于局部变量
    sudo:yes //是否sudo到root用户
    10.3.2任务列表和action
    (1)Play的主体部分是task list
    (2)Task list 中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个
    (3)在运行自下而上某playbook时,如果中途发生错误,所有已执行任务都可能回滚,因此,在更正playbook后重新执行一次即可
    (4)Task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果一致
    (5)每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰的秒数任务执行步骤,如果未提供name,则action的结果将用于输出
    (6)定义task的可以使用“action:module options”或“module:option”的格式,推荐使用后者以实现向后兼容,前边的只是在较新的版本中才可以使用。如果action一行的内容过多,可以在行首使用几个空白字符进行替换
    tasks:
    -name:make sure apache is runing
    service :name-httpd state=running //在运行这个模块时使用后面的参数
    (7)在众多模块中,只有command和shell模块仅需要给定一个列表而无需使用“key-value”格式,例如
    tasks:
    -name:disbles selinux
    command: /sbin/setenforce 0
    (8)如果命令或脚本的退出码不为0,可以使用如下方式替代:
    tasks:
    • name: run this command and ignore the result
      shell: /usr/bin/somecommand || /bin/true //强行成功
      (9)使用ignore_errors来忽略错误信息
      tasks:
      -name: run this command and ingore the result
      shell: /usr/bin/somecommand
      ignore errors:True //忽略失败,不影响后续执行
      10.3.3例一
      安装apache服务,并确保服务正常启动
  • hosts: webnodes //只对webnodes组里边的服务器生效,webnodes在inventory中定义
    vars: //在这组主机上定义了一组变量,vars,是一个键值对,值是个字典
    http_port:80
    max_clients:256
    remote_user:root //连接到远程主机时以哪个用户登录
    tasks: //用来定义接下来执行的任务有哪些
    • name:ensure apache is at the lastest version //第一个任务
      yum:name=httpd state=latest //基于yum模块来安装程序包
    • name:ensure apache is runing //第二个任务
      service:name=httpd state=started //基于service模块来启动服务
      handlers: //处理器
    • name:restart apache
      service:name=httpd state=restarted
      10.3.4例二
      创建nginx组和用户,复制本地文件到远端服务器
  • hosts: zhang
    remote_user: root
    tasks:
    • name: create nginx group
      group: name=nginx system=yes gid=208
    • name: create nginx user
      user: name=nginx uid=208 group=nginx system=yes
  • hosts: wang
    remote_user: root
    tasks:
    • name: copy file to wang
      copy: src=/etc/passwd dest=/tmp/wang.txt
      ansible playbooks
      执行后结果如下图,changed表示已经在远程主机上已经做了修改,后边有个PLAY RECAP是报告任务的执行情况
      ansible playbooks

10.3.5例三
安装httpd服务,使用本地配置文件,启动服务

  • hosts: zhang
    remote_user: root
    tasks:
    • name: install httpd package
      yum: name=httpd state=latest
    • name: install configuration file for httpd
      copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
    • name: start httpd service
      service: enabled=true name=httpd state=started
      ansible playbooks
      ansible playbooks

10.3.6例四
使用两个花括号来表示引用变量值

  • hosts: zhang
    remote_user: root
    vars:
    • package: httpd
    • service: httpd
      tasks:
    • name: install httpd package
      yum: name={{ package }} state=latest
    • name: install configuration file for httpd
      copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: restart httpd
    • name: start {{ service }} service
      service: enabled=true name=httpd state=started
      handlers:
    • name: restart httpd
      service: name=httpd state=restarted
      ansible playbooks
      10.3.7 handlers
      (1)用于当关注的资源发生变化时采取一定的操作
      (2)举例说明,比如上面的实例二,当重新修改httpd.conf的时候,需要重启下服务,但是ansible并没有这么做,所以需要使用handlers这个action
      (3)“notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性的执行指定操作,(4)在notify中列出的操作称为handler,也即notify中调用handler中定义的操作,当有改变的时候notify通知handler执行下边的操作。
      如果配置文件改变,将重启apache和memcache
  • 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
      (5)headles跟tasks是同级,需要定义,一般不会执行,只有当触发了某一条件的时候才会执行。比如可以将上述例二修改为如下,这样就可以确保,当配置文件发生改变的时候,服务也会重启,配置文件将重读一次。
      可以监控另外一个task,只有当这个task改变的时候才会触发notify执行
  • hosts: zhang
    remote_user: root
    tasks:
    • name: install httpd package
      yum: name=httpd state=latest
    • name: install configuration file for httpd
      copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: restart httpd
    • name: start httpd service
      service: enabled=true name=httpd state=started
      handlers:
    • name: restart httpd
      service: name=httpd state=restarted
      ansible playbooks
      ansible playbooks

(6)hendlers还可以监听某一个handers A,当A触发的时候,会触发这个handlers,这样多个handler监听A的时候,当触发了A,那么监听A的handlers都会被触发
handlers:

  • name: restart memcached
    service:
    name: memcached
    state: restarted
    listen: "restart web services"
  • name: restart apache
    service:
    name: apache
    state:restarted
    listen: "restart web services"

tasks:

  • name: restart everything
    command: echo "this task will restart the web services"
    notify: "restart web services"
    10.3.8条件测试
    (1)when用于条件判断,只有满足条件的主机才会执行这个任务,这个信息可以在setup收集回来的信息上取值
    (2)例如:
    • hosts: all
      remote_user: root
      vars:
    • username: user10
      tasks:
    • name: create {{ username }} user
      user: name={{ username }}
      when: ansible_fqdn == "glusterfs.tarena.com"
      ansible playbooks
      如下,不满足条件的就被跳过了
      ansible playbooks
      10.3.9 迭代
      (1)简介:当有需要重复执行的任务时,可以使用迭代机制,其使用格式为将需要迭代的内容定义为item变量引用,并通过with_items语句来指明迭代的元素
      (2)item_items中可以使用元素还可为hashes
      (3)item是固定的变量名,会循环with_items列表中的每一个值来替代,相当于遍历式的迭代循环
      (4)with_items中的列表还也可以是字典,但是引用时需要使用item.key
      (5)ansible的循环机制还有更多的高级功能,具体可以参见官方文档http://docs.ansible.com/playbooks_loops.html
      例1:增加多个用户
    • name: add serveral users
      user: name={{ item }} state=present groups=wheel
      with_items:
      • testuser1
      • testuser2
        例2:增加多个用户并且指定组
    • name: add serveral users
      user: name={{ item }} state=present groups={{ item.groups }}
      with_items:
  • { name: 'testuser1',groups: 'wheel'}
  • { name: 'testuser2',groups: 'root'}
    10.3.10算数和比较运算符
    (1)允许使用计算值,很少用到,但是为了完成性,允许其存在
    (2)支持 + - * / //(取整) % **(幂)
    (3)支持比较运算符 != == > >= < <=
    (4)可以使用变量
    (5)所有运算都必须在{{}}中
    10.3.11 Tags
    (1)Tags用于有选则的运行playbook中的代码,可以选择只运行有标签的代码,即调用playbook中的某一个任务
    (2)Ansible具有幂等性,因此会自动跳过没有变化的部分,即使如此,有些代码为测试其没有发生变化的时间依然会非常长。此时,如果确信其没有变化,就可以使用tags跳过这些代码片段
    (3)always_tags,这个选项的意思是无论如何被这个标记的任务都会执行
    Tags: t3,always
    (4)可以在play级别写,也可以在tasks级别写,写到play级别下边的tasks自动继承play的tags名称
    (5)一个name可以有多个tag,如下
    Tags: ts,http
    (6)ansible playbooks

例:

  • name: install httpd package
    yum: name={{ package }} state=latest
    tags:
    • conf
      10.3.12 roles
      10.3.12.1简介
      (1)Ansible自1.2版本引入的新特性,用于层次性、结构化的组织playbook
      (2)roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include命令即可。简单来讲,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷的include它们的一种机制。
      (3)角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
      10.3.12.2案例
      一个roles的案例如下:
      roles/
      common/
      files/ //分别将一些需要的东西放到对应的目录中
      templates/
      tasks/
      handlers/
      vars/
      meta/
      webservers/
      files/
      templates/
      tasks/
      handlers/
      vars/
      meta/
      而在playbook中,可以这样使用roles,直接调用roles里边的参数
    • hosts: webservers
      roles:
    • common
    • webservers
      也可以向roles传递参数,例如
    • hosts: webservers
      roles:
  • common
  • { role: foo_app_instance, dir: '/opt/a', port:5000 }
  • { role: foo_app_instance, dir: '/opt/b', port:5001 }
    甚至也可以条件式的使用roles,例如:
    • hosts: webservers
      roles:
      • { role: som_role, when: "ansible_os_family == 'Redhat'" }
        10.3.12.3创建role的步骤
        (1)构建以role命名的目录
        (2)在roles目录中分别创建以各角色名称命名的目录,如webservers等
        (3)在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和var目录;用不到的目录可以创建为空目录,也可以不创建
        (4)在playbook文件中,请用各角色
        10.3.12.4role内各目录中可用的文件
        Tasks目录:至少应该包含一个名为main.yml的文件,其定义的此角色的任务列表:此文件可以使用include包含其它的位于此目录中的task文件
        Files目录:存放由copy或scripts等模块调用的文件
        Template目录:template模块会自动在此目录中寻找jinja2模板文件
        Handlers目录:此目录中应当包含一个main
        Yml文件:用于定义此角色用到的各handlers;在handlers中使用include包含的其它handler文件也应该位于此目录中
        Vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量
        Meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;ansible1.3及其以后的版本才支持
        Default目录:为当前角色设定默认变量时才使用此目录,应当包含一个main.yml文件
        10.3.13 lookups
        Lookup插件可以用来从外部数据读取信息,然后赋给一个变量。获取外部数据信息的种类包括:读取文件内容、随机生成password、执行shell命令、读取redis的键值等等。注意,lookup所有的运算都是在ansible中控机上完成的,而不是远程目标机
        10.3.13.1 第一个参数为file
        第一个参数为file,表示获取外部文件内容
    • name: test
      hosts: self
      vars:
      contents: "{{ lookup('file', '/etc/foo.txt') }}"
      tasks:
    • debug: msg="the value of foo.txt is {{ contents }}"
    • debug: msg="the value of foo.txt is {{ lookup('file','/etc/foo.txt') }}"
      ansible playbooks
      10.3.13.2第一个参数为password
      第一个参数为password,表示生成一个随机明文密码,并存储到指定文件中,生成的密码包括大小写字母、数字和.,:-_,长度为20个字符,该长度可以通过传递一个额外参数length=<length>修改

除了length外,还可以使用chars=<chars>参数,用于自定义生成密码的字符集
chars=’ ascii_letters,digits,hexdigits,punctuation,,’ ,号本身用,号

  • hosts: self
    gather_facts: false
    tasks:
  • debug: msg="password - {{ lookup('password', '/tmp/random_pass.txt length=10')}}"
    ansible playbooks
    10.3.13.3其它类型
  • hosts: all
    tasks:

    • debug: msg="{{ lookup('env','HOME') }} is an environment variable"

    • debug: msg="{{ lookup('pipe','date') }} is the raw result of running this command"

    • debug: msg="{{ lookup('redis_kv', 'redis://localhost:6379,somekey') }} is value in Redis for somekey"

    • debug: msg="{{ lookup('dnstxt', 'example.com') }} is a DNS TXT record for example.com"

    • debug: msg="{{ lookup('template', './some_template.j2') }} is a value from evaluation of this template"
      10.3.14循环
      ansible playbooks

猜你喜欢

转载自blog.51cto.com/zhangdl/2349414