Ansible介紹

一、簡介

Ansible is a radically simple configuration-management, application deployment, task-execution, and multinode orchestration engine.

Design Principles

Have a dead simple setup process and a minimal learning curve
Be super fast & parallel by default
Require no server or client daemons; use existing SSHd
Use a language that is both machine and human friendly
Focus on security and easy auditability/review/rewriting of content
Manage remote machines instantly, without bootstrapping
Allow module development in any dynamic language, not just Python
Be usable as non-root
Be the easiest IT automation system to use, ever.

二、安裝

ansible依賴於Python 2.6或更高的版本、paramiko、PyYAML及Jinja2。

2.1 編譯安裝

解決依賴關係

#yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto
#tar xf ansible-1.5.4.tar.gz
#cd ansible-1.5.4
#python setup.py build
#python setup.py install
#mkdir /etc/ansible
#cp -r examples/* /etc/ansible

2.2 rpm包安裝
#yum install ansible

注意:不同版本的ansible的功能差異可能較大。

三、簡單應用

ansible通過ssh實現配置管理、應用部署、任務執行等功能,因此,需要事先配置ansible端能基於密鑰認證的方式聯繫各被管理節點。

ansible <host-pattern> [-f forks] [-m module_name] [-a args]
-m module:默認爲command

ansible-doc: Show Ansible module documentation
-l, --list List available modules
-s, --snippet Show playbook snippet for specified module(s)

四、YAML

4.1 YAML介紹

YAML是一個可讀性高的用來表達資料序列的格式。YAML參考了其他多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822等。Clark Evans在2001年在首次發表了這種語言,另外Ingy döt Net與Oren Ben-Kiki也是這語言的共同設計者。

YAML Ain't Markup Language,即YAML不是XML。不過,在開發的這種語言時,YAML的意思其實是:"Yet Another Markup Language"(仍是一種標記語言)。其特性:

YAML的可讀性好
YAML和腳本語言的交互性好
YAML使用實現語言的數據類型
YAML有一個一致的信息模型
YAML易於實現
YAML可以基於流來處理
YAML表達能力強,擴展性好

更多的內容及規範參見http://www.yaml.org。

4.2 YAML語法

YAML的語法和其他高階語言類似,並且可以簡單表達清單、散列表、標量等數據結構。其結構(Structure)通過空格來展示,序列(Sequence)裏的項用"-"來代表,Map裏的鍵值對用":"分隔。下面是一個示例。

name: John Smith
age: 41
gender: Male
spouse:
name: Jane Smith
age: 37
gender: Female
children:
•name: Jimmy Smith
age: 17
gender: Male
•name: Jenny Smith
age 13
gender: Female

YAML文件擴展名通常爲.yaml,如example.yaml。

4.2.1 list

列表的所有元素均使用“-”打頭,例如:

A list of tasty fruits
•Apple
•Orange
•Strawberry
•Mango

4.2.2 dictionary

字典通過key與value進行標識,例如:

An employee record

name: Example Developer
job: Developer
skill: Elite

也可以將key:value放置於{}中進行表示,例如:

An employee record

{name: Example Developer, job: Developer, skill: Elite}

五、Ansible基礎元素

5.1 變量

5.1.1 變量命名

變量名僅能由字母、數字和下劃線組成,且只能以字母開頭。

5.1.2 facts

facts是由正在通信的遠程目標主機發回的信息,這些信息被保存在ansible變量中。要獲取指定的遠程主機所支持的所有facts,可使用如下命令進行:

ansible hostname -m setup

5.1.3 register

把任務的輸出定義爲變量,然後用於其他任務,示例如下:

tasks:
•shell: /usr/bin/foo
register: foo_result
ignore_errors: True

5.1.4 通過命令行傳遞變量

在運行playbook的時候也可以傳遞一些變量供playbook使用,示例如下:

ansible-playbook test.yml --extra-vars "hosts=www user=mageedu"

