由于第三章内容较长,我将分做几个部分来翻译。
Advanced Playbooks So far the playbooks that we have looked at are simple and just run a number of modules in order. Ansible allows much more control over the execution of your playbook. Using the following techniques, you should be able to perform even the most complex deployments. Running operations in parallel By default, Ansible will only fork up to five times, so it will only run an operation on five different machines at once. If you have a large number of machines, or you have lowered this maximum fork value, then you may want to launch things asynchronously. Ansible's method for doing this is to launch the task and then poll for it to complete. This allows Ansible to start the job across all the required machines while still using the maximum forks. To run an operation in parallel, use the async and poll keywords. The async keyword triggers Ansible to run the job in parallel, and its value will be the maximum time that Ansible will wait for the command to complete. The value of poll indicates to Ansible how often to poll to check if the command has been completed. If you wanted to run updatedb across an entire cluster of machines, it might look like the following code: - hosts: all tasks: - name: Install mlocate yum: name=mlocate state=installed - name: Run updatedb command: /usr/bin/updatedb async: 300 poll: 10 You will notice that when you run the previous example on more than five machines, the yum module acts differently to the command module. The yum module will run on the first five machines, then the next five, and so on. The command module, however, will run across all the machines and indicate the status once complete. If your command starts a daemon that eventually listens on a port, you can start it without polling so that Ansible does not check for it to complete. You can then carry on with other actions and check for completion later using the wait_for module. To configure Ansible to not wait for the job to complete, set the value of poll to 0 . Finally, if the task that you are running takes an extremely long time to run, you can tell Ansible to wait for the job as long as it takes. To do this, set the value of async to 0 . You will want to use Ansible's polling in the following situations: ? You have a long-running task that may hit the timeout ? You need to run an operation across a large number of machines ? You have an operation for which you don't need to wait to complete There are also a few situations where you should not use async or poll : ? If your job acquires locks that prevent other things from running ? You job only takes a short time to run
之前我们遇到的playbook都比较简单,只需要运行一些模块就可以了。但是Ansible允许你在运行playbook的时候有更多的控制,让你可以完成最最复杂的部署任务。
Ansible默认一次启用5个线程,所以只能一次只能对5台机器进行操作。如果你的机器数量超过5个,或者线程数低于5个,那么你可能会想要用异步来完成。Ansible的方法是轮询每个任务直到任务结束,这样Absible就可以在使用5个线程的情况下完成所有机器(超过5台机器)操作的任务。
启用并行,需要使用async 和poll这2个关键字,async关键字启用并行,而它的值是他的最大等待时间;poll则设置Ansible多久检查一次任务是否完成。
下面的例子,一次性更新一个群集里面所有的数据库,代码如下:
- hosts: all
tasks:
- name: Install mlocate
yum: name=mlocate state=installed
- name: Run updatedb
command: /usr/bin/updatedb
async: 300
poll: 10
当你运行这个列子的时候,yum操作是5台机器5台机器的运行,但是updatedb操作是一次性操作所有机器,并立刻返回操作状态信息。
如果启用一个daemon程序,并最终会监听一个端口,那么你可以不需要使用poll轮询,而用上一章介绍的wait_for模块,这样只需要把poll的值设置为0就可以了;如果你的操作可能要执行很长很长的时间,那么我们只需要告诉Ansible一直等待就可以了,这样只需要把asyn设置为0即可。
轮询适用的场合有:
不适用async 或则 poll 的场合:
Looping Ansible allows you to repeat a module several times with different input, for example, if you had several files that should have similar permissions set. This can save you a lot of repetition and allows you to iterate over facts and variables. To do this, you can use the with_items key on an action and set the value to the list of items that you are going to iterate over. This will create a variable for the module called item , which will be set to each item in turn as your module is iterated over. Some modules such as yum will optimize this so that instead of doing a separate transaction for each package, they will operate on all of them at once. Using with_items looks like this: tasks: - name: Secure config files file: path=/etc/{{ item }} mode=0600 owner=root group=root with_items: - my.cnf - shadow - fstab In addition to looping over fixed items, or a variable, Ansible can also use what are called lookup plugins. These plugins allow you to tell Ansible to fetch the data from somewhere externally. For example, you might want to upload all the files that match a particular pattern, and then upload them. In this example, we upload all the public keys in a directory and then assemble them into an authorized_keys file for the root user. 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 Repeating modules can be used in the following situations: ? Repeating a module many times with similar settings ? Iterating over all the values of a fact that is a list ? Used to create many files for later use with the assemble module to combine into one large file ? Used with_fileglob to copy a directory of files using the glob pattern matching
Anisble可以根据不同的输入重复运行一个模块很多次,比如一些权限集差不多的文件,你可以根据实际情况和变量值里迭代他们。
使用with_items关键字来定义一个循环,把你希望的数据插入一个列表作为它的值。这样会生成一个变量叫item,当你历遍列表的时候,item将被列表中的元素挨个赋值。像yum这样的模块还会自动优化这种操作,所以你可以使用循环一次性全部完成。
循环的机构类似下面的代码:
tasks:
- name: Secure config files
file: path=/etc/{{ item }} mode=0600 owner=root group=root
with_items:
- my.cnf
- shadow
- fstab
此外,Anisble还可以使用lookup插件来使用外部数据,比如你想上传所有符合一个表达式规则的文件到目的地。下面的例子中,我们上传公钥目录下的所有文件,合并到authorized_keys文件给root用户。
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_fileglob:
- keys/*.pub
- name: Assemble keys into authorized_keys file
assemble: src=/root/.sshkeys dest=/root/.ssh/authorized_keys
mode=0600 owner=root group=root
Repeating模块适用的场景有:
Conditional execution Some modules, such as the copy module, provide mechanisms to configure it to skip the module. You can also configure your own skip conditions that will only execute the module if they resolve to true . This can be handy if your servers use different packaging systems or have different filesystem layouts. It can also be used with the set_fact module to allow you to compute many different things. To skip a module, you can use the when key; this lets you provide a condition. If the condition you set resolves to false , then the module will be skipped. The value that you assign to when is a Python expression. You can use any of the variables or facts available to you at this point. --- - name: Install VIM hosts: all tasks: - name: Install VIM via yum yum: name=vim-enhanced state=installed when: ansible_os_family == "RedHat"<p> - name: Install VIM via apt apt: name=vim state=installed when: ansible_os_family == "Debian"</p> - 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" This feature can be used to pause at a particular point and wait for the user intervention to continue. Normally when Ansible encounters an error, it will simply stop what it is doing without running any handlers. With this feature, you can add the pause module with a condition on it that triggers in unexpected situations. This way the pause module will be ignored in a normal situation, but in unexpected circumstances it will allow the user to intervene and continue when it is safe to do so. The task would look like this: name: pause for unexpected conditions pause: prompt="Unexpected OS" when: ansible_os_family != "RedHat" There are numerous uses of skipping actions; here are a few suggestions: ? Working around differences in operating systems ? Prompting a user and only then performing actions that they request ? Improving performance by avoiding a module that you know won't change anything but may take a while to do so ? Refusing to alter systems that have a particular file present ? Checking if custom written scripts have already been run
有些像copy这样的模块提供skip忽略机制,你也可以配置你自己的条件来跳过某些模块的执行。当你的服务器使用不同的操作系统、文件类型的时候特别有用。你可以根据set_fact模块的值来做不同的事情。
跳过一个模块的执行,使用when这个关键字来提供一个条件,如果条件为假,跳过执行,使用python表达式作为它的值,在这里你可以使用任何变量或则任何可能的fact。
下面的例子就是根据操作系统确定是使用apt还是yum来执行安装操作,当os信息无法确定的时候,就打印一个消息。
---
- 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"
根据这个特性,我们还可以添加pause模块来让用户进行确认以继续,在符合我们设定的条件的正常情况下,pause模块不会被执行,只有异常情况下才会被调用并请求用户确认以继续任务,代码如下
name: pause for unexpected conditions
pause: prompt="Unexpected OS"
when: ansible_os_family != "RedHat"
条件执行适用的场景和建议:
提示用户,然后再执行操作请求
Task delegation Ansible, by default, runs its tasks all at once on the configured machine. This is great when you have a whole bunch of separate machines to configure, or if each of your machines is responsible for communicating its status to the other remote machines. However, if you need to perform an action on a different host than the one Ansible is operating on, you can use a delegation. Ansible can be configured to run a task on a different host than the one that is being configured using the delegate_to key. The module will still run once for every machine, but instead of running on the target machine, it will run on the delegated host. The facts available will be the ones applicable to the current host. Here, we show a playbook that will use the get_url option to download the configuration from a bunch of web servers. --- - 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 If you are delegating to the localhost , you can use a shortcut when defining the action that automatically uses the local machine. If you define the key of the action line as local_action , then the delegation to localhost is implied. If we were to have used this in the previous example, it would be slightly shorter and look like this: --- - name: Fetch configuration from all webservers hosts: webservers tasks: - name: Get config local_action: get_url dest=configs/{{ ansible_hostname }}.cfg url=http://{{ ansible_hostname }}/diagnostic/config Delegation is not limited to the local machine. You can delegate to any host that is in the inventory. Some other reasons why you might want to delegate are: ? Removing a host from a load balancer before deployment ? Changing DNS to direct traffic away from a server you are about to change ? Creating an iSCSI volume on a storage device ? Using an external server to check that access outside the network works
Ansible默认在配置的机器上执行任务,当你有一大票机器需要配置或则每个设备都可达的情况下很有用。但是,当你需要在另外一个Ansible控制机器上运行任务的时候,就需要用到任务委派了。
使用delegate_to关键字就可以委派任务到其他机器上运行,同时可用的fact也会使用委派机器上的值。下面的例子使用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
当你委派给本机的时候,还可以使用更快捷的方法local_action,代码如下:
---
- name: Fetch configuration from all webservers
hosts: webservers
tasks:
- name: Get config
local_action: get_url dest=configs/{{ ansible_hostname
}}.cfg url=http://{{ ansible_hostname
}}/diagnostic/config
你可以委派任务给设备清单上的任意机器,下面是使用任务委派的一些场景:
Ansible@一个高效的配置管理工具--Ansible configure management--翻译(四),布布扣,bubuko.com
Ansible@一个高效的配置管理工具--Ansible configure management--翻译(四)
原文:http://blog.csdn.net/smallfish1983/article/details/37741021