1. 程式人生 > >ansible運維工具(二)

ansible運維工具(二)

包含 example ice 完成 fqdn 模塊 php flavor 主體

ansible playbook(二)

運行palybook時 要使用ansible-playbook命令
palybook執行任務的順序是,在第一個主機上完成第一個任務,然後在第二個主機上完成第一個任務
而不是在第一個主機上完成所有任務,然後再在第二個主機上完成所有任務,以任務為中心,在所有主機上執行
如何構建ansible的playbook
Inventory
Modules
Ad Hoc Commands
PlayBooks
Tasks 任務,及調用某模塊所完成的操作
Variable 變量
Templates 模版
Handlers 處理器,通常指的是在某條件滿足時觸發執行的操作
Roles 角色
如果想說清楚的playbooks,還要額外的了解一些基礎概念

Ansible中使用的YAML基礎元素:
    變量
    Inventory
    條件判斷
    叠代
基本結構

    - hosts: websrvs
      remote_user:
      tasks:
        - name: task1
          module_name:
        - name: task2
          module_name:

    - hosts: dbsrvs

簡單示例1:

- hosts: websrvs
  remote_user: root
  tasks:
    - name: create nginx group
      group: name=nginx system=yes gid=208
    - name: create nginx user
      user: name=nginx uid=208 system=yes group=nginx

- hosts: dbsrvs
  remote_user: root
  tasks:
    - name: copy file to dbsrvs
      copy: src=/etc/inittab dest=/tmp/inittab.ansible

簡單實例2:

- hosts: websrvs
  remote_user: root
  tasks:
    - name: install httpd packege
      yum: name=httpd state=latest
    - name: install configuration file for httpd
      copy: src=conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
    - name: start httpd service
      service: enabled=true name=httpd  state=started

簡單實例3-handler:
當配置文件發生改變時,應該讓服務重啟。那麽重啟服務就要用handler,當這個服務發生變化時使用notify屬性通知要執行的handler裏定義的任務如下:

- hosts: websrvs
  remote_user: root
  tasks:
    - name: install httpd packege
      yum: name=httpd state=latest
    - name: install configuration file for httpd
      copy: src=conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify:
        - restart httpd
    - name: start httpd service
      service: enabled=true name=httpd  state=started
  handlers:
    - name: restart httpd
      service: name=httpd state=restarted
~

簡單實例4-定義變量:

- hosts: websrvs
  remote_user: root
  vars:
    - package: httpd
    - service: httpd
  tasks:
    - name: install httpd packege
      yum: name={{ package }} state=latest
    - name: install configuration file for httpd
      copy: src=conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify:
        - restart httpd
    - name: start httpd service
      service: enabled=true name={{ service }} state=started
  handlers:
    - name: restart httpd
      service: name={{ service }} state=restarted

簡單示例5-使用facts變量:

- hosts: websrvs
  remote_user: root
  tasks:
    - name: copy file
      copy: content= "{{ ansible_all_ipv4_addresses }}" dest=/tmp/vars.ans

同樣在inventory 中為主機 或者主機組定義的變量也可以通過 {{ 變量名 }}直接調用。

簡單示例6-條件判斷語句when:

- hosts: all
  remote_user: root
  vars:
    - username: user10
  tasks:
    - name: create {{ username }} user
      user: name= {{username}}
      when: ansible_fqdn  == ‘node1.my.com‘

簡單示例7-叠代
重復執行同類task時使用
定義循環列表:with_items

    - name: add serveral users
      user: name={{ item }} state=present groups=wheel
      with_items:
        - testuser1
        - testuser2
要安裝多個程序包的時候使用很方便,定義yum
    - apache
    - php
    - mysql-server

註意: with_item中的列表值也可以是字典

    - name add serveral users
      user: name= {{ itesm.name }} state=present groups= {{ item.groups }}
      with_items:
        - { name: ‘testuser1‘, groups: ‘wheel‘ }
        - { name: ‘testuser2‘, groups: ‘root‘ }

比較是用的是,一個tasks下安裝程序包,定義配置文件就可以用yum,和copy

    with_items:
      - { name: apache, conf: conffiles/httpd.conf }
      - { name: php, conf: conffiles/php.ini }
      - { name: mysql-server, conf: conffiles/my.cnf }

