kolla-ansible是一個結構相對簡單的項目,它經過一個shell腳本,根據用戶的參數,選擇不一樣的playbook和不一樣的參數調用ansible-playbook執行,沒有數據庫,沒有消息隊列,因此本文的重點是ansible自己的語法。html
kolla-ansible命令的主要代碼以下:java
#!/bin/bash # # This script can be used to interact with kolla via ansible. # 默認變量 INVENTORY="${BASEDIR}/ansible/inventory/all-in-one" PLAYBOOK="${BASEDIR}/ansible/site.yml" CONFIG_DIR="/etc/kolla" PASSWORDS_FILE="${CONFIG_DIR}/passwords.yml" while [ "$#" -gt 0 ]; do case "$1" in (--inventory|-i) INVENTORY="$2" shift 2 ;; kolla-ansible支持的各類參數,略 esac done case "$1" in (prechecks) ACTION="Pre-deployment checking" EXTRA_OPTS="$EXTRA_OPTS -e action=precheck" ;; (mariadb_recovery) 略,如下相似皆略 esac CONFIG_OPTS="-e @${CONFIG_DIR}/globals.yml -e @${PASSWORDS_FILE} -e CONFIG_DIR=${CONFIG_DIR}" CMD="ansible-playbook -i $INVENTORY $CONFIG_OPTS $EXTRA_OPTS $PLAYBOOK $VERBOSITY" process_cmd
能夠看出,當咱們執行kolla-ansible deploy時,kolla-ansible命令幫咱們調用了對應的ansible-playbook執行,除此以外,沒有其餘工做。因此對於kolla-ansible項目,主要學習ansible語法便可。node
一個簡單的ansible命令示例以下:
ansible -i /root/myhosts ha01 -m setup
這個命令的做用是,對/root/hosts文件中的全部屬於ha01分類的主機,執行setup模塊收集該主機的信息,它包括兩種元素,主機清單和模塊,下面分別介紹這兩種元素。python
host inventory 是一個文件,存放了全部被ansible管理的主機,能夠在調用anabile命令時,經過-i參數指定。mysql
193.192.168.1.50 ha01 ha02·
能夠執行如下命令檢查ha01是否可以連通git
ansible -i $filename ha01 -m ping ha01 | SUCCESS => { "changed": false, "ping": "pong" }
2.咱們能夠把主機分類,示例以下web
deploy-node [ha] ha01 ha02 [compute] compute01 compute02 compute03
deploy-node [ha] ha[01:02] [openstack-compute] compute[01:50] [openstack-controller] controller[01:03] [databases] db-[a:f].example.com
[openstack-common:children] openstack-controller openstack-compute [common:children] openstack-common databases ha
ansible -i $file common -m ping
ansible封裝了不少python腳本做爲module提供給使用者,如:yum、copy、template,command,etc. 當咱們會特定主機執行某個module時,ansible會把這個module對應的python腳本,拷貝到目標主機上執行。可使用ansible-doc -l來查看ansible支持的全部module。使用ansible -v 模塊名 來查看該模塊的詳細信息。sql
上文的例子,使用了-m ping參數,意思是對這些主機,執行ping 模塊,ping 模塊是一個python腳本,做用是用來判斷:目標機器是否可以經過ssh連通而且已經安裝了python。docker
# ping module主要源碼 description: - A trivial test module, this module always returns C(pong) on successful contact. It does not make sense in playbooks, but it is useful from C(/usr/bin/ansible) to verify the ability to login and that a usable python is configured. - This is NOT ICMP ping, this is just a trivial test module. options: {} from ansible.module_utils.basic import AnsibleModule def main(): module = AnsibleModule( argument_spec=dict( data=dict(required=False, default=None), ), supports_check_mode=True ) #什麼都不作,構建一個json直接返回 result = dict(ping='pong') if module.params['data']: if module.params['data'] == 'crash': raise Exception("boom") result['ping'] = module.params['data'] module.exit_json(**result) if __name__ == '__main__': main()
example:Ansible模塊開發-自定義模塊
若是默認模塊不能知足需求,能夠自定義模塊放到ansible指定的目錄,默認的ansible配置文件是/etc/ansible/ansible.cfg,library配置項是自定義模塊的目錄。
openstack的kolla-ansbile項目的ansible/library目錄下面存放着kolla自定義的module,這個目錄下每個文件都是一個自定義moudle。可使用以下的命令來查看自定義module的使用方法:ansible-doc -M /usr/share/kolla-ansible/ansible/library -v merge_configs
shell
如上文所述,ansible moudle最終執行的位置是目標機器,因此module腳本的執行依賴於目標機器上安裝了對應的庫,若是目標機器上沒有安裝對應的庫,腳本變不能執行成功。這種狀況下,若是咱們不打算去改動目標機器,可使用action moudle,action moudle是一種用來在管理機器上執行,可是能夠最終做用到目標機器上的module。
例如,OpenStack/kolla-ansible項目部署容器時,幾乎對每一臺機器都要生成本身對應的配置文件,若是這個步驟在目標機器上執行,那麼須要在每一個目標機器上都按照配置文件對應的依賴python庫。爲了減小依賴,kolla-ansible定義了action module,在部署節點生成配置文件,而後經過cp module將生成的文件拷貝到目標節點,這樣就沒必要在每一個被部署節點都安裝yml,oslo_config等python庫,目標機器只須要支持scp便可。kolla-ansible的action module存放的位置是ansible/action_plugins.
不建議深刻去學,太多了,用到的時候一個個去查就行了
待補充
前文提到的ansible命令,都是一些相似shell命令的功能,若是要作一些比較複雜的操做,好比說:部署一個java應用到10臺服務器上,一個模塊顯然是沒法完成的,須要安裝模塊,配置模塊,文件傳輸模塊,服務狀態管理模塊等模塊聯合工做才能完成。把這些模塊的組合使用,按特定格式記錄到一個文件上,而且使該文件具有可複用性,這就是ansible的playbook。若是說ansible模塊相似於shell命令,那playbook相似於shell腳本的功能。
這裏舉一個使用playbook集羣的例子,kolla-ansible deploy 實際上就是調用了:
ansible-playbook -i /usr/share/kolla-ansible/ansible/inventory/all-in-one -e @/etc/kolla/globals.yml -e @/etc/kolla/passwords.yml -e CONFIG_DIR=/etc/kolla -e action=deploy /usr/share/kolla-ansible/ansible/site.yml
--- - hosts: webservers vars: http_port: 80 max_clients: 200 remote_user: root tasks: - name: ensure apache is at the latest version yum: name=httpd state=latest - name: write the apache config file template: src=/srv/httpd.j2 dest=/etc/httpd.conf notify: - restart apache - name: ensure apache is running (and enable it at boot) service: name=httpd state=started enabled=yes handlers: - name: restart apache service: name=httpd state=restarted
這個playbook來自ansible官網,包含了一個play,功能是在全部webservers節點上安裝配置apache服務,若是配置文件被重寫,重啓apache服務,在任務的最後,確保服務在啓動狀態。
play中的hosts表明這個play要在哪些主機上執行,這裏可使一個或者多個主機,也能夠是一個或者多個主機組。remote_user表明要以指定的用戶身份來執行此play。remote_user能夠細化到task層。
--- - hosts: webservers remote_user: root tasks: - name: test connection ping: remote_user: yourname
task是要在目標機器上執行的一個最小任務,一個play能夠包含多個task,全部的task順序執行。
在play中能夠定義一些參數,如上文webservers中定義的http_port和max_clients,這兩個參數會做用到這個play中的task上,最終template模塊會使用這兩個參數的值來生成目標配置文件。
當某個task對主機形成了改變時,能夠觸發notify操做,notify會喚起對應的handler處理該變化。好比說上面的例子中,若是template module重寫/etc/httpd.conf文件後,該文件內容發生了變化,就會觸發task中notify部分定義的handler重啓apache服務,若是文件內容未發生變化,則不觸發handler。
也能夠經過listen來觸發想要的handler,示例以下:
handlers: - name: restart memcached service: name=memcached state=restarted listen: "restart web services" - name: restart apache service: name=apache state=restarted listen: "restart web services" tasks: - name: restart everything command: echo "this task will restart the web services" notify: "restart web services"
上文給出的webserver playbook中,task和hanler的部分是最通用的,vars部分其次,hosts參數最次。其餘人拿到這個playbook想到使用,通常不須要修改task,可是host和vars部分,就須要修改爲本身須要的值。因此ansible這裏引入了role的概念,把host從playbook中移出,把剩下的內容按照下面示例的樣式,拆成幾部分,handler存放到handler中,task存放到task目錄中去,默認變量存放到default中,使用到的文件'httpd.j2'存放到templates目錄下,按照這樣的目錄格式組織完成後,咱們就獲得了一個webserber role。
tasks中能夠有不少task,被執行的入口是main.yml
# 官網的一個role目錄結構的例子 site.yml webservers.yml fooservers.yml roles/ common/ tasks/ main.yml handlers/ files/ templates/ defaults/ meta/ webservers/ tasks/ main.yml defaults/ meta/ templates/
role的使用方法,能夠參考下面的例子,下面的playbook做用是:對全部的webservers機器,執行common,weservers,foo_app_instance對應的task,執行最後一個role時,傳遞了dir和app_port兩個參數。
--- - hosts: webservers roles: - common - webservers - { role: foo_app_instance, dir: '/opt/a', app_port: 5000 }
能夠考慮這樣兩個問題:
include功能能夠解決這樣的問題,一個include的例子以下
tasks/ bootstrap.yml ceph.yml config.yml check.yml deploy.yml upgrade.yml precheck.yml register.yml main.yml main.yml --- - include: "{{ action }}.yml" deploy.yml --- - include: ceph.yml when: - enable_ceph | bool and nova_backend == "rbd" - inventory_hostname in groups['ceph-mon'] or 略 - include: register.yml when: inventory_hostname in groups['nova-api'] - include: config.yml - include: bootstrap.yml when: inventory_hostname in groups['nova-api'] or inventory_hostname in groups['compute'] 略
當nova role被賦給一臺服務器後,若是用戶指定的action是deploy,ansible會引入deploy.yml,若是是upgrade,則引入upgrade.yml。這樣根據用戶參數的不一樣,include不一樣的playbook,從而實現一個role支持多種功能。
deploy playbook又由多個不一樣的playbook組成,根據用戶的配置的參數,有不一樣的組合方式,很靈活。
個人理解是,在role的task中,一個play就好像一個內部函數,一個playbook是由一個由多個play組成的公有函數,被其餘playbook根據include參數組合調用。
kolla-ansible中的play都比上面的例子複雜不少,它不少時候都不直接調用module,而是加了不少判斷,循環,錯誤處理之類的邏輯,一個例子:
ansible.roles.prechecks.tasks.package_checks.yml --- - name: Checking docker SDK version command: "/usr/bin/python -c \"import docker; print docker.__version__\"" register: result changed_when: false when: inventory_hostname in groups['baremetal'] failed_when: result | failed or result.stdout | version_compare(docker_py_version_min, '<')
這個playbook的功能是:
下面分別介紹幾種kolla-ansible中經常使用的ansible語法。
when,faild_when, change_when 後面能夠接入一個條件語句,條件語句的值是true或者false,條件語句示例以下:
ansible_os_family == "Debian" test == 1 or run == always hostname in [1,2,3,4]
ansible除了上文的==, or, in來進行判斷外,ansible還支持經過管道調用ansible自定義的test plugin進行判斷,上文中的result | failed or result.stdout | version_compare(docker_py_version_min, '<')
用到了version_compare和failed兩個test plugin,這兩個test plugin本質是ansible指定目錄下兩個python函數,用來解析字符串判斷版本版本是否匹配,執行命令是否成功。它們的源碼位於ansible.plugins.test.core, ansible。全部test plugin位於ansible.plugins.test,ansible支持自定義test plugin。
with_itmes 是ansible的迭代語句,做用相似python的 for item in {}, 用法示例:
- name: test list command: echo {{ item }} with_items: [ 0, 2, 4, 6, 8, 10 ] when: item > 56 - name: Setting sysctl values sysctl: name={{ item.name }} value={{ item.value }} sysctl_set=yes with_items: - { name: "net.bridge.bridge-nf-call-iptables", value: 1} - { name: "net.bridge.bridge-nf-call-ip6tables", value: 1} - { name: "net.ipv4.conf.all.rp_filter", value: 0} - { name: "net.ipv4.conf.default.rp_filter", value: 0} when: - set_sysctl | bool - inventory_hostname in groups['compute']
一種錯誤處理機制,通常用來檢測執行的結果,若是執行失敗,終止任務,和條件語句搭配使用
當咱們控制一些遠程主機執行某些任務時,當任務在遠程主機上成功執行,狀態發生更改時,會返回changed狀態響應,狀態未發生更改時,會返回OK狀態響應,當任務被跳過期,會返回skipped狀態響應。咱們能夠經過changed_when來手動更改changed響應狀態。
當對一個主機組賦予進行操做時,有部分操做並不須要在每一個主機上都執行,好比說nova服務安裝時,須要初始化nova數據庫,這個操做只須要在一個節點上執行一次就能夠了,這種狀況可使用run_once標記,被標記的任務不會在多個節點上重複執行。
delegate_to能夠配合run_once使用,能夠在playbook中指定數據庫任務要執行的主機,下面的例子中,指定要執行數據庫建立的主機是groups['nova-api'][0]
- name: Creating Nova databases kolla_toolbox: module_name: mysql_db module_args: login_host: "{{ database_address }}" login_port: "{{ database_port }}" login_user: "{{ database_user }}" login_password: "{{ database_password }}" name: "{{ item }}" register: database run_once: True delegate_to: "{{ groups['nova-api'][0] }}" with_items: - "{{ nova_database_name }}" - "{{ nova_database_name }}_cell0" - "{{ nova_api_database_name }}"
delegate_to指定的機器能夠當前任務的機器沒有任何關係,好比,在部署nova服務時,能夠delegate_to的目標不限於nova機器,能夠到delegate_to ansible控制節點或者存儲機器上執行任務。例如:
通常狀況下, ansible會同時在全部服務器上執行用戶定義的操做, 可是用戶能夠經過serial參數來定義同時能夠在多少太機器上執行操做.
- name: test play
hosts: webservers
serial: 3
webservers組中的3臺機器徹底完成play後, 其餘3臺機器纔會開始執行
這種循環由三個指令完成:
示例以下:
wait_for 可讓ansible等待一段時間,直到條件知足,再繼續向下執行,這個模塊主要用來等待以前的操做完成,好比服務啓動成功,鎖釋放。
下面是一個kolla-ansible判斷murano-api服務是否啓動成功的例子:
在murano-api[0]節點上, 嘗試和api_interface_address:murano_api_port創建連接,若是成功創建鏈接,結束等待。若是1秒(connect_timeout)內未創建成功,放棄,休眠1秒(參數sleep,未配置,默認值)後重試,若是60秒(timeout)內沒有成功建立連接,任務失敗。
- name: Waiting for Murano API service to be ready on first node wait_for: host: "{{ api_interface_address }}" port: "{{ murano_api_port }}" connect_timeout: 1 timeout: 60 run_once: True delegate_to: "{{ groups['murano-api'][0] }}"
ansible入門書:https://ansible-book.gitbooks.io/ansible-first-book/content/begin/basic_module/module_list_details.html ansible循環用法:http://www.cnblogs.com/PythonOrg/p/6593910.html 自定義過濾器:http://rfyiamcool.blog.51cto.com/1030776/1440686/ 異步和輪詢:http://www.mamicode.com/info-detail-1202005.html ansible 語法:http://blog.csdn.net/ggz631047367/article/details/50359127 ansible官網:http://docs.ansible.com/ansible/latest/