自動化運維工具Ansible之Playbooks的roles和include

當需要對多個遠程節點,做很多操作的時候,如果將所有的內容都書寫到一個playbooks中,這就會產生一個很大的文件,而且裏面的某些內容也很難複用。此時不得不考慮怎麼樣分隔及組織相關的文件。


最基本的,可以將任務列表單獨分隔到一個小文件裏,然後在tasks中包含該文件即可。同樣的handlers其實也是一個任務列表(裏面指定的任務都需要有一個全局唯一的名稱),所以也可以在handlers中包含單獨定義好的handlers任務文件。


playbooks也可以包含其他playbooks文件。


playbooks中的文件包含使得你在大多數情況下並不需要考慮具體功能的實現細節,只需要複用某些已有的文件即可,類似於編程中的封裝概念一樣,當某個功能封裝並測試OK以後,在需要的地方調用即可,如,一個人會開車,但他並不需要了解發動機的原理是什麼。


Ansible中的“角色”就是利用文件包含這個功能來使得文件組織的更加清晰明瞭,並具有很高的複用性。


任務文件包含和重用


如果想在多個playbooks之間服用任務列表,那麼include將會是個很好的方法。


官方示例的一個很小的任務列表文件:


 

    ---
    # possibly saved as tasks/foo.yml
    
    - name: placeholder foo
      command: /bin/foo
    
    - name: placeholder bar
      command: /bin/bar

在playbooks中包含該文件:


tasks:
    
      - include: tasks/foo.yml


同時也可以向包含文件內傳遞參數,稱爲“參數化包含”。


例如,想要部署多個wordpress,可以將部署操作寫到一個文件中,保存爲wordpress.yml,然後以下邊這樣包含文件並傳遞參數:

    tasks:
      - include: wordpress.yml wp_user=timmy
      - include: wordpress.yml wp_user=alice
      - include: wordpress.yml wp_user=bob

在wordpress.yml可以` wp_user `的方式使用變量。


還可以傳遞一個參數列表:


    tasks:
     - { include: wordpress.yml, wp_user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] }

以上兩種傳遞參數都稱爲顯式傳參,在vars中定義的變量特可以在被包含文件中使用。


也可以在handlers中包含文件。如,想要定義一個重啓apache的handler,這時候只需要爲所有的playbooks定義一個handler即可,保存爲handlers.yml:

     ---
    # this might be in a file like handlers/handlers.yml
    - name: restart apache
      service: name=httpd state=restarted


在playbooks中包含該文件:


    handlers:
      - include: handlers/handlers.yml


還可以將一個playbooks文件導入到另外一個playbooks中,這樣的話,只需要定義一個頂級的且內容爲一些較爲通用的操作的playbooks文件,然後再文件中包含其他的playbooks即可。

     - name: this is a play at the top level of a file
      hosts: all
      remote_user: root
    
      tasks:
    
      - name: say hi
        tags: foo
        shell: echo "hi..."
    
    - include: load_balancers.yml
    - include: webservers.yml
    - include: dbservers.yml


示例:


[root@web1 ansible]# tree /etc/ansible/
    /etc/ansible/
    ├── handlers
    │   └── restart.yml
    ├── hosts
    ├── main.yml
    ├── tasks
    │   └── apache.yml
    └── templates
        └── httpd.j2
    [root@web1 ansible]# cat tasks/apache.yml 
    ---
    - name: config httpd.file
      template: src=templates/httpd.j2 dest=/etc/httpd.conf
    [root@web1 ansible]# cat handlers/restart.yml 
    ---
    - name: restart apache
      service: name=httpd state=restarted
    [root@web1 ansible]# cat main.yml 
    ---
    - hosts: webservers
      remote_user: root
      vars:
        http_port: 8085
        max_clients: 123
      
      tasks:
        - include: tasks/apache.yml
        
      handlers:
        - include: handlers/restart.yml
    [root@web1 ansible]# ansible-playbook /etc/ansible/main.yml 
    
    PLAY [webservers] ************************************************************* 
    
    GATHERING FACTS *************************************************************** 
    ok: [192.168.1.65]
    
    TASK: [config httpd.file] ***************************************************** 
    changed: [192.168.1.65]
    
    PLAY RECAP ******************************************************************** 
    192.168.1.65               : ok=2    changed=1    unreachable=0    failed=0


注:上邊文件雖然定義幷包含了重啓apache的handler,但並沒有任務一個任務來觸發該handler。所以並沒有執行重啓操作,即使配置文件發生了改變。


角色


“文件包含”本身只是很簡單且很單純的包含各個子文件,當文件較多的時候,其組織方式也並是好,且需要人爲的來指定包含哪些文件。Ansible中的“角色”會基於已知的文件結構來自動加載特定的變量文件、任務文件一級handlers文件,使用角色來組織內容可以更好的實現共享。


官方的一個使用角色組織內容的文件結構:


 

    site.yml
    webservers.yml
    fooservers.yml #playbooks文件,最後ansible執行的就是這些文件
    roles/
       common/
         files/
         templates/ #保存操作中所需要的模板文件
         tasks/ #保存任務列表文件
         handlers/ #保存handler文件
         vars/ #保存定義變量的文件
         defaults/ #默認變量文件
         meta/ #角色的依賴關係
       webservers/
         files/
         templates/
         tasks/
         handlers/
         vars/
         defaults/
         meta/


在playbooks中這樣書寫內容,如上邊的webservers.yml文件:

     ---
     - hosts: webservers
      roles:
         - common
         - webservers


