一、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
算數運算:
+,-,*,/,%, //,** //:表示隻要熵
比較運算:
==,!=,>=,<=,<,
邏輯運算符:
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] => (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] => (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] => (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] => (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] => (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] => (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] => (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] => (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] => (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] => (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] => (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] => (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,如需轉載請自行聯系原作者