天天看點

Ansible詳解(三)

一、template模闆

二、playbook中的條件判斷

三、PlayBook中的循環

四、角色(roles)

template使用了Jinjia2格式作為檔案模版,進行文檔内變量的替換的子產品。它的每次使用都會被ansible标記為”changed”狀态。基于模闆方式生成一個檔案複制到遠端主機

常用參數:

<code>參數名     是否必須     預設值     選項     說明</code>

<code>backup     no         no     </code><code>yes</code><code>/no</code>     <code>建立個包括timestamp在内的檔案備份,以備不時之需.</code>

<code>dest     </code><code>yes</code>             <code>遠端節點上的絕對路徑,用于放置template檔案。</code><code>//</code><code>必須是絕對路徑</code>

<code>group     no             設定遠端節點上的的template檔案的所屬使用者組</code>

<code>mode     no             設定遠端節點上的template檔案權限。類似Linux中</code><code>chmod</code><code>的用法 </code><code>//group</code><code>,owner</code>

<code>owner     no             設定遠端節點上的template檔案所屬使用者</code>

<code>src     </code><code>yes</code>             <code>本地Jinjia2模版的template檔案位置。 </code><code>//</code><code>絕對或者相對路徑</code>

一般程式設計語言都有把自己嵌入到文本的模闆語言

    php:直接嵌入

    python:Jinja2 //ansible就是python寫的

Jinja2 中常用的程式設計元素

    字面量:字元串,單引号或者雙引号引用即可

        數字:整數和浮點數

        清單:[item1,item2,...]

        元祖:(item1,itme2,...) //不可變

        字典:{key1:value1,key2:value2,...}

        布爾型:true/false

    算數運算:

        +,-,*,/,%, //,**     //:表示隻要熵

    比較運算:

        ==,!=,&gt;=,&lt;=,&lt;,

        邏輯運算符:

            and,or,not

ansible-doc -s template 

利用模闆:實作對不同主機的nginx配置成不同的啟動processor

    vim nginx.conf.j2

        worker_processes {{ ansible_processor_vcpus }}; //使用模闆變量

        listen {{ http_port }};  //自定義變量

    注:這個參數是在setup模闆中

        worker_processes {{ ansible_processor_vcpus-1 }}; //可以直接增加或減去

    template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf mode=0644

    template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=bin group=wheel mode="u=rw,g=r,o=r"

vim ansible/hosts

    [websrvs]

    192.168.4.100 http_port=888

    192.168.4.116 http_port=808  //使用主機變量

[root@localhost ~]# cat nginx.yaml 

<code>- hosts: websrvs</code>

<code>  </code><code>remote_user: root</code>

<code>  </code><code>tasks:</code>

<code>  </code><code>- name: install nginx</code>

<code>    </code><code>yum: name=nginx state=present</code>

<code>  </code><code>- name: install conf</code>

<code>    </code><code>template</code><code>: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf mode=0644</code>

<code>    </code><code>notify: restart nginx</code>

<code>    </code><code>tags: instconf</code>

<code>  </code><code>- name: start nginx service </code>

<code>    </code><code>service: name=nginx state=started</code>

<code>  </code><code>handlers:</code>

<code>  </code><code>- name: restart nginx</code>

<code>    </code><code>service: name=nginx state=restarted</code>

ansible-playbook --check nginx.yaml

ansible-playbook  nginx.yaml

    注意:6和7的配置nginx配置檔案不一樣

    執行結果

RUNNING HANDLER [restart nginx]

************************************************

changed: [192.168.4.110]  //發生改變的話,就會執行 restart nginx

changed: [192.168.4.106]

handlers:用于當關注的資源發生變化時觸發一定的操作。

    “notify”這個action可用于在每個play的最後被觸發,這樣可以避免多次有改變發生時每次都執行指定的操作

    取而代之,僅在所有的變化發生完成後一次性地執行指定操作。在notify中列出的操作稱為handler,也即notify中調用handler中定義的操作。

多個條件:and/when/or

1.條件測試:tasks上使用when語句,在tasks上使用,Jinja2的文法格式。根據不同的OS配置設定不同的機制

    字元串要加引号{單雙都可},數值一定不加引号