每個角色都會遵循以下原則:


  1. 如果`roles/x/tasks/main.yml`存在,裏面的任務列表會被添加到`play`中。

  2. 如果`roles/x/handlers/main.yml`存在,裏面的`handlers`會被添加到`play`中。

  3. 如果`roles/x/vars/main.yml`存在,裏面的變量會被添加到`play`中。

  4. 如果`roles/x/meta/main.yml`存在,裏面的角色依賴會被添加到角色列表中。

  5. `roles/x/files`任務所需要被複制的文件,無需絕對路徑或者相對路徑都可以引用該文件。

  6. `roles/x/files`中的任務腳本都可以直接使用該文件,無需指定絕對路徑或者是相對路徑。

  7. `roles/x/templates`中的模板,無需指定絕對路徑或者相對路徑,都可以直接使用文件名引用該文件。

  8. 需要包含在`roles/x/tasks`中的任務文件時,無需指定絕對路徑或者相對路徑,可以直接使用文件名包含。


tasks,handlers,vars,meta目錄下main.yml中的內容都會被自動調用。


 如果某些文件不存在的話,將會自動跳過,所以`vars/`之類的子目錄如果用不到的話也可以不創建。


也可以給角色傳遞參數,在playbooks文件定義:

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


有時候也可以給角色添加執行條件:

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

當遠程節點的操作系統爲RedHat的時候纔會執行"some_role"中的操作。


如果在某個play中定義了一個tasks任務塊,它將會在橘色執行完成後再執行。


定義在角色執行之前或者執行後需要執行的任務:

    ---
    
    - hosts: webservers
    
      pre_tasks:
        - shell: echo 'hello'
    
      roles:
        - { role: some_role }
    
      tasks:
        - shell: echo 'still busy'
    
      post_tasks:
        - shell: echo 'goodbye'


示例:


   

[root@web1 ~]# tree /etc/ansible/
    /etc/ansible/
    ├── hosts
    ├── roles
    │   └── webservers
    │       ├── defaults
    │       ├── files
    │       ├── handlers
    │       │   ├── main.yml
    │       │   └── restart.yml
    │       ├── meta
    │       ├── tasks
    │       │   ├── apache.yml
    │       │   └── main.yml
    │       ├── templates
    │       │   └── httpd.j2
    │       └── vars
    │           └── main.yml
    └── webservers.yml
    
    [root@web1 ~]# cat /etc/ansible/roles/webservers/tasks/main.yml 
    ---
    - include: apache.yml
    [root@web1 ~]# cat /etc/ansible/roles/webservers/tasks/apache.yml 
    ---
    - name: config httpd.file
      template: src=httpd.j2 dest=/etc/httpd.conf
      notify:
        - restart apache
    [root@web1 ~]# cat /etc/ansible/roles/webservers/handlers/main.yml 
    ---
    - include: restart.yml
    [root@web1 ~]# cat /etc/ansible/roles/webservers/handlers/restart.yml 
    ---
    - name: restart apache
      service: name=httpd state=restarted
    [root@web1 ~]# cat /etc/ansible/roles/webservers/vars/main.yml 
    ---
    http_port: 8099
    max_clients: 321

    [root@web1 ansible]# ansible-playbook /etc/ansible/webservers.yml
    
    PLAY [webservers] ************************************************************* 
    
    GATHERING FACTS *************************************************************** 
    ok: [192.168.1.65]
    
    TASK: [webservers | config httpd.file] **************************************** 
    changed: [192.168.1.65]
    
    NOTIFIED: [webservers | restart apache] *************************************** 
    changed: [192.168.1.65]
    
    PLAY RECAP ******************************************************************** 
    192.168.1.65               : ok=3    changed=2    unreachable=0    failed=0


有些子目錄並沒有使用到,如meta目錄,就可以不用創建。


角色依賴


 角色依賴使得當使用某個角色的時候自動將其他角色導入。角色依賴保存在角色目錄下的`meta/main.yml`文件中,該文件包含一個角色和參數的列表,這些內容會在某個特定的角色之前插入。即在某個特定的角色執行之前會先執行其依賴。


     ---
    dependencies:
      - { role: common, some_parameter: 3 }
      - { role: apache, port: 80 }
      - { role: postgres, dbname: blarg, other_parameter: 12 }

也可以以絕對路徑的方式定義:

     ---
    dependencies:
       - { role: '/path/to/common/roles/foo', x: 1 }

 角色依賴總在包含它們的角色執行之前而執行,而且是遞歸執行。默認情況下,角色也只能作爲一個依賴關係添加一次,如果另一個角色也將它列爲一個依賴關係,它將不再運行。但是在`meta/main.yml`設置`allow_duplicates: yes`,可以突破這個限制。如一個稱爲`car`的角色需要添加一個名爲`wheel`的角色作爲它的依賴:

    ---
    dependencies:
    - { role: wheel, n: 1 }
    - { role: wheel, n: 2 }
    - { role: wheel, n: 3 }
    - { role: wheel, n: 4 }

meta/main.yml內容:

    ---
    allow_duplicates: yes
    dependencies:
    - { role: tire }
    - { role: brake }

 執行的結果會是類似下邊這樣:

    tire(n=1)
    brake(n=1)
    wheel(n=1)
    tire(n=2)
    brake(n=2)
    wheel(n=2)
    ...
    car


總結:

角色和文件包含,在平時的運維工作中會經常使用到,而且使得文件組織更加清晰,複用性較高。可以對遠程節點主機進行大量且複雜有序的操作。

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