一個完整的程序開發流程少不了部署發佈這個環節,而部署發佈是一個重複的過程,最基本的操做包含中止系統服務、更新軟件包、重啓系統服務,複雜的還須要作好監控、灰度發佈、回滾等。在只有少許服務器的狀況下,大多數運維人員會選擇手動更新,減小自動化部署發佈的開發成本。而當服務器數量增長,甚至服務器可能存在於跨地域的不一樣機房狀況下,如何減小部署發佈的人力和時間成本,實現自動化部署發佈和無縫發佈,並且在部署發佈期間仍然可以正常提供服務,就成爲一個相當重要的問題。 python
在咱們發佈風控情報服務的時候,就遇到了自動化部署發佈的問題。因爲風控服務在用戶場景中處於很是重要的地位,對SLA要求極高,須要提供毫秒級別的訪問質量,爲了達到這一點,消除掉公網的消耗,須要支持多機房服務,而同時帶來的問題就是,如何保持各機房的軟件版本統一,可以作到快速的統一發布、運維,則成爲了一大難題。nginx
目前自動化部署發佈領域已經有了比較成熟的方案,中小公司會維護一些自動化腳本或開源軟件,而大公司因爲複雜的網絡環境更多會選擇維護一套專屬的部署發佈系統。而在咱們這樣的創業型公司,爲了減小人力資源成本,首先選擇的成熟的開源軟件。git
咱們本身的項目後端開發語言爲Python,目前主流的開源自動化配置工具備puppet、ansible、saltstack等,ansible和saltstack是基於Python開發,可以很好的支持Python程序發佈。在服務器數量很少,不須要考慮大規模併發性能的狀況下,咱們對比了ansible和saltstack,最終選用了ansible做爲部署發佈工具。github
1.通信方式
ansible 無需安裝服務端和客戶端,管理機經過ssh協議將命令推送到服務器端執行,只須要管理機上安裝ansible,便可實現統一管理,同時ansible也支持使用ZeroMQ、Kerberos、LDAP等方式推送命令。而saltstack須要分別安裝master和minion,master和minion之間能夠經過ZeroMQ、RAET消息隊列進行通訊,salt在升級時,master版本需向後兼容,minion版本不能高於master。web
2.響應速度
saltstack的master和minion是經過ZeroMQ推送命令,而ansible經過標準ssh推送命令,ZeroMQ的傳輸速度比標準SSH鏈接會快不少,在大規模服務器併發的狀況下,saltstack執行效率會比ansible好,而在通常的運維場景下,ansible能夠知足需求。docker
3.二次開發
ansible和saltstack是基於Python開發,支持使用Python進行二次開發。ansible 附帶不少能夠直接在遠端主機或者經過Playbooks執行的模塊,用戶能夠開發本身的模塊或者插件,而saltstack也有一些預裝的formulas,一樣能夠執行自定義的formula,而他們都覆蓋了經常使用的軟件模塊,如文件傳輸、web服務器、MySQL命令等。apache
4.安全性
ansible使用標準ssh協議通信,標準ssh是加密傳輸,而且遠程服務器不須要運行守護進程,使得遠程服務器不容易受到攻擊。而saltstack雖然能夠經過數據加密方法配置數據傳輸加密方式,可是遠程服務器必須運行守護進程,暴露了可攻擊的點。json
在綜合考慮了上述幾點,結合了項目特色,在不須要維護大規模服務器的狀況下,且項目遠程服務器部署在公有云上,須要經過訪問接口完成服務器的拉出集羣、拉入集羣操做,咱們選用了ansible,開發插件簡單,只須要維護一臺能夠鏈接到全部遠程服務器的管理機,儘可能避免暴露網絡端口減小被攻擊的可能性,而且執行效率能夠知足需求。後端
上圖爲ansible的基礎架構圖,其由如下部分組成:centos
ansible:核心
core modules:ansible自帶的核心模塊
custom modules:自定義模塊
plugins:ansible插件,包括郵件插件、日誌插件、鏈接插件等
playbooks:劇本,ansible配置、部署、編排語言,定義主機執行的task集合
host inventory:ansible管理遠程主機和組之間的關係清單,記錄主機ssh端口、帳號密碼等
在管理主機上,ansible模塊經過標準ssh協議(ZeroMQ、Kerberos)執行inventory文件中的主機對應的playbook task集合。
ansible
核心命令,用於執行ad-hoc命令,既單條命令,能夠經過ansible -h得到幫助。
ansible-doc
該命令用於查看模塊信息,參數-l能夠列出全部已安裝的模塊,參數-s能夠查看具體某個模塊的用戶,如想查詢ping模塊的相關信息。
$ ansible-doc ping
PING
A trivial test module, this module always returns pong' on successful contact. It does not make sense in playbooks, but it is useful from
/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.
EXAMPLES:
ansible webservers -m ping
MAINTAINERS: Ansible Core Team, Michael DeHaan
ansible-galaxy
用於從官方站點下載第三方擴展模塊,相似於centos的yum、Python的pip指令。
ansible-playbook
該命令是使用最多的命令,經過讀取playbook文件,執行相應的操做。
ansible-vault
配置文件中若是包含密碼等敏感信息,能夠經過ansible-vault加密、解密文件。
官方提供了多種安裝方式,可從github的ansible project下載源碼編譯安裝,也可經過yum、apt-get指令安裝,這裏僅介紹經過pip安裝ansible,其餘可參考官方網站。
$ sudo pip install ansible
爲了不在創建ssh鏈接時,重複輸入密碼,能夠設置遠程主機免密碼登陸。
$ ssh-keygen –t rsa –P " $ ssh-copy-id -i ~/.ssh/id_rsa.pub user@remote_host
編輯(或建立)/etc/ansible/hosts文件,並在其中加入遠程主機,例:192.168.1.2
$ ansible all -m ping 192.168.1.2 | SUCCESS => { "changed": false, "ping": "pong" }
/etc/ansible/hosts文件格式與ini配置文件相似,能夠指定鏈接方式,也能夠指定鏈接用戶名。同時,再分配變量時,能夠指定主機分配變量,也能夠指定組分配變量。變量能夠在多個地方定義,有優先級的差異。例如如下代碼顯示。
mail.example.com [webservers] foo.example.com bar.example.com [databases] localhost ansible_connection=local other1.example.com ansible_connection=ssh ansible_ssh_user=mpdehaan other2.example.com ansible_connection=ssh ansible_ssh_user=mdehaan [raleigh] host1 http_port=80 maxRequestsPerChild=808 host2 http_port=303 maxRequestsPerChild=909 [atlanta] host1 host2 [atlanta:vars] ntp_server=ntp.atlanta.example.com proxy=proxy.atlanta.example.com
playbooks的文件格式爲yaml,遠程主機被定義成不一樣角色,每一個角色須要根據playbook中不一樣的task執行不一樣的指令,好比一組主機在inventory文件中被定義成webservers,則可能會執行web服務器重啓等操做。
以下playbook,執行一組定義爲webservers的主機,使用root帳號登陸,而且定義了http_port、max_clients變量,會執行三個task,分別爲安裝最新hhtpd服務、拷貝/srv/httpd.j2文件到遠程主機的/etc/httpd.conf、重啓httpd服務。’notify‘ action表示在playbook每個task結束時被觸發,只會被觸發一次。handlers是一些task列表,經過名字引用。則該playbook中,配置文件拷貝結束後,執行'restart apache' task。
--- - hosts: webservers vars: http_port: 80 max_clients: 200 remote_user: root tasks: - name: ensure apache is at the latest version yum: pkg=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 service: name=httpd state=started handlers: - name: restart apache service: name=httpd state=restarted
簡要說明下咱們的項目如何使用ansible實現了多個環境的自動化部署發佈。
├── group_vars │ ├── all │ ├── production │ │ ├── build_server.yml │ │ ├── web_server_bj.yml │ │ └── web_server_sh.yml │ └── staging │ ├── build_server.yml │ ├── web_server_bj.yml │ └── web_server_sh.yml ├── library │ ├── slb_op.py ├── roles │ ├── build │ │ └── tasks │ │ └── main.yml │ └── publish │ ├── tasks │ │ └── main.yml │ └── templates │ ├── config.conf │ ├── nginx.conf │ └── supervisord.conf ├── production ├── production.yml ├── staging └── staging.yml
如上目錄結構,是目前ansible比較受歡迎的實現方式。例如項目有生產和測試環境,則分爲兩個inventory文件,分別爲production、staging,inventory文件中定義對應環境的服務器所在的組,以staging爲例,web_server_sh、web_server_bj表示兩個機房的主機,build_server爲打包機器。
[web_server_sh] 192.168.0.2 [web_server_bj] 192.168.0.3 [build_server] localhost ansible_connection=local
而每一個inventory對應的playbook則爲production.yml、staging.yml,指定不一樣的組須要執行的角色task。以staging.yml爲例,build_server組的主機須要執行build角色的task,而且變量文件爲
group_vars/staging/build_server.yml,而web_server_sh、web_server_bj組的主機須要執行publish角色的task,而且指定變量文件不相同。
--- - hosts: build_server serial: 1 vars_files: - group_vars/staging/build_server.yml roles: - build - hosts: web_server_sh remote_user: root serial: 1 vars_files: - group_vars/staging/web_server_sh.yml roles: - publish - hosts: web_server_bj remote_user: root serial: 1 vars_files: - group_vars/staging/web_server_bj.yml roles: - publish
library目錄則爲自定義插件,可直接在playbook中使用,slb_op.py爲自定義的集羣拉入拉出模塊。
ansible 很好的幫助了咱們解決了自動化部署發佈的事情,如今項目同步更新到幾個機房,已經只須要幾分鐘就能夠完成,節省了許多人力。
在部署發佈工具的選擇上,工具沒有好壞,應該結合自身項目來選擇,都可以很好地提升工做效率。
ansible解決了燃眉之急,而目前已經很好地與jenkins、docker結合,當集羣數量愈來愈多,愈來愈難以維護時,是否須要更換工具,或是結合最新技術,都是一個考驗的難題。
做者 葉柴柴 豈安科技軟件工程師 負責豈安科技業務風險分析平臺後臺開發。鏟屎官裏會寫代碼的,寫代碼裏會鏟屎的,一個愛柯基、愛Python、愛生活的鏟屎官。