ansible all -m setup | grep "ansible_distribution" //版本資訊

    "ansible_distribution": "CentOS", 

    "ansible_distribution_major_version": "6", 

    "ansible_distribution_release": "Final", 

    "ansible_distribution_version": "6.6",        

    tasks:

    - name: install conf file

      template: src=nginx.conf.7

      when: ansible_distribution_major_version == '7'        4tasks:

      template: src=nginx.conf.6

      when: ansible_distribution_major_version == '6'

條件測試1: when

<code>  </code><code>- name: copy </code><code>file</code> <code>6</code>

<code>    </code><code>template: src=</code><code>/tmp/6</code><code>.txt dest=</code><code>/tmp</code>

<code>    </code><code>when: ansible_distribution_major_version == </code><code>'6'</code>

<code>  </code><code>- name: copy </code><code>file</code> <code>7</code>

<code>    </code><code>template: src=</code><code>/tmp/7</code><code>.txt dest=</code><code>/tmp</code>

<code>    </code><code>when: ansible_distribution_major_version == </code><code>'7'</code>

<code>handlers:</code>

<code>- name: restart nginx</code>

<code>  </code><code>service: name=nginx state=restarted</code>

2.register

示例,判斷sda6是否存在。存在就執行一些相應的腳本,則可以為該判斷注冊一個register變量,并用它來判斷是否存在,存在傳回 succeeded, 失敗就是 failed.

<code>- name: Create a register to represent the status </code><code>if</code> <code>the </code><code>/dev/sda6</code> <code>exsited</code>

<code>  </code><code>shell: </code><code>df</code> <code>-h | </code><code>grep</code> <code>sda6</code>

<code>  </code><code>register: dev_sda6_result</code>

<code>  </code><code>ignore_errors: True</code>

<code>  </code><code>tags: docker</code>

<code>    </code> 

<code>- name: Copy docker-thinpool.sh to all hosts</code>

<code>  </code><code>copy: src=docker-thinpool.sh dest=</code><code>/usr/bin/docker-thinpool</code> <code>mode=0755</code>

<code>  </code><code>when: dev_sda6_result | succeeded</code>

假如我們想忽略某一錯誤,通過執行成功與否來做決定,我們可以像這樣:

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

三、PlayBook中的循環    

循環:疊代,需要重複執行的任務;

例如需要同時安裝,nginx,httpd,php-fpm,php-mysql,mariabd等

    對疊代項的引用,固定變量名為"item"

    而後,要在task中使用with_items給定要疊代的元素清單

    清單方法:

        字元串:

        字典:

1.标準循環:        

<code>- name: </code><code>install</code> <code>some packages</code>

<code>  </code><code>yum: name={{ item }} state=present</code>

<code>  </code><code>with_items:</code>

<code>  </code><code>- nginx</code>

<code>  </code><code>- memcached</code>

<code>  </code><code>- php-fpm</code>

<code>    </code><code>//</code><code>将可以安裝多個軟體同時安裝</code>

<code>循環測試腳本:item    </code>

<code>[root@localhost ~]</code><code># cat e.yaml </code>

<code>  </code><code>- name: </code><code>install</code> <code>pkgs </code>

<code>    </code><code>yum: name={{ item }} state=present</code>

<code>    </code><code>with_items:</code>

<code>    </code><code>- telnet</code>

<code>    </code><code>- vim</code>

<code>    </code><code>- tree</code>

循環測試腳本3.

    建立三個使用者分别屬于不同組

[root@localhost ~]# cat f.yaml 

<code>  </code><code>- name: group add</code>

<code>    </code><code>group: name={{ item }} state=present     </code><code>//</code><code>注意:引用的時候使用的是{{ }}沒有s,列舉參數的時候使用的是複數,items</code>

<code>    </code><code>- group11</code>

<code>    </code><code>- group12</code>

<code>    </code><code>- group13 </code>

<code>  </code><code>- name: add </code><code>users</code>

<code>    </code><code>user: name={{ item.name }}  group={{ item.group }} state=present</code>

<code>    </code><code>- { name: </code><code>'user11'</code><code>, group: </code><code>'group11'</code> <code>}</code>

<code>    </code><code>- { name: </code><code>'user12'</code><code>, group: </code><code>'group12'</code> <code>}</code>

<code>    </code><code>- { name: </code><code>'user13'</code><code>, group: </code><code>'group13'</code> <code>}</code>

==============================

[root@localhost ~]# cat c.yaml

<code>- hosts: testweb</code>

<code>  </code><code>- name: </code><code>install</code> <code>user</code>

<code>    </code><code>user: name={{ item.name }} state=present </code><code>groups</code><code>={{ item.</code><code>groups</code> <code>}}</code>

