到目前爲止,咱們只是簡單的運行了幾個模塊.其實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能按你的預期來執行.