5.1.5 通過roles傳遞變量

當給一個主機應用角色的時候可以傳遞變量,然後在角色內使用這些變量,示例如下:

  • hosts: webservers
    roles:
    • common
    • { role: foo_app_instance, dir: '/web/htdocs/a.com', port: 8080 }

5.2 Inventory

ansible的主要功用在於批量主機操作,爲了便捷地使用其中的部分主機,可以在inventory file中將其分組命名。默認的inventory file爲/etc/ansible/hosts。

inventory file可以有多個,且也可以通過Dynamic Inventory來動態生成。

5.2.1 inventory文件格式

inventory文件遵循INI文件風格,中括號中的字符爲組名。可以將同一個主機同時歸併到多個不同的組中;此外,當如若目標主機使用了非默認的SSH端口,還可以在主機名稱之後使用冒號加端口號來標明。

ntp.magedu.com

[webservers]
www1.magedu.com:2222
www2.magedu.com

[dbservers]
db1.magedu.com
db2.magedu.com
db3.magedu.com

如果主機名稱遵循相似的命名模式,還可以使用列表的方式標識各主機,例如:

[webservers]
www[01:50].example.com

[databases]
db-[a:f].example.com

5.2.2 主機變量

可以在inventory中定義主機時爲其添加主機變量以便於在playbook中使用。例如:

[webservers]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909

5.2.3 組變量

組變量是指賦予給指定組內所有主機上的在playboo中可用的變量。例如:

[webservers]
www1.magedu.com
www2.magedu.com

[webservers:vars]
ntp_server=ntp.magedu.com
nfs_server=nfs.magedu.com

5.2.4 組嵌套

inventory中,組還可以包含其它的組,並且也可以向組中的主機指定變量。不過,這些變量只能在ansible-playbook中使用,而ansible不支持。例如:

[apache]
httpd1.magedu.com
httpd2.magedu.com

[nginx]
ngx1.magedu.com
ngx2.magedu.com

[webservers:children]
apache
nginx

[webservers:vars]
ntp_server=ntp.magedu.com

5.2.5 inventory參數

ansible基於ssh連接inventory中指定的遠程主機時,還可以通過參數指定其交互方式;這些參數如下所示:

ansible_ssh_host
The name of the host to connect to, if different from the alias you wish to give to it.
ansible_ssh_port
The ssh port number, if not 22
ansible_ssh_user
The default ssh user name to use.
ansible_ssh_pass
The ssh password to use (this is insecure, we strongly recommend using --ask-pass or SSH keys)
ansible_sudo_pass
The sudo password to use (this is insecure, we strongly recommend using --ask-sudo-pass)
ansible_connection
Connection type of the host. Candidates are local, ssh or paramiko. The default is paramiko before Ansible 1.2, and 'smart' afterwards which detects whether usage of 'ssh' would be feasible based on whether ControlPersist is supported.
ansible_ssh_private_key_file
Private key file used by ssh. Useful if using multiple keys and you don't want to use SSH agent.
ansible_shell_type
The shell type of the target system. By default commands are formatted using 'sh'-style syntax by default. Setting this to 'csh' or 'fish' will cause commands executed on target systems to follow those shell's syntax instead.
ansible_pythoninterpreter
The target host python path. This is useful for systems with more
than one Python or not located at "/usr/bin/python" such as BSD, or where /usr/bin/python
is not a 2.X series Python. We do not use the "/usr/bin/env" mechanism as that requires the remote user's
path to be set right and also assumes the "python" executable is named python, where the executable might
be named something like "python26".
ansible\
_interpreter
Works for anything such as ruby or perl and works just like ansible_python_interpreter.
This replaces shebang of modules which will run on that host.

5.3 條件測試

如果需要根據變量、facts或此前任務的執行結果來做爲某task執行與否的前提時要用到條件測試。

5.3.1 when語句

