ansible 使用技巧

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

  1. 你有一個task須要運行很長的時間,這個task極可能會達到timeout.
  2. 你有一個任務須要在大量的機器上面運行
  3. 你有一個任務是不須要等待它完成的

固然也有一些場景是不適合使用polling特性的vim

  1. 你的這個任務是須要運行完後才能繼續另外的任務的
  2. 你的這個任務能很快的完成

Looping

在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模塊通常在下面的場景中使用

  1. 相似的配置模塊重複了多遍
  2. fact是一個列表
  3. 建立多個文件,而後使用assemble聚合成一個大文件
  4. 使用with_fileglob匹配特定的文件管理

條件語句

有一些模塊,例如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"

下面一些情景建議你使用條件語句作跳過動做

  1. job裏面有不一樣操做系統的機器
  2. 提示用戶,而後再執行操做請求
  3. 提升性能,避免運行一個須要執行一段時間模塊,並且你知道這個模塊不會返回changed

task委託

默認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.下列一些場景適用使用委託

  1. 部署以前你但願從負載均衡裏面把host移除
  2. 更改你的server時候更改dns的指向
  3. 建立一個iSCSI卷存儲設備
  4. 使用一個外部服務器去檢測一下服務

額外的變量

你們應該在以前的章節的例子裏面有看到group_names這個變量.這個是ansible提供的一個很神奇變量.直至寫本書的時候,有7個這樣的變量,我會在下面的章節介紹

a.hostvars變量

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

b.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使用

下面的例子配置建立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 %}

c.group_names變量

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

d.inventory_hostname變量

inventory_hostname是機器的hostname,當你沒有使用setup模塊,或者因爲各類緣由致使setup的變量是錯誤的,你能夠選擇使用這個變量.此變量能夠幫助你初始化你的機器和改變hostname

e.inventory_hostname_short

inventory_hostname_short相似與上面的inventory_hostname變量,只是它是截取第一個句點的前面的字符,例如hostname是host.example.com,就會只截取到host

f.inventory_dir

此變量是inventory文件的路徑,包括目錄與文件名

g.inventory_file

相似上面的變量,只是它只有文件名

使用變量來查找文件

全部的模塊均可以把變量做爲參數的一部分,經過使用」{{}}」符號擴起來.譬如變量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的.下面一些場景也是須要配置環境變量的

  1. 運行application installers
  2. 當運行shell的時候須要添加一些額外的的變量在path裏
  3. 須要load的一些庫不在系統的library路徑中
  4. 在運行模塊時使用LD_PRELOAD hack

External data lookups

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很是有用

  1. 複製整個目錄的apache配置到conf.d
  2. 使用環境變量調整playbook的運行
  3. 從DNS TXT記錄中獲取配置
  4. 獲取一個命令的輸出到一個變量中

保存結果

幾乎全部的模塊都是會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對於數多場景是頗有用的

  1. 在一臺遠端的服務器獲取一個目錄下的一列表的文件,而後下載這些文件
  2. 在handler執行以前,發現前面一個task發生了changed,而後執行一個指定的task
  3. 獲取遠端服務器的ssh key的內容,構建出known_hosts文件

debugging playbook

有好幾種方法去debug咱們的playbook.ansible有verbose模式和debug模式,也可使用例如fetch和get_url模塊來協助debug.當你想學習怎樣使用一些模塊時,這些debugging技術可以幫助你.

a.debug模塊

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運行期間一些變量

b.verbose模式

另外的debug選擇是verbose模式.當運行verbose模式時,會打印出全部模塊運行後的變量.這對於你要使用register功能時候很重要.只須要在執行playbook命令時加上參數–verbose即可以.ansible-playbook –verbose playbook.yml

c.check模式

除了verbose模式外,ansible還提供了check模式和diff模式.只須要執行playbook時添加參數–check和–diff.check模式運行時,ansible不會真正控制遠程機器發生變動.這可以讓你得到此次playbook任務中,將會發生changed事件的列表.

很重要的一點是check模式不是完美的.有一些模塊是會跳過check模式的.尤爲明顯的限制是在運行command和shell模塊

在diff模式下,當文件發現更變,會打印出變動文件的變動部分.配合check模式使用效果更好

d.pause模塊

另一個debug技巧是使用pause模塊,它可讓你須要在某個地方須要檢查遠程機器的配置的時候暫停playbook的執行.這樣可讓先觀察一下運行到這裏爲止的效果,再判斷是否繼續運行下去.

總結

在這個章節咱們更加深刻探索了編寫playbook的一些細節.如今你應該可使用一些ansible的特性.例如delegation,looping,conditionals,和fact,registration等等,讓你可以更容易的編寫和維護你的playbook.咱們也看到了如何獲取其餘host的信息,如何配置環境變量,如何從外圍獲取到數據.最後咱們展現了一些debug技巧,讓playbook能按你的預期來執行.

相關文章
相關標籤/搜索