自动化运维之ansible——playbook进阶

一、并发运行

ansible默认只会创建5个进程,所以一次任务只能同时控制5台机器执行。那如果在使用ansible的过程中有大量的机器需要控制,或者在使用中想减少进程数,以上情况下,可以采取异步执行。ansible的门票快可以把task放入后台,然后轮循它,这使得在一定进程数下能让大量需要的机器同时运作起来。

使用async和poll这两个关键字便可以并行运行一个任务。async这个关键字触发ansible并行运作任务,而async的值是ansible等待运行这个任务的最大超时时间,而poll就是ansible检查这个任务是否完成的频率时间。

如果我们希望在整个集群里面平行的执行一下updatedb这个命令。使用下面的配置

- hosts: all
     tasks:
       - name: install mlocate
         yum: name=mlocate state=installed

       - name: run updatedb
         command: /usr/bin/updatedb
         async: 300
         poll: 10

在以上的例子中,如果all包括5台以上的机器。install mlocate这个任务会先在5台机器上跑,完成之后再继续下面的机器。而run updatedb任务会一次性在所有机器上都执行,然后监听这个任务的回调结果。

如果某一个任务的command是控制机器开启一个进程放到后台,那就可以不用检查这个任务是否完成了,我们只需要继续其他的动作,最后使用wait_for这个模块去检查之前的进程是否按预期中开启了便可。只需要将poll的值设置为0,便可以按照上面的要求配置。ansible不等待job的完成。

最后,还有一种需求是有一个task,他需要运行很长的时间(例如,需要将远程主机重启),那我们需要设置一直等待这个job完成,这个时候就需要将async的值设置为0便可以。

 总结:

(1)适合使用polling特性的场景

  • 一个task需要运行很长时间,这个task可能需要会达到tomeout。
  • 有一个任务task需要在大量远程主机上运行
  • 有一个任务task不需要等待它执行完成

(2)不适合使用polling特性的场景

  • 有一个任务task是需要运行完后才能继续完成其他任务
  • 有一个任务可以很快完成。

二、Looping

     在ansible中可以通过不同的输入去重复的执行同一个模块。例子:我们需要管理几个相同权限的文件,我们可以使用for循环迭代一个facts或者variables去减少重复操作。

(1)with_items

     使用with_items这个关键字就可以完成迭代一个列表。列表中的每个变量都叫做item。例如:

tasks:
  - name: secure config files
    file: path=/etc/{{ item }} mode=0600 owner=root group=root
    with_items:
       - my.cnf
       - fstab
       - shadow

    以上例子中,可以修改几个相同权限,用户和组的文件

例子二:

tasks:
  - name: yum 
    yum : name={{ item }} state=installed
    with_items:
      - tree
      - net-tools
      - vim
      - lsof

以上例子中,可以私用with_items安装一系列的包,而不用些好多个yum。

 (2)lookup插件

   lookup插件,这些插件可以让ansible从外部获取数据。

   一个例子:我们希望通过一种特定模式上传文件。即上传所有的public keys到一个目录,然后聚合他们到authroized_keys文件