在task後添加when子句即可使用條件測試;when語句支持Jinja2表達式語法。例如:

tasks:
•name: "shutdown Debian flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "Debian"

when語句中還可以使用Jinja2的大多“filter”,例如要忽略此前某語句的錯誤並基於其結果(failed或者sucess)運行後面指定的語句,可使用類似如下形式:

tasks:
•command: /bin/false
register: result
ignore_errors: True
•command: /bin/something
when: result|failed
•command: /bin/something_else
when: result|success
•command: /bin/still/something_else
when: result|skipped

此外,when語句中還可以使用facts或playbook中定義的變量。

5.4 迭代

當有需要重複性執行的任務時,可以使用迭代機制。其使用格式爲將需要迭代的內容定義爲item變量引用,並通過with_items語句來指明迭代的元素列表即可。例如:
•name: add several users
user: name={{ item }} state=present groups=wheel
with_items: ◦testuser1
◦testuser2

上面語句的功能等同於下面的語句:
•name: add user testuser1
user: name=testuser1 state=present groups=wheel
•name: add user testuser2
user: name=testuser2 state=present groups=wheel

事實上,with_items中可以使用元素還可爲hashes,例如:
•name: add several users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items: ◦{ name: 'testuser1', groups: 'wheel' }
◦{ name: 'testuser2', groups: 'root' }

