无书面许可请勿转载
高级playbook
Finding files with variables All modules can take variables as part of their arguments by dereferencing them with {{ and }} . You can use this to load a particular file based on a variable. For example, you might want to select a different config file for NRPE (a Nagios check daemon) based on the architecture in use. Here is how that would look: --- #1 - name: Configure NRPE for the right architecture #2 hosts: ansibletest #3 user: root #4 tasks: #5 - name: Copy in the correct NRPE config file #6 copy: src=files/nrpe.{{ ansible_architecture }}.conf dest=/etc/nagios/nrpe.cfg #7 In the copy and the template modules, you can also configure Ansible to look for a set of files, and it finds them using the first one. This lets you configure a file to look for; if that file is not found a second will be used, and so on until the end of the list is reached. If the file is not found, then the module will fail. The feature is triggered by using the first_available_file key, and referencing {{ item }} in the action. The following code is an example of this feature: --- #1 - name: Install an Apache config file #2 hosts: ansibletest #3 user: root #4 tasks: #5 - name: Get the best match for the machine #6 copy: dest=/etc/apache.conf src={{ item }} #7 first_available_file: #8 - files/apache/{{ ansible_os_family }}-{{ ansible_architecture }}.cfg #9 - files/apache/default-{{ ansible_architecture }}.cfg - files/apache/default.cfg #11 Remember that you can run the setup module from the Ansible command-line tool. This comes in handy when you are making heavy use of variables in your playbooks or templates. To check what facts will be available for a particular play, simply copy the value of the host line and run the following command: ansible [host line] -m setup On a CentOS x86_64 machine, this configuration would first look for the file RedHat-x86_64.cfg upon navigating through files/apache/ . If that file did not exist, it would look for file default-x86_64.cfg upon navigating through file/ apache/ , and finally if nothing exists, it'll try and use default.cfg .
使用变量查找文件
所有的Ansible模块都可以使用{{ }}这种形式将变量做为他的一部分参数。这样你就可以利用变量来加载不同的配置。比如你希望根据不同架构来加载不同nrpe配置,代码如下:
---
- 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和template模块中,Ansible可以让那个你配置去查找一个文件集,第一个被找到的文件将被使用,若找不到则继续知道找到匹配的为止,若循环完毕还是没有找到对应的文件,那么模块不会被运行。使用first_available_file关键字和在action中使用{{ item }}来完成以上功能,示例代码如下:
---
- 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
注意:在你大量使用模板和变量之前,你可以使用setup模块来确认一些fact(比如上面这个例子主要是因为不同的操作系统apache的配置文件名和格式都不一样)。
在centos X86_64的机器上,他首先会查找RedHat-x86_64.cfg,因为他的架构是x86_64,如果找不到就找default-x86_64.cfg,如果再找不到就用default.cfg。
Environment variables Often Unix commands take advantage of certain environment variables. Prevalent examples of this are C makefiles, installers, and the AWS command-line tools. Fortunately, Ansible makes this really easy. If you wanted to upload a file on the remote machine to Amazon S3, you could set the Amazon access key as follows. You will also see that we install EPEL so that we can install pip, and pip is used to install the AWS tools. --- #1 - name: Upload a remote file via S3 #2 hosts: ansibletest #3 user: root #4 tasks: #5 - name: Setup EPEL #6 command rpm -ivh #7 http://download.fedoraproject.org/pub/epel/6/i386/epel- release-6-8.noarch.rpm creates=/etc/yum.repos.d/epel.repo #8 - name: Install pip #9 yum: name=python-pip state=installed - name: Install the AWS tools pip: name=awscli state=present #10 #11 #12 - name: Upload the file #13 shell: aws s3 put-object --bucket=my-test-bucket --key={{ ansible_hostname }}/fstab --body=/etc/fstab --region=eu- west-1 #14 environment: #15 AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXX #16 AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXX #17 Internally, Ansible sets the environment variable into the Python code; this means that any module that already uses environment variables can take advantage of the ones set here. If you write your own modules, you should consider if certain arguments would be better used as environment variables instead of arguments. Some Ansible modules such as get_url , yum , and apt will also use environment variables to set their proxy server. Some of the other situations where you might want to set environment variables are as follows: ? Running application installers ? Adding extra items to the path when using the shell module ? Loading libraries from a place not included in the system library search path ? Using an LD_PRELOAD hack while running a module
Environment 环境变量
unix的一些命令经常配合环境变量来运行,典型的例子比如,C makefiles, installers, 和 AWS这些命令行工具。幸运的是使用Ansible做到这一点,非常简单。比如:当我们要上传一个文件到S3服务器的时候,我们需要提AWS_SECRET_ACCESS_KEY,我们的脚本代码如下:
---
- 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
我们先使用epel来安装pip,然后使用ip来安装aws最后设置shell环境变量然后上传文件。
注意:我们在ansible内部把这些环境变量放入到python的代码中,这样就可以让任何使用环境变量的模块都可以使用这里的设置了。如果你要编写自己的模块,你可以把参数作为环境变量放到这里将比使用参数更好哦!
另外像get_url , yum , 和 apt还会使用环境变量中的代理设置。下面是其他一些需要使用环境变量的场景:
- 安装一个应用程序
- 在使用shell模块的时候加入新的path
- 加载不存在系统默认搜索路径的库
- 运行的模块需要使用动态链接库的时候
External data lookups Ansible introduced the lookup plugins in Version 0.9. These plugins allow Ansible to fetch data from outside sources. Ansible provides several plugins, but you can also write your own. This really opens the doors and allows you to be flexible in your configuration. Lookup plugins are written in Python and run on the controlling machine. They are executed in two different ways: direct calls and with_* keys. Direct calls are useful when you want to use them like you would use variables. Using the with_* keys is useful when you want to use them as loops. In an earlier section we covered with_ fileglob , which is an example of this. In the next example, we use a lookup plugin directly to get the http_proxy value from environment and send it through to the configured machine. This makes sure that the machines we are configuring will use the same proxy server to download the file. --- #1 - name: Downloads a file using the same proxy as the controlling machine #2 hosts: all #3 tasks: #4 - name: Download file #5 get_url: dest=/var/tmp/file.tar.gz url=http://server/file.tar.gz #6 environment: #7 http_proxy: "{{ lookup('env', 'http_proxy') }}" #8
外部数据查找
Ansible在0.9版本的时候引入了lookup插件。这些插件可以让Ansible从外部数据源获取数据。Ansible提供了好多插件,但是你还是可以自己写,这真的是非常开放,可以你非常灵活的配置。
lookup插件用python编写,并运行在控制主机上。它有2中执行方式:直接调用和使用with_*关键字;当你想像使用变量那样使用的时候可以用直接调用的方式,如果你想像循环那样使用则可以选择with_*关键字这种方式,之前前我们有一个例子中使用了ith_fileglob就是这种方式。
下面的例子我们直接从环境变量中获取http_proxy然后发送给远程主机,以确保他们使用同样的下载代理。
---
- 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‘) }}"
注意:你也可以在lookup插件中使用变量,他不会在查找到之后马上被赋值,而是保存在一个宏里面,你每次运行的时候再查找一次。如果你用的某些值经常会变的时候,这就非常有用了。
使用with_*格式可以让你历遍列表中的所有值,任何插件都可以,而他们返回的列表通常都很有用。下面的例子展示如何注册动态的app farm,它可以为每个虚拟机添加一个新的任务,并在每个虚拟机上运行。
---
- 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适用的从场景有:
- 复制apache的整个配置文件夹到conf.d这种形式的文件夹下面
- 根据环境变量来调整哪些playbook需要运行
- 从DNS TXT 记录获取配置
- 把一个命令的输出放如一个变量
Storing results Almost every module outputs something, even the debug module. Most of the time the only variable used is the one named changed . The changed variable helps Ansible decide whether to run handlers or not and which color to print the output in. However, if you wish you can store the returned values and use them later in the playbook. In this example we look at the mode in the /tmp directory and create a new directory called /tmp/subtmp with the same mode. --- - 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 Some modules, like we see in the previous file module, can be configured to simply give information. Combining this with the register feature, you can create playbooks that can examine the environment and calculate how to proceed. Combining the register feature and the set_fact module allows you to perform data processing on data you receive back from modules. This allows you to compute values and perform data processing on these values. This makes your playbooks even smarter and more flexible than ever. Register allows you to make your own facts about hosts from modules already available to you. This can be useful in many different circumstances: ? Getting a list of files in a remote directory and downloading them all with fetch ? Running a task when a previous task changes, before the handlers run ? Getting the contents of the remote host SSH key and building a known_hosts file
保存结果
几乎所有的模块都会输出一些东西,debug模式中也是如此。多数情况下只有变量被标记是否被改变了,这可以帮助Ansible来决定是否要调用处理程序handle、输出哪种颜色的信息。如果你想保存返回变量的值,保存之后在以后的playbook中使用。下面的例子向你展示,我们先查找/tmp目录的信息,将信息注册为变量,然后利用这个变量为子目录的全新赋值:
---
- 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注册模块和set_fact模块,你可以根据模块返回的值来处理数据,这将让我们的playbooks变得更加聪明、更加灵活。
register注册模块允许你从主机上可用的模块中注册你自己的fact,这在以下场景中非常有用:
- 从远程主机上获取一个目录列表并下载他们
- 在handlers处理程序运行之前,根据前一个任务的改变内容运行一个新任务
- 获取远程主机的ssh的key的内容,合成一个known_hosts文件
Debugging playbooks There are a few ways in which you can debug a playbook. Ansible includes both a verbose mode, and a debug module specifically for debugging. You can also use modules such as fetch and get_url for help. These debugging techniques can also be used to examine how modules behave when you wish to learn how to use them.
Debugging playbooks
有很多方法可以debug一个playbook。Ansible包含一个详细模式和一个专用调试模块。你可以像其他模块的帮助一样使用调试模式的帮助。这些debugging技术还可以让你在想学习如何使用他们的时候,熟悉他们的行为方式。
The debug module Using the debug module is really quite simple. It takes two optional arguments, msg and fail . msg sets the message that will be printed by the module and fail , if set to yes , indicates a failure to Ansible, which will cause it to stop processing the playbook for that host. We used this module earlier in the skipping modules section to bail out of a playbook if the operating system was not recognized. In the following example, we will show how to use the debug module to list all the interfaces available on the machine: --- - name: Demonstrate the debug module hosts: ansibletest user: root vars: hostcount: 5 tasks: - name: Print interface debug: msg="{{ item }}" with_items: ansible_interfaces The preceding code gives the following output: 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 As you can see the debug module is easy to use to see the current value of a variable during the play.
Debug 模式
使用debug模式非常简单,只需要2个可选的参数,msg和fail。msg 设置模块和fail来打印消息,当msg设置为yes时,表明Ansible有failure会导致playbook停止在这台主机上运行。通常我们在脚本的开始处来检测操作系统是否可以被认出。下面的例子中,我们将展示如何使用debug模块来列机器上所有可用的接口:
---
- 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
The verbose mode Your other option for debugging is the verbose option. When running Ansible with verbose, it prints out all the values that were returned by each module after it runs. This is especially useful if you are using the register keyword introduced in the previous section. To run ansible-playbook in verbose mode, simply add --verbose to your command line as follows: ansible-playbook --verbose playbook.yml
详细模式
另外一个选择是debugging详细模式。当使用详细模式时,他会打印出每个模块运行后所有的返回值。这在使用register关键字的时候特别有用。使用详细模式的方法非常简单,在命令后加一个--verbose就可以了:
ansible-playbook --verbose playbook.yml
The check mode In addition to the verbose mode, Ansible also includes a check mode and a diff mode. You can use the check mode by adding --check to the command line, and --diff to use the diff mode. The check mode instructs Ansible to walk through the play without actually making any changes to remote systems. This allows you to obtain a listing of the changes that Ansible plans to make to the configured system. It is important here to note that the check mode of Ansible is not perfect. Any modules that do not implement the check feature are skipped. Additionally, if a module is skipped that provides more variables, or the variables depend on a module actually changing something (like file size), then they will not be available. This is an obvious limitation when using the command or shell modules. The diff mode shows the changes that are made by the template module. This limitation is because the template file only works with text files. If you were to provide a diff of a binary file from the copy module, the result would almost be unreadable. The diff mode also works with the check mode to show you the planned changes that were not made due to being in check mode.
检查模式
除了详细模式,Ansible还有检查模式和差异模式。你可以用--check和--diff来运行他们,检查模式会检查脚本的运行,但是不会在远程受管主机上执行任何改变配置的操作,它返回一个可能改变的列表。
注意:检测模式不是全能的,那些不做任何改变配置操作的模块会直接被忽略,另外基于变量的模块也会被忽略,那些基于上一个任务改变而运行的模块也会被忽略。它主要用于检查command和shell模块的可行性。
差异模块可以现实出被模板模块改变的内容,但是这仅限于text文件,如果你指向的是一个binary可执行文件,那么结果永远是不可达。差异模块和检查模块一样不会对远程主机有任何改变。
The pause module Another technique is to use the pause module to pause the playbook while you examine the configured machine as it runs. This way you can see changes that the modules have made at the current position in the play, and then watch while it continues with the rest of the play.
暂停模块
另外一种debug技术是使用暂停模块,当你要检测远程受管主机上的脚本运行的时候,使用暂停模块来暂停playbook,这样你可以看到当前步骤模块所做的改变,并继续监视知道结束。
Summary In this chapter we explored the more advanced details of writing playbooks. You should now be able to use features such as delegation, looping, conditionals, and fact registration to make your plays much easier to maintain and edit. We also looked at how to access information from other hosts, configure the environment for a module, and gather data from external sources. Finally we covered some techniques for debugging plays that are not behaving as expected. In the next chapter we will be covering how to use Ansible in a larger environment. It will include methods for improving the performance of your playbooks that may be taking a long time to execute. We will also cover a few more features that make plays maintainable, particularly splitting them into many parts by purpose.
本章小节
这一章我们介绍了更多在写playbooks时候的高级细节。你现在应该可以使用委派、循环、条件、fact注册来是你的plays更加易于维护和编写。我们还介绍了如何访问其他机器的信息、为模块配置环境变量、从外部数据源收集信息。最后我们还介绍了一些debugging技术。
下一章我们将介绍如何在一个大的环境中使用Ansible,这包括如何改进playbooks的运行性能以减少运行时间。我们还将介绍更多的特性,关于如何使得plays更易维护,并根据目标将他们分为多个部分。
[email protected]一个高效的配置管理工具--Ansible configure management--翻译(六),布布扣,bubuko.com