天天看點

Ansible介紹A list of tasty fruitsAn employee recordAn employee recordansible hostname -m setup

一、簡介

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

  • name: Jenny Smith

    age 13

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放置于{}中進行表示,例如:

{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中使用。例如:

www1.magedu.com http_port=80 maxRequestsPerChild=808

www2.magedu.com http_port=8080 maxRequestsPerChild=909

5.2.3 組變量

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

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

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表達式文法。例如:

  • name: "shutdown Debian flavored systems"

    command: /sbin/shutdown -h now

    when: ansible_os_family == "Debian"

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

  • command: /bin/false

    register: result

  • 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,例如:

  • user: name={{ item.name }} state=present groups={{ item.groups }}
    • { 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

    • 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

      • 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 rel="nofollow" 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 。           
==
    比較兩個對象是否相等。
!=
    比較兩個對象是否不等。
>
    如果左邊大于右邊,傳回 true 。
>=
    如果左邊大于等于右邊,傳回 true 。
<
    如果左邊小于右邊,傳回 true 。
<=
    如果左邊小于等于右邊,傳回 true 。           
and
    如果左操作數和右操作數同為真,傳回 true 。
or
    如果左操作數和右操作數有一個為真,傳回 true 。
not
    對一個表達式取反(見下)。
(expr)
    表達式組。           
上一篇: ansible 介紹
下一篇: Ansible入門