ansible的循環機制還有更多的高級功能,具體請參見官方文檔(http://docs.ansible.com/playbooks_loops.html)。

七、ansible playbooks

playbook是由一個或多個“play”組成的列表。play的主要功能在於將事先歸併爲一組的主機裝扮成事先通過ansible中的task定義好的角色。從根本上來講,所謂task無非是調用ansible的一個module。將多個play組織在一個playbook中,即可以讓它們聯同起來按事先編排的機制同唱一臺大戲。下面是一個簡單示例。

  • hosts: webnodes
    vars:
    http_port: 80
    max_clients: 256
    remote_user: root
    tasks:
    • name: ensure apache is at the latest version
      yum: name=httpd state=latest
    • name: ensure apache is running
      service: name=httpd state=started
      handlers:
    • name: restart apache
      service: name=httpd state=restarted

7.1 playbook基礎組件

7.1.1 Hosts和Users

playbook中的每一個play的目的都是爲了讓某個或某些主機以某個指定的用戶身份執行任務。hosts用於指定要執行指定任務的主機,其可以是一個或多個由冒號分隔主機組;remote_user則用於指定遠程主機上的執行任務的用戶。如上面示例中的
-hosts: webnodes
remote_user: root

不過,remote_user也可用於各task中。也可以通過指定其通過sudo的方式在遠程主機上執行任務,其可用於play全局或某任務;此外,甚至可以在sudo時使用sudo_user指定sudo時切換的用戶。

- hosts: webnodes
  remote_user: mageedu
  tasks:
    - name: test connection
      ping:
      remote_user: mageedu
      sudo: yes

7.1.2 任務列表和action

play的主體部分是task list。task list中的各任務按次序逐個在hosts中指定的所有主機上執行,即在所有主機上完成第一個任務後再開始第二個。在運行自下而下某playbook時,如果中途發生錯誤,所有已執行任務都將回滾,因此,在更正playbook後重新執行一次即可。

task的目的是使用指定的參數執行模塊,而在模塊參數中可以使用變量。模塊執行是冪等的,這意味着多次執行是安全的,因爲其結果均一致。

每個task都應該有其name,用於playbook的執行結果輸出,建議其內容儘可能清晰地描述任務執行步驟。如果未提供name,則action的結果將用於輸出。

定義task的可以使用“action: module options”或“module: options”的格式,推薦使用後者以實現向後兼容。如果action一行的內容過多,也中使用在行首使用幾個空白字符進行換行。
tasks:

  • name: make sure apache is running
    service: name=httpd state=running

    在衆多模塊中,只有command和shell模塊僅需要給定一個列表而無需使用“key=value”格式,例如:
    tasks:

    • name: disable selinux
      command: /sbin/setenforce 0

    如果命令或腳本的退出碼不爲零,可以使用如下方式替代:
    tasks:

    • name: run this command and ignore the result
      shell: /usr/bin/somecommand || /bin/true

    或者使用ignore_errors來忽略錯誤信息:
    tasks:

    • name: run this command and ignore the result
      shell: /usr/bin/somecommand
      ignore_errors: True

7.1.3 handlers

用於當關注的資源發生變化時採取一定的操作。

“notify”這個action可用於在每個play的最後被觸發,這樣可以避免多次有改變發生時每次都執行指定的操作,取而代之,僅在所有的變化發生完成後一次性地執行指定操作。在notify中列出的操作稱爲handler,也即notify中調用handler中定義的操作。

  • name: template configuration file
    template: src=template.j2 dest=/etc/foo.conf
    notify:
    • restart memcached
    • restart apache

handler是task列表,這些task與前述的task並沒有本質上的不同。
handlers:

  • name: restart memcached
    service: name=memcached state=restarted
  • name: restart apache
    service: name=apache state=restarted

案例:
heartbeat.yaml
•hosts: hbhosts
remote_user: root
tasks: ◦name: ensure heartbeat latest version
yum: name=heartbeat state=present
◦name: authkeys configure file
copy: src=/root/hb_conf/authkeys dest=/etc/ha.d/authkeys
◦name: authkeys mode 600
file: path=/etc/ha.d/authkeys mode=600
notify: ◾restart heartbeat

◦name: ha.cf configure file
copy: src=/root/hb_conf/ha.cf dest=/etc/ha.d/ha.cf
notify: ◾restart heartbeat
handlers:

◦name: restart heartbeat
service: name=heartbeat state=restarted

八、roles

ansilbe自1.2版本引入的新特性,用於層次性、結構化地組織playbook。roles能夠根據層次型結構自動裝載變量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。簡單來講,roles就是通過分別將變量、文件、任務、模板及處理器放置於單獨的目錄中,並可以便捷地include它們的一種機制。角色一般用於基於主機構建服務的場景中,但也可以是用於構建守護進程等場景中。

一個roles的案例如下所示:
site.yml
webservers.yml
dbservers.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
meta/

而在playbook中,可以這樣使用roles:

  • hosts: webservers
    roles:
    • common
    • webservers

也可以向roles傳遞參數,例如:

  • hosts: webservers
    roles:
    • common
    • { role: foo_app_instance, dir: '/opt/a', port: 5000 }
    • { role: foo_app_instance, dir: '/opt/b', port: 5001 }

甚至也可以條件式地使用roles,例如:

  • hosts: webservers
    roles:
    • { role: some_role, when: "ansible_os_family == 'RedHat'" }

8.1 創建role的步驟

(1) 創建以roles命名的目錄;
(2) 在roles目錄中分別創建以各角色名稱命名的目錄,如webservers等;
(3) 在每個角色命名的目錄中分別創建files、handlers、meta、tasks、templates和vars目錄;用不到的目錄可以創建爲空目錄,也可以不創建;
(4) 在playbook文件中,調用各角色;

8.2 role內各目錄中可用的文件

tasks目錄:至少應該包含一個名爲main.yml的文件,其定義了此角色的任務列表;此文件可以使用include包含其它的位於此目錄中的task文件;
files目錄:存放由copy或script等模塊調用的文件;
templates目錄:template模塊會自動在此目錄中尋找Jinja2模板文件;
handlers目錄:此目錄中應當包含一個main.yml文件,用於定義此角色用到的各handler;在handler中使用include包含的其它的handler文件也應該位於此目錄中;
vars目錄:應當包含一個main.yml文件,用於定義此角色用到的變量;
meta目錄:應當包含一個main.yml文件,用於定義此角色的特殊設定及其依賴關係;ansible 1.3及其以後的版本才支持;
default目錄:爲當前角色設定默認變量時使用此目錄;應當包含一個main.yml文件;

九、Tags

tags用於讓用戶選擇運行playbook中的部分代碼。ansible具有冪等性,因此會自動跳過沒有變化的部分,即便如此,有些代碼爲測試其確實沒有發生變化的時間依然會非常地長。此時,如果確信其沒有變化,就可以通過tags跳過此些代碼片斷。

十、Jinja2相關

10.1 字面量
表達式最簡單的形式就是字面量。字面量表示諸如字符串和數值的 Python 對象。下面 的字面量是可用的:

“Hello World”:
雙引號或單引號中間的一切都是字符串。無論何時你需要在模板中使用一個字 符串(比如函數調用、過濾器或只是包含或繼承一個模板的參數),它們都是 有用的。

42 / 42.23:
直接寫下數值就可以創建整數和浮點數。如果有小數點,則爲浮點數,否則爲 整數。記住在 Python 裏, 42 和 42.0 是不一樣的。

[‘list’, ‘of’, ‘objects’]:
一對中括號括起來的東西是一個列表。列表用於存儲和迭代序列化的數據。例如 你可以容易地在 for 循環中用列表和元組創建一個鏈接的列表:

<ul>
{% for href, caption in [('index.html', 'Index'), ('about.html', 'About'),
('downloads.html', 'Downloads')] %}
<li><a href="{{ href }}">{{ caption }}</a></li>
{% endfor %}
</ul>

(‘tuple’, ‘of’, ‘values’):
元組與列表類似,只是你不能修改元組。如果元組中只有一個項,你需要以逗號 結尾它。元組通常用於表示兩個或更多元素的項。更多細節見上面的例子。

{‘dict’: ‘of’, ‘key’: ‘and’, ‘value’: ‘pairs’}:
Python 中的字典是一種關聯鍵和值的結構。鍵必須是唯一的,並且鍵必須只有一個 值。字典在模板中很少使用,罕用於諸如 xmlattr() 過濾器之類。

true / false:
true 永遠是 true ,而 false 始終是 false 。

10.2 算術運算

Jinja 允許你用計算值。這在模板中很少用到,但是爲了完整性允許其存在。支持下面的 運算符:

+
把兩個對象加到一起。通常對象是素質,但是如果兩者是字符串或列表,你可以用這 種方式來銜接它們。無論如何這不是首選的連接字符串的方式!連接字符串見 ~ 運算符。 {{ 1 + 1 }} 等於 2 。

用第一個數減去第二個數。 {{ 3 - 2 }} 等於 1 。

/
對兩個數做除法。返回值會是一個浮點數。 {{ 1 / 2 }} 等於 {{ 0.5 }} 。
//
對兩個數做除法,返回整數商。 {{ 20 // 7 }} 等於 2 。
%
計算整數除法的餘數。 {{ 11 % 7 }} 等於 4 。

用右邊的數乘左邊的操作數。 {{ 2
2 }} 會返回 4 。也可以用於重 復一個字符串多次。 {{ ‘=’ * 80 }} 會打印 80 個等號的橫條。

取左操作數的右操作數次冪。 {{ 2
3 }} 會返回 8 。

10.3 比較操作符

==
比較兩個對象是否相等。
!=
比較兩個對象是否不等。

如果左邊大於右邊,返回 true 。

如果左邊大於等於右邊,返回 true 。
<
如果左邊小於右邊,返回 true 。
<=
如果左邊小於等於右邊,返回 true 。

10.4 邏輯運算符

對於 if 語句,在 for 過濾或 if 表達式中,它可以用於聯合多個表達式:

and
如果左操作數和右操作數同爲真,返回 true 。
or
如果左操作數和右操作數有一個爲真,返回 true 。
not
對一個表達式取反(見下)。
(expr)
表達式組。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章