<code>      </code><code>- { name: </code><code>'testuser1'</code><code>, </code><code>groups</code><code>: </code><code>'wheel'</code> <code>}</code>

<code>      </code><code>- { name: </code><code>'testuser2'</code><code>, </code><code>groups</code><code>: </code><code>'root'</code> <code>}</code>

//建立testuser1{wheel},testuser2{root}    

注意:

    1.hosts 不是host

    2.嚴格對齊,清單和内容分開

    3.name: 'user11' //中間必須有空格,字元必須用引号,

    4.目标主機存在user11或其中一個使用者的話,也會傳回錯誤

    5.whih_itmes後的内容為下一個key-value (先加空格)

2.嵌套循環:

<code>-name:give </code><code>users</code> <code>access to multiple databases</code>

<code> </code><code>mysql_user:name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=</code><code>yes</code> <code>password=foo</code>

<code> </code><code>with_nested:</code>

<code>  </code><code>-[</code><code>'alice'</code><code>,</code><code>'bob'</code><code>]        </code><code>//</code><code>表示item[0],nested:嵌套</code>

<code>  </code><code>-[</code><code>'clientdb'</code><code>,</code><code>'employeedb'</code><code>,</code><code>'providerdb'</code><code>]</code>

<code>  </code> 

<code>- name: here, </code><code>'users'</code> <code>contains the above list of employees</code>

<code>  </code><code>mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=</code><code>yes</code> <code>password=foo</code>

<code>  </code><code>with_nested:</code>

<code>    </code><code>- </code><code>"{{users}}"</code>

<code>    </code><code>- [ </code><code>'clientdb'</code><code>, </code><code>'employeedb'</code><code>, </code><code>'providerdb'</code> <code>]</code>

<code>  </code><code>- name: give </code><code>users</code> <code>access to multiple databases</code>

<code>    </code><code>command</code><code>: </code><code>"echo name={{ item[0] }} priv={{ item[1] }} test={{ item[2] }}"</code>

<code>    </code><code>with_nested:</code>

<code>      </code><code>- [ </code><code>'alice'</code><code>, </code><code>'bob'</code> <code>]</code>

<code>      </code><code>- [ </code><code>'clientdb'</code><code>, </code><code>'employeedb'</code><code>, </code><code>'providerdb'</code> <code>]</code>

<code>      </code><code>- [ </code><code>'1'</code><code>, </code><code>'2'</code><code>, ]</code>

<code>    </code><code>tags: netsted</code>

輸出:

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'alice'</code><code>, u</code><code>'clientdb'</code><code>, u</code><code>'1'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'alice'</code><code>, u</code><code>'clientdb'</code><code>, u</code><code>'2'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'alice'</code><code>, u</code><code>'employeedb'</code><code>, u</code><code>'1'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'alice'</code><code>, u</code><code>'employeedb'</code><code>, u</code><code>'2'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'alice'</code><code>, u</code><code>'providerdb'</code><code>, u</code><code>'1'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'alice'</code><code>, u</code><code>'providerdb'</code><code>, u</code><code>'2'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'bob'</code><code>, u</code><code>'clientdb'</code><code>, u</code><code>'1'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'bob'</code><code>, u</code><code>'clientdb'</code><code>, u</code><code>'2'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'bob'</code><code>, u</code><code>'employeedb'</code><code>, u</code><code>'1'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'bob'</code><code>, u</code><code>'employeedb'</code><code>, u</code><code>'2'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'bob'</code><code>, u</code><code>'providerdb'</code><code>, u</code><code>'1'</code><code>])</code>

<code>skipping: [192.168.2.122] =&gt; (item=[u</code><code>'bob'</code><code>, u</code><code>'providerdb'</code><code>, u</code><code>'2'</code><code>])</code>

3.字典循環

假如你有以下變量:

users:

  alice:

    name: Alice Appleworth

    telephone: 123-456-7890

  bob:

    name: Bob Bananarama

    telephone: 987-654-3210

你想列印出每個使用者的名稱和電話号碼.你可以使用 with_dict 來循環哈希表中的元素:

  - name: Print phone records

    debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"

    with_dict: "{{users}}"

4.周遊檔案whith_file,whith_fileglob

with_file 是将每個檔案的檔案内容作為item的值

<code>- hosts: all</code>

<code>    </code><code># first ensure our target directory exists</code>

