到目前为止,咱们只是简单的运行了几个模块.其实ansible运行更多控制去执行playbook.使用这些技术,你可以执行更加复杂的部署.python
ansible默认只会建立5个进程,因此一次任务只能同时控制5台机器执行.那若是你有大量的机器须要控制,或者你但愿减小进程数,那你能够采起异步执行.ansible的模块能够把task放进后台,而后轮询它.这使得在必定进程数下能让大量须要的机器同时运做起来.mysql
使用async和poll这两个关键字即可以并行运行一个任务. async这个关键字触发ansible并行运做任务,而async的值是ansible等待运行这个任务的最大超时值,而poll就是ansible检查这个任务是否完成的频率时间.linux
若是你但愿在整个集群里面平行的执行一下updatedb这个命令.使用下面的配置ios
- hosts: all tasks: - name: Install mlocate yum: name=mlocate state=installed - name: Run updatedb command: /usr/bin/updatedb async: 300 poll: 10
你会发现当你使用上面的例子控制超过5台机器的时候,command.在上面yum模块会先在5台机器上跑,完成后再继续下面的机器.而上面command模块的任务会一次性在全部机器上都执行了,而后监听它的回调结果web
若是你的command是控制机器开启一个进程放到后台,那就不须要检查这个任务是否完成了.你只须要继续其余的动做,最后再使用wait_for这个模块去检查以前的进程是否按预期中开启了即可.只须要把poll这个值设置为0,即可以按上面的要求配置ansible不等待job的完成.sql
最后,或者你还有一种需求是有一个task它是须要运行很长的时间,那你须要设置一直等待这个job完成.这个时候你把async的值设成0即可.shell
总结来讲,大概有如下的一些场景你是须要使用到ansible的polling特性的apache
固然也有一些场景是不适合使用polling特性的vim
在ansible你可以经过不一样的输入去重复的执行同一个模块,举个例子,你须要管理几个具备相同权限的文件.你可以用一个for循环迭代一个facts或者variables去减小你的重复劳动.安全
使用with_items这个关键字就能够完成迭代一个列表.列表里面的每一个变量都叫作item.有一些模块譬如yum,它就支持使用with_items去安装一列表的包,而不须要写好多个yum的task
下面来一个with_items的例子
tasks: - name: Secure config files file: path=/etc/{{ item }} mode=0600 owner=root group=root with_items: - my.cnf - shadow - fstab
除了使用items轮训,ansible还有一种方式是lookup插件.这些插件可让ansible从外部取得数据,例如,你或许但愿能够经过一种特定模式去上传你的文件.
在这个例子里面,咱们会上传全部的public keys到一个目录,而后聚合它们到一个authorized_keys文件
tasks: #1 - name: Make key directory #2 file: path=/root/.sshkeys ensure=directory mode=0700 owner=root group=root #3 - name: Upload public keys #4 copy: src={{ item }} dest=/root/.sshkeys mode=0600 owner=root group=root #5 with_fileglob: #6 - keys/*.pub #7 - name: Assemble keys into authorized_keys file #8 assemble: src=/root/.sshkeys dest=/root/.ssh/authorized_keys mode=0600 owner=root group=root #9
loop模块通常在下面的场景中使用
有一些模块,例如copy这个模块有一些机制能跳过本次模块的运行.其实咱们也可使用本身的条件语句去配置跳过模块,这样方便你服务可以选择使用不一样的包管理(apt,yum)和不一样的文件系统.而且你还可使用set_fact这个模块作成更多的差别配置
你可以使用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: Unexpected 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 unexpected conditions pause: prompt="Unexpected OS" when: ansible_os_family != "RedHat"
下面一些情景建议你使用条件语句作跳过动做
默认ansible的全部task是在咱们的配置的管理机器上面运行的,当在一个独立的群集里面配置,那是适用的.而有一些状况是,某些任务运行的状态是须要传递给其余机器的,在同一个任务你须要在其余机器上执行,这时候你就许多要用task委托
使用delegate_to关键字即可以配置任务在其余机器上执行.其余模块仍是在全部配置的管理机器上运行的,当到了这个关键字的任务就是使用委托的机器上运行.而facts仍是适用于当前的host,下面咱们演示一个例子,使用get_url模块去下载一个web集群的配置
--- - name: Fetch configuration 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: localhost
若是须要委托loaclhost执行任务,这里提供一个快捷的方式,只要使用local_action做为task的key便行.咱们尝试使用这种方式来配置上面的例子,会更加简洁.
--- #1 - name: Fetch configuration from all webservers #2 hosts: webservers #3 tasks: #4  - name: Get config local_action: get_url dest=configs/{{ ansible_hostname }}.cfg url=http://{{ ansible_hostname }}/diagnostic/config
委托不限于localhost,能够在你的inventory里面的任何host.下列一些场景适用使用委托
你们应该在以前的章节的例子里面有看到group_names这个变量.这个是ansible提供的一个很神奇变量.直至写本书的时候,有7个这样的变量,我会在下面的章节介绍
hostvars容许你在当前的任务中应用全部host的变量.当setup模块没有运行的时候,只有这些变量将是可用.例如你配置 ${hostvars.hostname.fact}能够访问其余复杂的变量.例如你能够配置${hostvars.ns1.ansible_ distribution}获得ns1这个server的linux发型版本.
下面的例子设置了一个dns_master变量,这是ns1 server的ip.而后这个变量可以在全部机器上调用
--- - name: Setup DNS Servers hosts: allnameservers tasks: - name: Install BIND yum: name=named state=installed - name: Setup Slaves #7 hosts: slavenamesservers #8 tasks: #9 - name: Get the masters IP set_fact: dns_master="{{ hostvars.ns1.ansible_default_ipv4.address }}" - name: Configure BIND template: dest=/etc/named.conf src/templates/named.conf.j2
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使用
下面的例子配置建立known_hosts文件
playbook配置
--- hosts: all tasks: - name: Setup known hosts hosts: all tasks: - name: Create known_hosts template: src=templates/known_hosts.j2 dest=/etc/ssh/ssh_known_hosts owner=root group=root mode=0644
template模板
{% for host in groups['all'] %} {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_ssh_host_key_rsa_public'] }} {% endfor %}
group_names是当前host所属的组的列表.这能够用于在条件语句中调用成员的group关系,或者用于debugging.一般来讲这变量大部分用于跳过一些task或者在模板中用于条件语句的变量.在下面的例子中,若是你有两套sshd的配置文件,一套用于安全性更加严谨的,一个安全性普通的.而后咱们根据group名来配分host到哪一个sshd配置下.
--- - name: Setup SSH hosts: sshservers tasks: - name: For secure machines set_fact: sshconfig=files/ssh/sshd_config_secure when: "'secure' in group_names" - name: For non-secure machines set_fact: sshconfig=files/ssh/sshd_config_default when: "'secure' not in group_names" - name: Copy over the config copy: src={{ sshconfig }} dest=/tmp/sshd_config
inventory_hostname是机器的hostname,当你没有使用setup模块,或者因为各类缘由致使setup的变量是错误的,你能够选择使用这个变量.此变量能够帮助你初始化你的机器和改变hostname
inventory_hostname_short相似与上面的inventory_hostname变量,只是它是截取第一个句点的前面的字符,例如hostname是host.example.com,就会只截取到host
此变量是inventory文件的路径,包括目录与文件名
相似上面的变量,只是它只有文件名
全部的模块均可以把变量做为参数的一部分,经过使用”{{}}”符号扩起来.譬如变量test就是”{{ test }}”.这样你就能够经过变量加载特定的文件.例如,你但愿根据不一样的机器architecture选择不一样的NRPE(nagios的客户端)配置文件,那能够像这样的配置
--- - name: Configure NRPE for the right architecture hosts: ansibletest user: root tasks: - name: Copy in the correct NRPE config file copy: src=files/nrpe.{{ ansible_architecture }}.conf dest=/etc/nagios/nrpe.cfg
在copy和tempalate模块里面,你可以使用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 src={{ item }} first_available_file: - files/apache/{{ ansible_os_family }}-{{ ansible_architecture }}.cfg - files/apache/default-{{ ansible_architecture }}.cfg - files/apache/default.cfg
unix命令常常须要依赖环境变量,例如C makefiles,installers,和aws cli工具.很幸运,ansible很容易实现,譬如你如今须要控制远程的机器一个文件到s3,那你许多要配置aws的access key.下面咱们的例子演示,安装pip,用pip安装aws cli,而且经过cli上传文件到s3
--- - name: Upload a remote file via S3 hosts: ansibletest user: root tasks: - name: Setup EPEL command: rpm -ivh http://download.fedoraproject.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 --bucket=my-test-bucket --key={{ ansible_hostname }}/fstab --body=/etc/fstab --region=eu-west-1 environment: AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXX AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXX
一些模块例如get_url,yum,和apt是须要使用环境变量配置proxy的.下面一些场景也是须要配置环境变量的
ansible在0.9版本开始引进了lookup插件,这些插件运行ansible在外围获取数据.ansible已经提供了几个插件,但它仍是支持本身编写插件.这真的让你使用ansible配置更加伸缩自如
lookup是在master机器运行的python程序.下面一个例子是使用lookup插件获取环境变量里面的http_proxy,而后配置在远端机器,确保远端机器使用相同的proxy下载文件
--- #1 - name: Downloads a file using the same proxy as the controlling machine hosts: all tasks: - name: Download file get_url: dest=/var/tmp/file.tar.gz url=http://server/file.tar.gz environment: http_proxy: "{{ lookup('env', 'http_proxy') }}"
使用with_*可以使用lookup插件迭代出特别的东西.您可使用任何这样的插件,但最好是返回一个列表.下面的例子让你自动注册webapp,使用下面的例子会建立出虚拟机并配置它
--- - name: Registers the app server farm hosts: localhost connection: local vars: hostcount: 5 tasks: - name: Register the webapp farm local_action: add_host name={{ item }} groupname=webapp with_sequence: start=1 end={{ hostcount }} format=webapp%02x
在下面的场景,lookup很是有用
几乎全部的模块都是会outputs一些东西,甚至debug模块也会.大多数咱们会使用的结果变量是changed.这个changed变量决定了是否要直接handlers和输出的颜色是什么.然而,结果变量还有其余的用途,譬如我须要保存个人结果变量,而后咋个人playbook的其余地方给使用.在下面的例子咱们建立了一个/tmp目录,而后在后面咱们建立一个/tmp/subtmp使用和前面目录同样的权限
--- - 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对于数多场景是颇有用的
有好几种方法去debug咱们的playbook.ansible有verbose模式和debug模式,也可使用例如fetch和get_url模块来协助debug.当你想学习怎样使用一些模块时,这些debugging技术可以帮助你.
debug模块使用很简单.它具备两个参数,msg和fail.msg就是打印出来的信息,而当fail参数设置为yes时,会发送失败通知给ansible,而后ansible会中止运行任务.
在下面的例子,配置了使用debug模块去显示远端机器全部的network interface.
--- - name: Demonstrate the debug module hosts: ansibletest user: root vars: hostcount: 5 tasks: - name: Print interface debug: msg="{{ item }}" with_items: ansible_interfaces
运行上面的配置会出现这样的输出
PLAY [Demonstrate the debug module] ********************************* GATHERING FACTS ***************************************************** ok: [ansibletest] TASK: [Print IP address] ******************************************** ok: [ansibletest] => (item=lo) => {"item": "lo", "msg": "lo"} ok: [ansibletest] => (item=eth0) => {"item": "eth0", "msg": "eth0"} PLAY RECAP ********************************************************** ansibletest : ok=2 changed=0 unreachable=0 failed=0
如你说见,debug模块可让你很容易看到在playbook运行期间一些变量
另外的debug选择是verbose模式.当运行verbose模式时,会打印出全部模块运行后的变量.这对于你要使用register功能时候很重要.只须要在执行playbook命令时加上参数–verbose即可以.ansible-playbook –verbose playbook.yml
除了verbose模式外,ansible还提供了check模式和diff模式.只须要执行playbook时添加参数–check和–diff.check模式运行时,ansible不会真正控制远程机器发生变动.这可以让你得到此次playbook任务中,将会发生changed事件的列表.
很重要的一点是check模式不是完美的.有一些模块是会跳过check模式的.尤为明显的限制是在运行command和shell模块
在diff模式下,当文件发现更变,会打印出变动文件的变动部分.配合check模式使用效果更好
另一个debug技巧是使用pause模块,它可让你须要在某个地方须要检查远程机器的配置的时候暂停playbook的执行.这样可让先观察一下运行到这里为止的效果,再判断是否继续运行下去.
在这个章节咱们更加深刻探索了编写playbook的一些细节.如今你应该可使用一些ansible的特性.例如delegation,looping,conditionals,和fact,registration等等,让你可以更容易的编写和维护你的playbook.咱们也看到了如何获取其余host的信息,如何配置环境变量,如何从外围获取到数据.最后咱们展现了一些debug技巧,让playbook能按你的预期来执行.