kolla-ansible快速入門
kolla-ansible是一個結構相對簡單的項目,它通過一個shell腳本,根據用戶的參數,選擇不同的playbook和不同的參數調用ansible-playbook執行,沒有數據庫,沒有消息隊列,所以本文的重點是ansible本身的語法。
kolla-ansible命令
kolla-ansible命令的主要代碼如下:
#!/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語法即可。
ansible
一個簡單的ansible命令示例如下:
ansible -i /root/myhosts ha01 -m setup
這個命令的作用是,對/root/hosts文件中的所有屬於ha01分類的主機,執行setup模塊收集該主機的信息,它包括兩種元素,主機清單和模塊,下面分別介紹這兩種元素。
Host Inventory(主機清單)
host inventory 是一個文件,存放了所有被ansible管理的主機,可以在調用anabile命令時,通過-i參數指定。
- 下面是一個最簡單的hosts file的例子,包含1個主機ip和兩個主機名:
193.192.168.1.50
ha01
ha02·
可以執行以下命令檢查ha01是否能夠連通
ansible -i $filename ha01 -m ping
ha01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
2.我們可以把主機分類,示例如下
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
- 所有的controller和compute,都是openstack的節點,所以我們可以再定義一個類別openstack-common,把他們里面的主機都包括進去
[openstack-common:children]
openstack-controller
openstack-compute
[common:children]
openstack-common
databases
ha
- 當我們有了如上的inventory 文件后,可以執行如下命令,檢驗是不是所有機器都能夠被ansible管理
ansible -i $file common -m ping
Module(模塊)
ansible封裝了很多python腳本作為module提供給使用者,如:yum、copy、template,command,etc. 當我們會特定主機執行某個module時,ansible會把這個module對應的python腳本,拷貝到目標主機上執行。可以使用ansible-doc -l來查看ansible支持的所有module。使用ansible -v 模塊名 來查看該模塊的詳細信息。
1. 一個例子,ping
上文的例子,使用了-m ping參數,意思是對這些主機,執行ping 模塊,ping 模塊是一個python腳本,作用是用來判斷:目標機器是否能夠通過ssh連通並且已經安裝了python。
# 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()
2. 自定義模塊
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
3. action moudle
如上文所述,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.
4. 模塊學習
不建議深入去學,太多了,用到的時候一個個去查就好了
- 這篇文章介紹了ansible常用模塊的用法:http://blog.csdn.net/iloveyin/article/details/46982023
- ansible官網提供了所有module的用法:http://docs.ansible.com/ansible/latest/modules_by_category.html
- ansible 所有module源碼存放路徑:/usr/lib/python2.7/site-packages/ansible/modules/
ansible-playbook
待補充
Playbook(劇本)
前文提到的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
1. 一個簡單的playbook
---
- 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服務,在任務的最后,確保服務在啟動狀態。
playbook中的元素
1. hosts and remote_user
play中的hosts代表這個play要在哪些主機上執行,這里可以使一個或者多個主機,也可以是一個或者多個主機組。remote_user代表要以指定的用戶身份來執行此play。remote_user可以細化到task層。
---
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
2. tasks
task是要在目標機器上執行的一個最小任務,一個play可以包含多個task,所有的task順序執行。
3. vars
在play中可以定義一些參數,如上文webservers中定義的http_port和max_clients,這兩個參數會作用到這個play中的task上,最終template模塊會使用這兩個參數的值來生成目標配置文件。
4. handlers
當某個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"
使用role和include更好的組織playbook
1. role
上文給出的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 }
2. include
可以考慮這樣兩個問題:
- 上文我們定義webserver role作用是在指定服務器上安裝並確保apache服務運行,那么如果我們想要升級,關閉或者卸載apache服務呢,該怎么辦,再定義新的role,webserver-upgrade看起來似乎太蠢笨了。能不能像面向對象那樣,一個對象支持不同的操作?
- 上文中的webserver服務安裝比較簡單,所以我們的playbook也比較簡單,但是有時候會遇到比較麻煩的需求,比如說安裝openstack的neutron服務,它需要先檢車設置,再生存配置文件,同步數據庫,等步驟,這項功能如果都寫成一個playbook,這個playbook是不是太大了,很難維護。可不可以把檢查,配置,同步等功能做成不同的playbook,然后從一個主playbook中看情況調用?
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中常見ansible語法
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的功能是:
- 開始執行book中的第一個play:Checking docker SDK version
- 判斷目標主機inventory_hostname是否屬於主機清單中的baremetal組
- 如果屬於,到這台主機上執行command module,參數是"/usr/bin/python -c "import docker; print docker.version""
- 將執行的結果賦值給result變量
- 因為這個模塊不會更改目標主機上的任何設置,所以change_when是false,無論執行結果如何,都不會去改變這個當然任務的changed屬性
- 將result變量傳遞給failed函數,判斷命令是否執行成功
- 如果命令執行成功,將result中的輸出結果,傳遞給version_compare函數,判斷版本是否符合要求
- 因為這個模塊不會更改目標主機上的任何設置,所以change_when永遠是false
- 如果failed_when判斷結果為失敗,則設置任務狀態為失敗,停止執行此playbook
下面分別介紹幾種kolla-ansible中常用的ansible語法。
1.條件語句
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。
2. 迭代
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']
3. failed_when
一種錯誤處理機制,一般用來檢測執行的結果,如果執行失敗,終止任務,和條件語句搭配使用
4. changed_when
當我們控制一些遠程主機執行某些任務時,當任務在遠程主機上成功執行,狀態發生更改時,會返回changed狀態響應,狀態未發生更改時,會返回OK狀態響應,當任務被跳過時,會返回skipped狀態響應。我們可以通過changed_when來手動更改changed響應狀態。
5. run_once
當對一個主機組賦予進行操作時,有部分操作並不需要在每個主機上都執行,比如說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控制節點或者存儲機器上執行任務。例如:
- hosts: app_servers
tasks:- name: gather facts from db servers
setup:
delegate_to: "{{item}}"
delegate_facts: True
with_items: "{{groups[‘dbservers‘}}"
該例子會收集dbservers的facts並分配給這些機器, 而不會去收集app_servers的facts
- name: gather facts from db servers
6. serial
一般情況下, ansible會同時在所有服務器上執行用戶定義的操作, 但是用戶可以通過serial參數來定義同時可以在多少太機器上執行操作.
- name: test play
hosts: webservers
serial: 3
webservers組中的3台機器完全完成play后, 其他3台機器才會開始執行
7. until
這種循環由三個指令完成:
- until是一個條件表達式,如果滿足條件循環結束
- retry是重試的次數
- delay是延遲時間
示例如下:
- action: shell /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay:
8. wait_for
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/