<code>    </code><code>- </code><code>file</code><code>: dest=</code><code>/etc/fooapp</code> <code>state=directory</code>

<code>    </code><code># copy each file over that matches the given pattern  //注意copy必須要用 “-”</code>

<code>    </code><code>- copy: src={{ item }} dest=</code><code>/etc/fooapp/</code> <code>owner=root mode=600</code>

<code>      </code><code>with_fileglob:</code>

<code>        </code><code>- </code><code>/playbooks/files/fooapp/</code><code>*</code>

with_fileglob 是将每個檔案的全路徑作為item的值, 在檔案目錄下是非遞歸的, 如果是在role裡面應用改循環, 預設路徑是roles/role_name/files_directory

5.并行資料循環

已知變量:

    alpha: [ 'a', 'b', 'c', 'd' ]

    numbers:  [ 1, 2, 3, 4 ]

如果你想得到’(a, 1)’和’(b, 2)’之類的集合.可以使用’with_together’:

    - debug: msg="{{ item.0 }} and {{ item.1 }}"

      with_together:

        - "{{alpha}}"

        - "{{numbers}}"

還有更多的循環介紹方法請參考本文尾部連結位址...

四、角色:(roles)

一個主機可以擔任多種角色:

    定義為多個身份,用的時候直接調用該身份即可

角色名就是目錄名,任何角色都不能引用自己所屬目錄之外的其他目錄檔案

    roles/

        mysql/

        httpd/

        nginx/

        memcached/

每個角色,以特定的層級目錄結構進行組織: 注意:大多數都是複數"s",除了meta

    mysql/

        files/        存放由copy或script子產品等調用的檔案

        templates/  template子產品查找所需要的模闆檔案目錄;

        handlers/   至少應該包含一個名為main.yml檔案

        vars/        至少一個main.yml

        tasks/        基本元素:至少一個名為main.yml的檔案,其他的檔案需要在此檔案中通過include進行包含

        meta/        main.yml,定義目前角色的特殊設定,及其依賴關系

        default/      設定預設變量時使用此目錄中的main.yml檔案

調用角色:

- hosts: websrvs

  remote_user: root

  roles: 

  - mysql        //會自動到mysql目錄中跑一遍

  - memcached    

  - nginx

mkdir /etc/ansible/roles/nginx/{files,tasks,templates,handlers,vars,default,meta} -pv

cd /etc/ansible/roles/nginx/

1.tasks    

[root@localhost nginx]# cat tasks/main.yml 

<code>- name: </code><code>install</code> <code>nginx pkg</code>

<code>  </code><code>yum: name=nginx state=present</code>

<code>- name: </code><code>install</code> <code>conf </code><code>file</code>

<code>  </code><code>template: src=nginx.conf dest=</code><code>/etc/nginx/nginx</code><code>.conf.</code><code>test</code>   <code>///nginx</code><code>.conf不在同級目錄,但是role可以直接識别為template中的檔案</code>

<code>- name: start nginx</code>

<code>  </code><code>service: name=nginx state=started enabled=</code><code>true</code>

templates 目錄中有存放的nginx.conf

2.在其他地方建立nginx.yaml //這個可以放在其他地方

<code>  </code><code>roles:</code>

執行:  

    ansible-playbook --check nginx.yaml

<code>/etc/ansible/roles/nginx/</code>

<code>├── default</code>

<code>├── files</code>

<code>├── handlers</code>

<code>├── meta</code>

<code>├── tasks</code>

<code>│   └── main.yml</code>

<code>├── templates</code>

<code>│   └── nginx.conf</code>

<code>└── vars</code>

3.添加handler

修改handlers/main.yml

- name: restart nginx        //注意,前面的 - 不可少,代表是handler的一個清單

  service: name=nginx state=restarted

建立tasks/main.yml        

<code>  </code><code>template: src=nginx.conf dest=</code><code>/etc/nginx/nginx</code><code>.conf.</code><code>test</code>

<code>  </code><code>notify: restart nginx</code>

<code>  </code><code>tags: instconf</code>

修改一下nginx.conf //否則不會觸發handler

ansible-playbook -t instconf --check g.yaml    

4.變量

[root@localhost yaml]# cat h.yaml 

<code>  </code><code>vars:</code>

<code>  </code><code>- username: testuser1</code>

<code>  </code><code>- groupname: testgroup1</code>

<code>  </code><code>- name: create group</code>