tasks:
   - name: make key directory
     file: path=/root/.sshkeys ensure=directory mode=0700 owner=root group=root
   - name: upload public keys
     copy: src={{ item }} dest=/root/.sshkeys mode=0600 owner=root group=root

     with_filelob:
       - keys/*.pub
   - name: Assemble keys into authorized_keys file
     assemble: src=/root/.sshkeys dest=/root/.ssh/authorized_keys mode=0600 owner=root group=root

 loop模块的使用场景:

  • 类似的配置模块重复了很多遍
  • fact是一个列表
  • 创建多个文件,然后使用assemble聚合成一个大文件。
  • 使用with_filelog匹配特定的文件管路。

三、条件语句

     在一些模块中有一些机制可以跳过本次模块的运行。但某些时候,我们并不能使用拥有跳过机制的模块,所以我们需要使用条件语句去配置跳过模块,这样情况下我们就可以选择使用不同的包管理和不同的文件系统,并且我们还可以使用set_facts这个模块做成更多的差异配置。

     我们可以使用when这个关键字去达到跳过本次模块运行的效果,when关键字后面可以跟/接python的表达式。在表达式中能够使用任何的变量或者fact。当表达式的结果返回的是false,便会跳过本次的模块。

     一个例子:如何在不同的系统中判断debian还是redhat系统并根据以上判断使用apt还是yum,如果不是这两种情况,使用debug模块把系统打印出来。

---
 - name: install vim
   hosts: all
   tasks:
    - name: install vim via yum
      yum: name=vim-enhanced state=installed
      when: ansible_os_family == "RedHat"
    - name: install vim via apt
      apt: name=vim state=installed
      when: ansible_os_family == "Debian"
    - name: unexcepted os family
      debug: msg="os family {{ ansible_os_family }} is not supported" fail=yes
      when: not ansible_os_family == "RedHat" or ansible_os_family == "Debian"

执行结果:

  条件语句还有一种用法,它可以当达到一定条件的时候暂停下来,等待我们的输入确认。一般情况下,当ansible遭遇error时,它就会自动结束运行。其实我们可以当遭遇的不是预期的情况的时候给使用pause模块,这样可以让用户决定是否继续运行任务。

name: pause for unexcepted conditions
pause: prompt="unexpected os"
when: ansible_os_family != "Redhat"

 可以使用条件语句做跳过动作的场景:

  • job里面有不同操作系统的机器
  • 提示用户,然后再执行操作请求
  • 提高性能,避免运行一个需要执行一点时间模块,而且我们直到这个模块不会返回changed

四、tasks委托

    默认ansible的所有tasks是在我们的配置的管理机器上面运行。当在一个独立的集群里配置,以上情况是适用的。然而有一些情况下,某些任务运行的状态是需要传递给其他机器的,在同一任务需要再其他机器上执行的,以上情况下,就可以使用tasks委托。

   使用delegate_to关键字便可以配置任务在其他机器上执行。其他模块还是在所有配置的管理机器上运行的,当到了这个关键字的任务就是使用委托的机器上运行。而facts还是适用于当前的host。

   一个例子(使用get_url模块去下载一个web集群的配置):

---
 - name: fetch confgiuraction from all webservers
   hosts: webservers
   tasks:
     - name: get config
       get_url: dest=configs/{{ ansible_hostname }} force=yes url=http://{{ ansible_hostname }}/diagnostic/config
       delegate_to: loaclhost



如上例子委托localhost执行任务,我们可以使用一种更便捷的方式来实现。
---
 - name: fetch confgiuraction from all webservers
   hosts: webservers
   tasks:
     - name: get config
       local_action: get_url dest=configs/{{ ansible_hostname }} url=http://{{ ansible_hostname }}/diagnostic/config
       delegate_to: loaclhost

委托不限于localhost,可以是hosts里面的任何一个host。

委托的适用场景:

  • 部署之前希望从负载均衡里面把host移除。
  • 更改server时更改dns指向。
  • 创建一个ISCSI卷存储。
  • 使用一个外部服务器去检测服务。

五、其他变量

(1)hostvars变量

        hostvars允许我们在当前任务中应用所有host的变量。当setup模块没有运行的时候,只有这些变量将是可用的。

${hostvars.hostname.fact}可以访问其他复杂的变量、                                                              ${hostvars.ns1,ansible_distribution}可以得到ns1这个server的LINUX发行版本。

如下示例,设置一个dns_master变量,这是ns1的server的ip。这个变量可以在所有机器上调用。

---
  - name: setup slaves
    hosts: slavename
    tasks:
     - name: get the master
       set_fact: dns_master= "{{ hostvars.ns1.ansible_default_ipv4.address }}"
     - name: configure BIND
       template: dest=/etc/named.conf src/templates/named.conf.j2

(2)groups变量

groups变量是inventory里面的group分组列表。这个工具能够让我们迭代的配置所有的hosts。例子:

---
 - name: configure the database
   hosts: dbservers
   user: root
   tasks:
     - name: install mysql
       yum: name={{ item }} state=installed
       with_items:
          - mysql-server
          - MYSQL-python
     - name: start mysql
       service: name=mysqld state=started enabled=true
     - name: create a user for all app servers
       with_items: groups.appservers
       mysql_user: name=kate password=test host={{ hostvars[item].ansible_eth0.ipv4.address }} state=present

     groups变量实际上不是hosts变量的列表,它只是hosts的name列表,如果我们需要调用host里面的变量还需要配合hostvars使用。

(3)group_names变量

     group_names是当前host所属的组的列表。这可以用于在条件语句中调用成员的group关系,或者用于debugging。通常这个变量用于跳过一些task或者在模板中用于条件语句的变量。

   例子(我们拥有两套sshd配置文件,一套用于安全性更加严谨的,一个安全性普通的,然后根据group_name来分配host到那个sshd下):

---
 - name: setup sshd
   hosts: sshservers
   tasks:
      - name: for secure machines
        set_fact: sshconfig=files/ssh/sshd_config_secure
        when: "'secure' in group_name"
      - name: for non-secure machines
        set_fact: sshconfig=files/ssh/sshd_config_default
        when: "'secure' not in group_name"
      - name: copy over the config
        copy: src={{ sshconfig }} dest=/tmp/sshd_config

(4)inventory_hostname变量

inventory_hostname是机器的hostname。此变量可以帮助初始化机器和改变hostname。

(5)inventory_hostname_short变量

此变量类似与inventory_hostname变量,只是它截取第一个句点的前面的字符,例如:hostname是host.example.com就会截取到host。

(6)inventory_dir变量

此变量是inventory文件的路径,包括目录名与文件名。

(7)inventory_file变量

类似inventory_dir变量,但此变量只包含文件名。

(8)使用变量来查找文件

     所有的模块可以把变量作为参数的一部分。通过使用“{{ }}”来使用变量。例如,test变量就是“{{ test }}”,这样就可以通过变量加载特定的文件。

     例:我们通过不同的机器architecture选择不同的NRPE配置文件。

---
  - name: configure nrpe for the right architecture
    hosts: all
    user: root
    tasks:
      - name: copy in the correct nrpe config file
        copy: src=files/nrpe.{{ ansible_architecture }}.conf dest=/etc/nagios/nrpe.conf

   在copy和template模块里面。我们可以使用ansible去查找一组文件,然后默认使用第一个文件,这可以做到,当第一个文件不存在时,会查找第二个文件,如此类推知道最后一个文件还不存在就报fail。使用first_available_file这个关键字。

---
 - name: install an apache config file
   hosts: ansibletest
   user: root
   tasks:
      - name: get the best match for the machine
        copy: dest=/etc/apache.conf dest={{ item }}
        first_available_file:
          - files/apache/{{ absible_os_family }}-{{ ansible_architecture }}.cfg
          - files/apache/default-{{ ansible_architecture }}.cfg
          - files/apache/default.cfg
          

(9)环境变量

有一些命令经常需要依赖环境变量,但在ansible中很容易实现。例(现在需要远程控制一个机器文件到对象存储服务器[以aws的s3为例],那么就需要配置一些密钥之类的东西):

---
 - name: upload a remote five via s3
   hosts: ansibletest
   user: root
   tasks:
     - name: setup epel
       command: rpm -ivh http://download.fedoraprohect.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm creates=/etc/yum.repos.d/epel.repo
     - name: install pip
       yum: name=python-pip state=installed
     - name: install the aws tools
       pip: name=awscli state=present
     - name: upload the file
       shell:aws s3 put-object --buvket=my-test-bucket --key={{ ansible_hostname }}/fstab --body=/etc/fstab --region=eu-wext-1
   environment:
      AWS_ACCESS_KEY_ID:********************
      AWS_SECRET_ACCESS_KEY:*****************

需要配置环境变量的场景:

  • 运行application installers
  • 当运行shell的时候需要添加一些额外的变量在path中
  • 需要load的一些库不在系统的libary路径中
  • 在运行模块时使用LD_PRELOAD hack

六、register

 几乎所有的模块都是会outputs一些东西,甚至debug模块也会。大多数我们会使用的结果变量是changed。这个changed变量决定了是否要直接handlers和输出的颜色是什么。然而,结果变量还有一些其他的用处,例如,我需要将一个结果变量保存起来,在我的playbook的其他地方进行使用。例:

---
 - name: using register
   hosts: ansibletest
   user: root
   tasks:
      - name: get /tmp info
        file: dest=/tmp state=directory
        register: tmp
      - name: set mode on /var/tmp
        file: dest=/tmp/subtmp mode={{ tmp.mode }} state=directory

以上例子中,我们新建了一个目录,在下面的一个任务中,使用与上面的目录相同的权限。

    一些模块,类似于file模块,是能够获取到一些简单的信息。结合register这个功能,可以在playbook里面检查环境和计算。

可以使用register的场景:

  • 在一台远端的都武器获取一个目录下的一列表的文件,然后下载这些文件。
  • 在handlers执行之前,发现前面一个task发生了changed,然后执行一个指定的task
  • 获取远端服务器的ssh key的内容,构建出known_hosts文件。

七、解决管理节点过多导致的超时问题

   默认情况下,ansible将尝试管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键字定义ansible一次应管理多少主机,还可以将它定义为百分比,表示每次并行执行的主机数占总数的比例。

---
 - host: all
   name: example
   serial: 2 #每次只同时处理2个主机
   user: root
   tasks:
    - name: task one
      command: hostname



---
 - host: all
   name: example
   serial: "20%" #每次只同时处理20%主机
   user: root
   tasks:
    - name: task one
      command: hostname

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值