模版template 的使用,常用於靜態配置文件中定義變量以及條件語句,一般在ansible中模版文件後綴名為.j2因為使用的是jinjia2模版語言。同時也要安裝python的jinjia2擴展包,對於我們來將最常用的就是變量。
使用舉例:
inventory中定義如下:
[websrvs]
172.16.100.7 http_port=80 maxClients=100
172.16.100.8 http_port=8080 maxClients=200

假如有一個配置文件中關於端口和maxClients配置項更改如下
Server Name {{ ansible_fqdn }}
Listen {{ http_port }}
maxClients {{ maxClients }}
一般都會創建一個名為templates/httpd.conf.j2

接著我們在playbooks就把之前使用copy模塊定義配置文件的地方改用template模塊,如下:

- hosts: websrvs
  remote_user: root
  vars:
    - package: httpd
    - service: httpd
  tasks:
    - name: install httpd packege
      yum: name={{ package }} state=latest
    - name: install configuration file for httpd
      template: src=/root/templates/httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify:
        - restart httpd
    - name: start httpd service
      service: enabled=true name={{ service }} state=started
  handlers:
    - name: restart httpd
      service: name={{ service }} state=restarted

tags的使用
我們前面定義的playbook中有多個tasks,如果我們想單獨運行這個playbook中的某一個task就需要通過tabs來實現。

- hosts: websrvs
  remote_user: root
  vars:
    - package: httpd
    - service: httpd
  tasks:
    - name: install httpd packege
      yum: name={{ package }} state=latest
    - name: install configuration file for httpd
      template: src=/root/templates/httpd.conf dest=/etc/httpd/conf/httpd.conf
      tags:
        - conf
      notify:
        - restart httpd
    - name: start httpd service
      service: enabled=true name={{ service }} state=started
  handlers:
    - name: restart httpd
      service: name={{ service }} state=restarted

使用下面命令,只運行tags為conf的任務

    ansible-playbook apache.yml --tags=‘conf‘

當然可以--tage=‘aa,bb,cc‘指明多個tag

特殊tags
假如有的任務你想只要運行這個playbook(即使指定--tags)就需要執行這個task,那麽就可以使用
tags: always

以上內容就可以滿足我們對ansible的使用了,接來下了解角色的定義,讓我們更方便的使用ansible
我們想讓一批主機完成 一批任務就可以使用playbook進行配置執行。那麽我們想那為什麽還要有role角色這個東西的存在。存在的意義是什麽。這裏我們在playbook已經可以實現為一批主機執行一批任務了,為什麽還要有role角色這個玩意。 那好我們來舉個例子,假如一臺服務器上安裝nginx又安裝了php還安裝了mysql。那麽你可以寫一個playbook的yaml文件,但是我們現在又有一臺主機想只執行 nginx 和php,那麽你怎麽實現。當然可以再次更改playbook,為其添加一個play,但這違背了開發的盡量不寫重復代碼的宗旨。所以你實現的方式很low。那麽這時候你如果想,事先定義了三個角色,一個nginx,php,mysql 在應用到主機上就完美了,那就是roles。

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

一個roles的案例如下所示:
    site.yml
    webservers.yml
    fooservers.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模塊會自動在此目錄中尋找jinjia2模版文件;
handlers目錄: 此目錄中應當包含一個mian.yml文件,用於定義此角色用到的handler,在handler中使用include包含的其它的handler文件也應該位於此目錄;
vars目錄:應當包含一個mian.yml文件,用於定義此角色用到的變量;
meta目錄:應當包含一個main.yml文件,用於定義此角色的特殊設定及其依賴關系,ansible 1.3及其以後的版本才支持;
default目錄: 為當前角色設定變量時使用此目錄,應當包含一個main.yml文件

示例:
1.創建roles目錄
mkdir /root/ansible_playbooks/roles
mkidr -pv /root/ansible_playbooks/roles/{webservers, dbservers}/{tasks, files, templates, handlers, vars, meta}
2. 把要用到的文件放到 files目錄下,把要用到的template文件放到 templates目錄下
3. 在tasks目錄中編輯main.yml
vim /root/ansible_playbooks/roles/webservers/tasks/main.yml
- name: install httpd packeg
yum: name=httpd
- name: install configuration file for httpd
template: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
tags:
- conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{ service }} state=started
這裏指定模版文件的時候,就不用指定目錄來,它會自己去找角色目錄下的template目錄下的文件
4. 這裏我們用到了notify,也就是說我們需要定義handlers,接下來

    vim /root/ansible_playbooks/roles/webservers/handlers/main.yml
      - name: restart httpd
      service: name={{ service }} state=restarted