<code>    </code><code>group: name={{ groupname }} state=present</code>

<code>  </code><code>- name: create user</code>

<code>    </code><code>user: name={{ username }} group={{ groupname }} state=present</code>

在playbook中定義變量的方法

    vars:

    - var1: value1

    - var2: value2

ansible-playbook -e "groupname=mygrp1" -e "username=myuser"  --check h.yaml

    //可以覆寫變量,在指令行中定義的變量,會覆寫

5.變量使用,roles中

    vim nginx/vars/main.yml  

        username: nginx

    vim templates/nginx.conf 

        user {{ username }} //讓nginx以該使用者的身份運作

    其他不修改

    ansible 

問題:

[root@localhost yaml]# ansible-playbook --check g.yaml 

ERROR! The vars/main.yml file for role 'nginx' must contain a dictio

nary of variables

原因:vars/main.yml 前面不需要 - ,和其他的main.yml不一樣

ansible-playbook -e "username=adm" --check nginx.yml //假如想改變運作nginx的使用者,直接修改即可

6.在playbook中調用角色方法2

vim nginx.yaml

  roles:

  - {role: nginx, username: nginx} //向該角色傳遞變量

    鍵role用于指定角色名稱,後續的k/v用于傳遞變量給角色

    還可以基于條件測試,實作角色調用;

    例如:

    roles:

    - {role: nginx,when: "ansible_distribution_major_version == '7' }

        //條件滿足時,應用該角色

[root@localhost yaml]# cat i.yaml 

  - { role: nginx, username: nginx, when: "ansible_distribution_major_version == '7'" } 

//隻有在OS為7才會執行

7.安裝memcached,占用内從空間為目前可用空間的1/3

 mkdir -pv memcached/{tasks,vars,templates,hanlers}

<code>vim tasks</code><code>/main</code><code>.yml </code>

<code>- name: </code><code>install</code> <code>pack</code>

<code>  </code><code>yum: name=memcached state=present</code>

<code>- name: </code><code>install</code> <code>conf</code>

<code>  </code><code>template: src=memcached.j2 dest=</code><code>/etc/sysconfig/memcached</code>

<code>  </code><code>notify: restart memcached</code>

<code>  </code><code>tags: memconf</code>

<code>- name: start memcached</code>

<code>  </code><code>service: name=memcached state=started enabled=</code><code>true</code>

<code>vim templates</code><code>/memcached</code>

<code>PORT=</code><code>"11211"</code>

<code>USER=</code><code>"memcached"</code>

<code>MAXCONN=</code><code>"1024"</code>

<code>CACHESIZE=</code><code>"{{ ansible_memtotal_mb//4  }}"</code>  <code>//</code><code>除以4,可能是小數,是以</code><code>//</code> <code>取出整數</code>

<code>OPTIONS=</code><code>""</code>

<code>vim handlers</code><code>/main</code><code>.yml    </code>

<code>- name: restart memcached</code>

<code>  </code><code>service: name=memcached state=restarted</code>

<code>vim lnm.yaml  </code><code>//</code><code>同時調用兩個role</code>

<code>  </code><code>- roles:</code>

<code>  </code><code>- { role: nginx, when: ansible_distribution_version == </code><code>'7'</code> <code>}</code>

<code>  </code><code>- { role: memcached, when: ansible_hostname == </code><code>'memcached'</code> <code>}</code>

ansible-playbook -t memconf lnm.yaml 

出錯原因:

    1.main.yml中,template是沒有s的,但是目錄名是有s的

    2.notify不是nofify

=======================================================    

yaml和yml格式的差別:

    1.yml不需要hosts,remote_user //這些在yaml中定義

        - name: install pkgs

          yum: name=memcached state=present

    2.yaml一定要-hosts,-remote_user

        - hosts: all

          remote_user: root 

          roles: 

          - { role: nginx,when:ansible_distribution_version == '7' }

ansible all -m setup  //檢視所有内置變量

www.ansible.com.cn //站點,

推薦:參考ansible官方role的寫法,自行建立role進行練習

http://blog.csdn.net/kellyseeme/article/details/50619562

http://www.ansible.com.cn/docs/playbooks_loops.html

https://www.cnblogs.com/v394435982/p/5593274.html

本文轉自MT_IT51CTO部落格,原文連結:http://blog.51cto.com/hmtk520/2058293,如需轉載請自行聯系原作者

下一篇: PXE詳解

繼續閱讀