5. 如果想定義變量
    vim /root/ansible_playbooks/roles/webservers/vars/main.yml
        - http_port: 80
        - service: httpd
        - maxclients: 200
6. 這樣我們就定義了webservers 這個角色,將來我們想要調用這個角色,需要在roles這個目錄的同級目錄下有site.yml文件
vim site.yml
- hosts: websrvs
  remote_user: root
  roles:
    - webservers

至此 我們ansible-playbook site.yml
為了體現這個roles的靈活性:
vim site.yml
- hosts: 172.16.100.7
remote_user: root
roles:
- webservers

- hosts: 172.16.100.8
  remote_user: root
  roles:
    - dbservers

- hosts: 172.16.100.9
  remote_user: root
  roles:
    - webservers
    - dbservers





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

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

也是用於在不同主機之間共享數據時,能夠通過某種特定形式描述數據本身結構的一種數據組織形式。不同xml的是,yaml通過使用鍵值對+縮進的形式表示的

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 dictionay
字典通過key與value進行標示, 例如:
---
# An employee record
name: Examle Developer
job: Developer
skill: Elite

也可以將key:value 放置於{}中進行表示,例如:
---
# An employee record
{name: Examle 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 通過role傳遞變量
當給一個主機應用角色的時候可以傳遞變量, 然後在角色內使用這些變量,示例如下:
    - 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.mageedu.com

[webserver]
www1.my.com:2222
www2.my.com

[dbserver]
db1.my.com
db2.my.com
db3.my.com

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

[webservers]
www[01:10].my.com
[databases]
db-[a:f].my.com

5.2.2主機變量

可以在inventory中定義主機時為其添加主機變量以便與在playbook中使用,例如:
[webservers]
www1.my.com http_port=80 maxRequestsPerChild=808
www1.my.com http_port=8080 maxRequestsPerChild=909

5.2.3組變量

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

[webservers]
www1.my.com
www2.my.com

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

5.2.4 組嵌套
inventory 中,組還可以包含其他組,並且也可以向組中的主機指定變量,不過,這些變量只能在ansible-playbook中使用,而ansible不支持,例如:
[apache]
http1.my.com
http2.my.com

[nginx]
ngx1.my.com
ngx2.my.com

[webservers:children]
apache
nginx

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

5.2.5 inventory參數
ansible基於ssh連接inventory中指定的遠程主機時,還可以通過參數指定其交互方式;這些參數如下所示:
[webservers]
172.16.100.7 ansible_ssh_user=root ansible_ssh_pass=mypasswd ansible_ssh_port=12008


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

    tasks:
      - name: "shutdown Debian flavored systems"
      command: /sbin/shutdown -h now
      when: ansible_os_family == ‘Debian‘
when語句中還可以使用jinjia2的大多"filter", 例如要忽略此前某語句的錯誤並基於其結果<failed或者sucess> 運行後面指定的語句,可使用類似如下形式:

    tasks:
        - command: /bin/false
          register: result
          ignore_errors; True
        - command: /bin/something
          when: result|failed
        - command: /bin/somethin_else
          when: result|skipped
   此外,when 語句中還可以使用facts或playbook中定義的變量
5.4 叠代,其實就表示循環

當有需要重復性執行的任務時,可以使用叠代機制,其使用格式為將需要叠代的內容定義為item變量引用,並通過with_items 語句來指明叠代的元素列表即可
- 例如:

    - name: add serveral 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 serveral users
      user: name= {{ itesm.name }} state=present groups= {{ item.groups }}
      with_items:
        - { name: ‘testuser1‘, groups: ‘wheel‘ }
        - { name: ‘testuser2‘, groups: ‘root‘ }

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

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

- 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: retart apache
      service: name=httpd state=restarted

7.1 palybook的基礎組件
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: ted1
tasks:
- name: test connection
ping:
remote_user: ted2
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
          sehll: /usr/bin/somecommand|| /bin/true

或者使用ignore_errors來忽略錯誤信息:(即使運行有錯誤,不管他繼續執行其他tasks)

    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=mamcached state=restarted
- name: restart apache
service: name=apache state=restarted

示例:
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: install httpd packege
          yum: name=httpd state=latest
        - name: install configuration file for httpd
          copy: src=conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
          notify:
            - restart httpd
        - name: start httpd service
          service: enabled=true name=httpd  state=started
      handlers:
        - name: restart httpd
          service: name=httpd state=restarted

ansible運維工具(二)