安裝:
先安裝EPEL源
yum install ansible -y
Ansible配置和測試
第一步是修改主機與配置組,檔案位置 /etc/ansible/hosts, 格式是ini,添加兩台主機IP 同時定義兩個IP到webserver組 内容如下:
【/etc/ansible/hosts】
#web1.aa.com
#web2.aa.com
192.168.137.8
192.168.137.9
[webserver]
通過PING魔窟測試主機的連通性,分别對單主機及組進行PING操作 初夏如下結果 表示安裝測試成功
<code>[root@localhost ansible]</code><code># ansible webserver -m ping -k</code>
<code>SSH password:</code>
<code>192.168.137.8 | SUCCESS => {</code>
<code> </code><code>"changed"</code><code>: </code><code>false</code><code>,</code>
<code> </code><code>"ping"</code><code>: </code><code>"pong"</code>
<code>}</code>
<code>192.168.137.9 | SUCCESS => {</code>
<code>[root@localhost ansible]</code><code>#</code>
<code>#運作指令如下:</code>
<code>[root@localhost ansible]</code><code># ansible webserver -a "uptime"</code>
<code>192.168.137.8 | SUCCESS | rc=0 >></code>
<code> </code><code>16:43:39 up 26 min, 1 user, load average: 0.03, 0.01, 0.00</code>
<code>127.168.137.9 | SUCCESS | rc=0 >></code>
<code> </code><code>16:43:40 up 49 min, 4 </code><code>users</code><code>, load average: 0.14, 0.06, 0.01</code>
由于主要端與被控主機未配置SSH證書信任,需要在執行ansible指令時添加 -k 參數,要求提供root密碼 即在提示 SSH password:時輸入 很多人更傾向于使用Linux普通使用者賬戶進行連接配接并使用sudo指令實作root權限,格式為:ansible webserver -m ping -u ansible -sudo.
為了避免Ansible下發指令時輸入目标主機密碼,通過證書簽名達到SSH無密碼是一個方案,推薦使用ssk-keygen 與 ssh-copy-id來實作快速證書的生成及公鑰下發,其中ssh-keygen生成一對秘鑰,使用ssh-copy-id來下發生成的公鑰。具體操作如下:
在主要端主機建立秘鑰 執行:ssk-keygen -t rsa, 有詢問直接Enter鍵即可 将在/root/.ssh目錄下生成一對秘鑰,其中 id_rsa為私鑰,id_rsa.pub為公鑰,公鑰需要下發到被控主機使用者的.ssh目錄,同時要求重命名成authorized_keys檔案。
<code>[root@localhost ansible]</code><code># ssh-keygen -t rsa -b 4096</code>
<code>Generating public</code><code>/private</code> <code>rsa key pair.</code>
<code>Enter </code><code>file</code> <code>in</code> <code>which</code> <code>to save the key (</code><code>/root/</code><code>.</code><code>ssh</code><code>/id_rsa</code><code>):</code>
<code>Created directory </code><code>'/root/.ssh'</code><code>.</code>
<code>Enter passphrase (empty </code><code>for</code> <code>no passphrase):</code>
<code>Enter same passphrase again:</code>
<code>Your identification has been saved </code><code>in</code> <code>/root/</code><code>.</code><code>ssh</code><code>/id_rsa</code><code>.</code>
<code>Your public key has been saved </code><code>in</code> <code>/root/</code><code>.</code><code>ssh</code><code>/id_rsa</code><code>.pub.</code>
<code>The key fingerprint is:</code>
<code>36:ca:5e:14:6b:ef:ab:12:4d:82:be:33:d0:70:3c:f4 root@localhost</code>
<code>The key's randomart image is:</code>
<code>+--[ RSA 4096]----+</code>
<code>| |</code>
<code>| . |</code>
<code>| o o . |</code>
<code>| . = E .o |</code>
<code>| = . +S |</code>
<code>| . o..=.o |</code>
<code>| . .o.. . |</code>
<code>| +... . |</code>
<code>| o....o. |</code>
<code>+-----------------+</code>
接下來同步公鑰檔案id_rsa.pub到目标主機,推薦使用ssh-copy-id公鑰拷貝工具,指令格式:
/usr/bin/ssh-copy-id [-i[identity_file]][user@]machine 本例中使用一下指令:
<code>ssh</code><code>-copy-</code><code>id</code> <code>-i </code><code>/root/</code><code>.</code><code>ssh</code><code>/id_rsa</code><code>.pub [email protected]</code>
<code>ssh</code><code>-copy-</code><code>id</code> <code>-i </code><code>/root/</code><code>.</code><code>ssh</code><code>/id_rsa</code><code>.pub [email protected]</code>
效驗SSH無密碼是否配置成功 ,運作 ssh [email protected] 如果直接進入目标root賬号提示符,則署名配置成功。
定義主機與組規則
Ansible通過定義好的主機與組規則(Inventory)對比對的目标主機進行遠端操作,配置規則檔案預設是/etc/ansible/hosts.
定義主機與組
所有定義的主機與組規則都在/etc/ansible/hosts檔案中. 為ini檔案格式 主機可以用域名、IP、别名進行辨別,其中webserver、dbserver 為組名 緊跟着的主機為其成員 格式如下:
<code>mail.example.com</code>
<code>192.168.1.21:2135</code>
<code>[webserver]</code>
<code>foo.example.com</code>
<code>bar.example.com</code>
<code>192.168.1.22</code>
<code>[dbserver]</code>
<code>one.example.com</code>
<code>two.example.com</code>
<code>three.example.com</code>
<code>192.168.1.23</code>
其中 192.168.1.21:2135 的意思是定義一個SSH服務端口為2135的主機,當然我們也可以使用别名來描述一台主機。
jumper ansible_ssh_port=22 ansible_ssh_host=192.168.1.50
jumper為定義一個s别名,ansible_ssh_port為主機SSH服務端口,ansible_ssh_host為目标主機 更多保留主機變量如下:
ansible_ssh_host 目标主機位址
ansible_ssh_port 目标主機SSH端口 端口22無需指定
ansible_ssh_user 目标主機使用者名
ansible_ssh_pass 目标主機密碼
ansible_connection 目标主機連接配接類型 可以視local、ssh 或者paramiko
ansible_ssh_private_key_file 目标主機SSH私鑰
ansible_*_interpreter 指定采用非Python的其他腳本語言 如 Ruby Perl 或者其他
組成員主機名稱支援正則描述 示例如下:
<code>www[01:20].example.com</code>
<code>db-[a:f].example.com</code>
定義主機變量
主機可以指定變量,以便後面供Playbooks配置使用 比如定義主機hosts1 和 hosts2 上Apache參數http_port 及 maxRequestsPerChild,目的是讓兩台主機産生Apache配置檔案httpd.conf差異化,定義格式如下:
<code>[atlanta]</code>
<code>host1 http_port=80 maxRequestsPerChild=808</code>
<code>host2 http_port=8080 maxRequestsPerChild=909</code>
定義組變量
組變量的作用域是覆寫組所有成員,通過定義一個新塊,塊名由組名+":vars" 組成,定義格式如下:
<code>host1</code>
<code>host2</code>
<code>[atlanta:vars]</code>
<code>ntp_server=ntp.atlanta.example.com</code>
<code>proxy=proxy.atlanta.example.com</code>
同時Ansible支援組嵌套組 ,通過定義一個新塊,塊名由組名+":children"組成,格式如下:
<code>[raleigh]</code>
<code>host3</code>
<code>[southeast:children]</code>
<code>atlanta</code>
<code>raleigh</code>
<code>[southeast:vars]</code>
<code>some_server=foo.southeast.example.com</code>
<code>halon_system_timeout=30</code>
<code>self_destruct_countdown=60</code>
<code>escape_pods=2</code>
<code>[usa:children]</code>
<code>southeast</code>
<code>northeast</code>
<code>southwest</code>
分離主機與組特定資料
為了更好規範定義的主機與組變量,Ansible支援将/etc/ansible/hosts定義的主機名與組變量單獨剝離出來存放到指定檔案夾中.将采用YAML格式存放,存放位置規定: "/etc/ansible/group_vars/+組名" 和 "/etc/ansible/host_vars/+主機名" 分别存放指定組名或者主機名定義的變量。如下:
/etc/ansible/group_vars/dbservers
/etc/ansible/group_vars/webservers
定義的dbserver變量格式為:
[/etc/ansible/group_vars/dbservers]
---
ntp_server:acme.example.org
database_server:storage.example.org
Ansible常用子產品
遠端指令子產品
<code> </code><code>ansible webserver -m </code><code>command</code> <code>-a </code><code>"free -m"</code> <code>#遠端指令</code>
<code> </code><code>ansible webserver -m script -a </code><code>"/home/test.sh"</code> <code>#遠端主機執行主要伺服器腳本</code>
<code> </code><code>ansible webserver -m shell -a </code><code>"/home/test.sh"</code> <code>#執行遠端主機腳本</code>
2. copy子產品
實作主要端想目标主機拷貝檔案
以下例子實作拷貝/home/test.sh檔案到webserver組目标主機/tmp目錄下 并更新檔案屬主和權限
<code>ansible webserver -m copy -a </code><code>"src=/home/test.sh dest=/tmp/ owner=root group=root mode=0755"</code>
3. stat子產品
擷取遠端檔案狀态資訊,包括atime、ctime、mtime、MD5、uid、gid等資訊
例子:
<code>ansible webserver -m stat -a </code><code>"path=/etc/sysctl.conf"</code>
4. get_url子產品
實作在遠端主機下載下傳指定URL到本地 支援sha256sum檔案效驗
執行個體:
<code>ansible webserver -m get_url -a </code><code>"url=http://www.baidu.com dest=/tmp/index.html mode=0440 force=yes "</code>
5. yum功能
Linux平台軟體包管理操作 常見的有yum apt 管理方式
執行個體 :
<code> </code><code>ansible webserver -m yum -a </code><code>"name=curl state=latest"</code>
<code> </code><code>ansible webserver -m apt -a </code><code>"pkg=curl state=latest"</code>
6. cron子產品
遠端主機crontab配置
執行個體:
<code>ansible webserver -m </code><code>cron</code> <code>-a </code><code>"'name=check dirs' hour='5,2' job='ls -alh > /dev/null'"</code>
結果:
<code>#Ansible: test_check</code>
<code>* 5,2 * * * </code><code>ls</code> <code>-alh > </code><code>/root/ll</code><code>.txt</code>
7. mount子產品
遠端主機分區挂載
<code>ansible webserver -m </code><code>mount</code> <code>-a </code><code>"name=/mnt/data src=/dev/sd0 fstype=ext3 opts=ro state=present"</code>
8. service子產品
遠端主機系統服務管理
執行個體:
<code> </code><code>ansible webserver -m service -a </code><code>"name=nginx state=stopped"</code>
<code> </code><code>ansible webserver -m service -a </code><code>"name=nginx state=restarted"</code>
<code> </code><code>ansible webserver -m service -a </code><code>"name=nginx state=reloaded"</code>
9. sysctl包管理子產品
遠端主機sysctl配置
<code> </code><code>ansible webserver -m sysctl -a "name=kernel.panic value=3 sysctl_file=</code><code>/etc/sysctl</code><code>.conf checks=before reload=yessalt </code><code>'*'</code> <code>pkg.upgrade</code>
10 . user子產品
遠端主機系統使用者管理
<code> </code><code>ansible webserver -m user -a </code><code>"name=johnd comment='John Doe'"</code> <code>#添加使用者</code>
<code> </code><code>ansible webserver -m user -a </code><code>"name=johnd state=absent remove=yes"</code> <code>#删除使用者</code>
playbook介紹:
<code>---</code>
<code>- hosts: webserver</code>
<code> </code><code>vars:</code>
<code> </code><code>worker_processes: 4</code>
<code> </code><code>num_cpus: 4</code>
<code> </code><code>max_open_file: 65506</code>
<code> </code><code>root: </code><code>/data</code>
<code> </code><code>remote_user: root</code>
<code> </code><code>tasks:</code>
<code> </code><code>- name ensure nginx is at the latest version</code>
<code> </code><code>yum: pkg=nginx state=latest</code>
<code> </code><code>- name: write the nginx config </code><code>file</code>
<code> </code><code>template: src=</code><code>/home/test/nginx2</code><code>.conf dest=</code><code>/etc/nginx/nginx</code><code>.conf</code>
<code> </code><code>notify:</code>
<code> </code><code>- restart nginx</code>
<code> </code><code>- name: ensure nginx is running</code>
<code> </code><code>service: name=nginx start=started</code>
<code> </code><code>handlers:</code>
<code> </code><code>- name: restart nginx</code>
<code> </code><code>service: name=nginx state=restarted</code>
以上playbook定制了一個簡單的Nginx軟體包管理 内容包括安裝 配置模闆 狀态管理等。下面進行說明。
定義主機和使用者:
在playbook執行時,可以為主機或組定義變量,比如指定遠端登入使用者。一下為webserver組定義的相關變量,變量的作用域隻限于webserver組下的主機。
hosts參數的作用為定義的操作對象,可以視主機或組,本示例定義的為webserver組,同僚通過vars定義了4個變量 配置模闆用到,其中remote_user 為制動遠端操作的使用者名,預設為root賬号,支援sudo方式運作,通過添加sudo:yes即可。注意 remote_user參數在Ansible1.4或更高版本才引入。
任務清單:
所有定義的任務清單tasks list ,playbook将按定義的配置檔案自上而下的順序執行,定義的主機都将得到相同的任務,但執行的傳回結果不一定保持一緻,取決于主機的環境及程式包狀态。建議每個任務事件都定義一個name标簽增強可讀性,也便于觀察輸出結果了解運作的位置,預設使用action(具體的執行動作)來替換name作為輸入。下列是一個簡單的任務定義示例:
<code>tasks:</code>
<code> </code><code>- name: </code><code>make</code> <code>sure nginx is running</code>
<code> </code><code>service: name=nginx state=started</code>
功能實際檢測Nginx服務是否處于運作狀态,如果沒有則啟動。其中name标簽對下面的action進行描述,action部分可以視ansible的任意子產品,本示例為service子產品,參數使用key=value的格式,如 name=httpd 在定義任務時也可以引用變量 格式如下:
<code> </code><code>- name: create a virtual host </code><code>file</code> <code>for</code> <code>{{ vhost }}</code>
<code> </code><code>template: src=somefile.j2 dest=</code><code>/etc/httpd/conf</code><code>.d/{{ vhost }}</code>
在playbook可以通過template子產品對本地配置模闆檔案進行渲染并同步到目标主機。已nginx配置檔案為例,定義如下:
<code>- name: write the nginx config </code><code>file</code>
<code> </code><code>template: src=</code><code>/etc/ansible/nginx/nginx2</code><code>.conf dest=</code><code>/etc/nginx/nginx</code><code>.conf</code>
<code> </code><code>notify:</code>
<code> </code><code>- restart nginx</code>
其中scr=/etc/ansible/nginx/nginx2.conf位管理端模闆檔案的存放位置 dest=/etc/nginx/nginx.conf為目标主機nginx配置的檔案的存放位置,通過下面Nginx模闆檔案讓大家對模闆的定義有個基本的概念。
<code>user nginx;</code>
<code>worker_processes {{ worker_processes}};</code>
<code>{% </code><code>if</code> <code>num_cpus == 2 %}</code>
<code>worker_cpu_affinity 01 10;</code>
<code>{% </code><code>elif</code> <code>num_cpus == 4 %}</code>
<code>worker_cpu_affinity 1000 0100 0010 0001;</code>
<code>{% </code><code>elif</code> <code>num_cpus >= 8 %}</code>
<code>worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;</code>
<code>{% </code><code>else</code> <code>%}</code>
<code>{% endif %}</code>
<code>worker_rlimit_nofile {{ max_open </code><code>file</code> <code>}};</code>
Ansible會根據定義好的模闆渲染成真實的配置檔案 ,模闆使用YAML文法 最終生成的nginx.conf如下:
<code>worker_processes 4;</code>
<code>worker_rlimit_nofile 65506;</code>
檔目标主機配置檔案發生變化後,通知處理程式Handlers 來觸發後面的動作,比如重新開機nginx服務。handlers中定義的處理程式沒有通知觸發時時不會執行的,觸發後也隻會運作一次。觸發時通過Handlers定義的name标簽來識别的,比如下面的notify中的 restart nginx 與handlers中的 name:restart nginx保持一緻。
<code>notify:</code>
<code> </code><code>- restart nginx</code>
<code>handlers:</code>
<code> </code><code>- name: restart nginx</code>
<code> </code><code>service: name=nginx state=restarted</code>
執行playbook
執行playbook可以通過ansible-playbook指令實作,格式: ansible-playbook playbookfiel.yml [參數] 如啟用10個并行程序數執行playbook:
ansible-playbook /etc/ansible/nginx/nginx.yml -f 10
其他參數:
-u REMOTE_USER:手工指定遠端執行playbook的系統使用者
--syntax-check 檢查playbook文法
--list-hosts playbooks 比對到的主機清單
-T TIMEOUT 定義playbook執行逾時時間
--setp 以單任務分步驟運作,友善做每一個不的确認工作。
更多參數運作 ansible-playbook -help擷取。
以下是一個例子的執行結果 vsftpd.yml檔案内容如下:
<code>[root@localhost ansible]</code><code># cat vsftpd.yml</code>
<code> </code><code>- name: Install Vsftpd Server</code>
<code> </code><code>yum: pkg=vsftpd state=latest</code>
<code> </code><code>- restart vsftpd</code>
<code> </code><code>- name: Check Vsftpd is Running</code>
<code> </code><code>service: name=vsftpd state=started</code>
<code> </code><code>- name: restart vsftpd</code>
<code> </code><code>service: name=vsftpd stated=restarted</code>
執行結果如下:
<code>[root@localhost ansible]</code><code># ansible-playbook vsftpd.yml -f 10</code>
<code>PLAY [webserver] ***************************************************************</code>
<code>TASK [setup] *******************************************************************</code>
<code>ok: [192.168.137.9]</code>
<code>ok: [192.168.137.8]</code>
<code>TASK [Install Vsftpd Server] ***************************************************</code>
<code>TASK [Check Vsftpd is Running] *************************************************</code>
<code>PLAY RECAP *********************************************************************</code>
<code>192.168.137.8 : ok=3 changed=0 unreachable=0 failed=0</code>
<code>192.168.137.9 : ok=3 changed=0 unreachable=0 failed=0</code>
角色定義
已經了解了變量,任務和處理程式的定義 有什麼方法更好的進行組織或抽象 讓其複用性更強、功能根據子產品化?答案就是角色,角色是Ansible定制好的一種标準規範,以不同級别目錄層次及檔案對角色、變量、任務、處理程式等拆分、為後續功能擴充、可維護性打下基礎 一個定向的角色目錄結構如下:
<code>site.yml</code>
<code>webserver.yml</code>
<code>fooserver.yml</code>
<code>roles/</code>
<code> </code><code>common/</code>
<code> </code><code>files/</code>
<code> </code><code>templates/</code>
<code> </code><code>tasks/</code>
<code> </code><code>handlers/</code>
<code> </code><code>vars/</code>
<code> </code><code>meta/</code>
<code> </code><code>webserver/</code>
在playbook是這樣引用的:
<code>[site.yml]</code>
<code>- hosts:webserver</code>
<code> </code><code>roles:</code>
<code> </code><code>-common</code>
<code> </code><code>-webserver</code>
角色定制已下規範,其中X為角色名
如roles/x/tasks/main.yml 檔案存在。其中列出的任務江北添加到執行隊列
如roles/x/handlers/main.yml 檔案存在 其中所列出的處理程式将被添加到執行隊列;
如roles/x/vars/main.yml 檔案存在 其中列出的變量将被添加到執行隊列;
如roles/x/meta/main.yml 檔案存在 所列任何作用的依賴關系将被添加到角色的清單
任何副本任務可以引用roles/x/files/無需寫路徑 預設相對或絕對醫用;
任何腳本任務可以引用roles/x/files/無需寫路徑 預設相對或絕對醫用;
任何模闆任務可以引用檔案中的roles/x/templates/無需寫路徑 預設相對或絕對醫用;
為了便于更好的了解 以下示例以角色的形式存在。同時添加了一個公共角色common 從角色全局作用域中抽取出公共的部分,一般為系統的基礎服務,比如 ntp iptables、selinux、sysctl等。本示例是針對ntp服務的管理
playbook目錄結構
playbook目錄包括變量定義目錄group_vars、主機組定義檔案hotst、全局配置檔案site.yml 角色功能目錄,playbook目錄如下:
<code>[root@localhost playbook]</code><code># tree nginx/</code>
<code>nginx/</code>
<code>├── group_Vars</code>
<code>├── hosts</code>
<code>├── roles</code>
<code>│ ├── common</code>
<code>│ │ ├── handlers</code>
<code>│ │ │ └── main.yml</code>
<code>│ │ ├── tasks</code>
<code>│ │ ├── templates</code>
<code>│ │ │ └── ntp.conf.js</code>
<code>│ │ └── vars</code>
<code>│ │ └── main.yml</code>
<code>│ └── web</code>
<code>│ ├── handlers</code>
<code>│ │ └── main.yml</code>
<code>│ ├── tasks</code>
<code>│ └── templates</code>
<code>│ └── nginx2.conf</code>
<code>└── site.yml</code>
<code>11 directories, 9 files</code>
<code>[root@localhost playbook]</code><code>#</code>
1.建立目錄nginx
2.定義主機組
以下定義了一個業務組webserver 成員時兩台主機
【nginx/hosts】
<code> </code><code>[webserver]</code>
<code> </code><code>192.168.137.8</code>
<code> </code><code>192.168.137.9</code>
注意:這個非必選配置,預設将引用/etc/ansible/hosts的參數 角色中自定義組與主機檔案将通過 -i file 指令行參數調用。如 ansible-playbook -i hosts 來調用
3.定義主機組或變量
group_vars為定義變量目錄,目錄當中的檔案名要與組名保持一緻,組變量檔案定義的變量作為域值受限于該組,all代表所有主機
【nginx/group_vars/all】
<code>nptserver:ntp.sjtu.edu.cn</code>
【nginx/group_vars/webserver】
<code>worker_processes:4</code>
<code>num_cpus:4</code>
<code>max_open_file:65536</code>
<code>root:</code><code>/data</code>
4. 全局配置檔案site.yml
全局配置檔案引用了兩個角色塊,角色應用方位及實作的功能功都不一樣:
【nginx/site.yml】
<code>- name:apply common configuration to all nodes</code>
<code> </code><code>hosts:all</code>
<code> </code><code>- common</code>
<code>- name:configure and deploy the webserver and application code</code>
<code> </code><code>hosts:webserver</code>
<code> </code><code>- we</code>
全局配置檔案site.yml引用了兩個角色,一個為公共類的common,另一個為web類,分别對應nginx/common 、nginx/web目錄 以此類推,可以引用更多的角色,如dbserver、nosql、Hadoop等,前提是我們要先進行定義。通常情況下一個角色對應着一個特定功能服務。通過hosts參數來綁定角色對應的主機或組。
5. 角色common的定義
角色common定義了 handlers tasks templates vars 4個功能類,分别存放處理程式、任務清單、模闆、變量的配置檔案main.yml。需要注意的是 vars/main.yml中定義的變量優先級高于/nginx/group_vars/all定義的 可以從ansible-playbook的執行結果中得到驗證。各功能子產品配置檔案如下:
[handlers/main.yml]
<code>- name:restart ntp</code>
<code> </code><code>service:name=ntpd state=restarted</code>
[tasks/main.yml]
<code>- name:Install ntp</code>
<code> </code><code>yum:name=ntp state=present</code>
<code> </code>
<code>- name:Configure ntp </code><code>file</code>
<code> </code><code>template:src=ntp.conf.js dest</code><code>/etc/ntp</code><code>.conf</code>
<code> </code><code>notify:restart ntp</code>
<code>- name:Start the ntp service</code>
<code> </code><code>service: name=ntpd state=started enabled=</code><code>true</code>
<code> </code>
<code>- name: </code><code>test</code> <code>to see </code><code>if</code> <code>selinux is running</code>
<code> </code><code>command</code><code>:getenforce</code>
<code> </code><code>register:sestatus</code>
<code> </code><code>changed_when:</code><code>false</code>
其中template:src=ntp.conf.js引用是唔需要寫路徑。預設在上級的templates目錄中查找。
[templates/ntp.conf.j2]
<code>driftfile </code><code>/var/lib/ntp/drift</code>
<code>restrict 127.0.0.1</code>
<code>restrict -6 ::1</code>
<code>server {{ ntpserver }}</code>
<code>includefile </code><code>/etc/ntp/crypto/pw</code>
<code>keys </code><code>/etc/ntp/keys</code>
此處` ntpserver `将引用vars/main.yml定義的ntpserver變量。
[vars/main.yml]
<code>ntpserver:210.72.145.44</code>
6. 角色WEB的定義
角色web定義了handlers tasks templates三個功能類 具體如下:
<code>【handlers</code><code>/main</code><code>.yml】</code>
<code> </code><code>- name: restart nginx</code>
<code> </code><code>service: name=nginx state=restarted</code>
<code>【tasks</code><code>/main</code><code>.yml】</code>
<code> </code><code>- name: Install nginx</code>
<code> </code><code>yum: pkg=nginx state=latest</code>
<code> </code><code>- name: write the nginx config </code><code>file</code>
<code> </code><code>template: src=nginx2.conf dest=</code><code>/etc/nginx/nginx</code><code>.conf</code>
<code> </code><code>notify:</code>
<code> </code><code>- restart nginx</code>
<code> </code><code>- name: check nginx is running</code>
<code> </code><code>service:name=nginx state=started</code>
<code>【template</code><code>/nginx2</code><code>.conf】</code>
<code> </code><code>user nginx;</code>
<code> </code><code>worker_processes {{ worker_processes }};</code>
<code> </code><code>{% </code><code>if</code> <code>num_cpus == 2 %}</code>
<code> </code><code>worker_cpu_affinity 01 10;</code>
<code> </code><code>{% </code><code>if</code> <code>num_cpus == 4 %}</code>
<code> </code><code>worker_cpu_affinity 1000 0100 0010 0001;</code>
<code> </code><code>{% </code><code>if</code> <code>num_cpus >= 8 %}</code>
<code> </code><code>worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;</code>
<code> </code><code>{% </code><code>else</code> <code>%}</code>
<code> </code><code>{% endif %}</code>
<code> </code><code>worker_rlimit_nofile {{ max_open_file }};</code>
<code> </code><code>....</code>
7 運作角色
cd /etc/ansible/playbook/nginx
ansible-playbook -i hosts site.yml -f 10
我自己的測試執行結果如下:
<code>[root@localhost nginx]</code><code># ansible-playbook -i hosts site.yml -f 10</code>
<code>PLAY [comment settings] ********************************************************</code>
<code>TASK [common : Install ntp] ****************************************************</code>
<code>TASK [common : write ntp config </code><code>file</code><code>] ******************************************</code>
<code>TASK [common : start ntp server] ***********************************************</code>
<code>TASK [common : check selinux diabled] ******************************************</code>
<code>PLAY [Deploy webserver] ********************************************************</code>
<code>TASK [web : Copy nginx yum repo </code><code>file</code><code>] ******************************************</code>
<code>TASK [web : Install Nginx Web Server] ******************************************</code>
<code>TASK [web : write nginx config] ************************************************</code>
<code>TASK [web : check nginx running] ***********************************************</code>
<code>192.168.137.8 : ok=10 changed=0 unreachable=0 failed=0</code>
<code>192.168.137.9 : ok=10 changed=0 unreachable=0 failed=0</code>
<code>[root@localhost nginx]</code><code>#</code>
目錄結構和檔案内容如下:
<code>├── group_vars</code>
<code>│ └── webserver</code>
<code>│ │ │ └── ntp.conf.j2</code>
<code>│ ├── files</code>
<code>│ │ └── nginx.repo</code>
檔案内容如下:
<code>[root@localhost playbook]</code><code># cat nginx/group_vars/webserver</code>
<code>worker_processes: auto</code>
<code>num_cpus: 2</code>
<code>max_open_file: 65536</code>
<code>root: </code><code>/data</code>
<code>[root@localhost playbook]</code><code># cat nginx/hosts</code>
<code>192.168.137.8</code>
<code>192.168.137.9</code>
<code>[root@localhost playbook]</code><code># cat nginx/roles/common/handlers/main.yml</code>
<code>- name: restart ntp</code>
<code> </code><code>service: name=ntpd state=restarted</code>
<code>[root@localhost playbook]</code><code># cat nginx/roles/common/tasks/main.yml</code>
<code>- name: Install ntp</code>
<code> </code><code>yum: name=ntp state=present</code>
<code>- name: write ntp config </code><code>file</code>
<code> </code><code>template: src=ntp.conf.j2 dest=</code><code>/etc/ntp</code><code>.conf</code>
<code> </code><code>notify: restart ntp</code>
<code>- name: start ntp server</code>
<code>- name: check selinux diabled</code>
<code> </code><code>command</code><code>: getenforce</code>
<code> </code><code>register: sestatus</code>
<code> </code><code>changed_when: </code><code>false</code>
<code>[root@localhost playbook]</code><code># cat nginx/roles/common/templates/ntp.conf.j2</code>
<code>[root@localhost playbook]</code><code># cat nginx/roles/common/vars/main.yml</code>
<code>ntpserver: ntp.sjtu.edu.cn</code>
<code>[root@localhost playbook]</code><code># cat nginx/roles/web/handlers/main.yml</code>
<code>- name: restart nginx</code>
<code> </code><code>service: name=nginx state=restarted</code>
<code>[root@localhost playbook]</code><code># cat nginx/roles/web/tasks/main.yml</code>
<code>- name: Copy nginx yum repo </code><code>file</code>
<code> </code><code>copy: src=</code><code>/root/playbook/nginx/roles/web/files/nginx</code><code>.repo dest=</code><code>/etc/yum</code><code>.repos.d/ owner=root group=root mode=0755</code>
<code>- name: Install Nginx Web Server</code>
<code> </code><code>yum: name=nginx state=latest</code>
<code>- name: write nginx config</code>
<code> </code><code>template: src=nginx2.conf dest=</code><code>/etc/nginx/nginx</code><code>.conf</code>
<code>- name: check nginx running</code>
<code>[root@localhost playbook]</code><code># cat nginx/roles/web/templates/nginx2.conf</code>
<code>user nginx;</code>
<code>worker_processes {{ worker_processes }};</code>
<code>worker_rlimit_nofile {{ max_open_file }};</code>
<code>error_log </code><code>/var/log/nginx/error</code><code>.log warn;</code>
<code>pid </code><code>/var/run/nginx</code><code>.pid;</code>
<code>events {</code>
<code> </code><code>worker_connections 204800;</code>
<code> </code><code>use epoll;</code>
<code> </code><code>multi_accept on;</code>
<code>http {</code>
<code> </code><code>include </code><code>/etc/nginx/mime</code><code>.types;</code>
<code> </code><code>default_type application</code><code>/octet-stream</code><code>;</code>
<code> </code><code>log_format main </code><code>'$remote_addr - $remote_user [$time_local] "$request" '</code>
<code> </code><code>'$status $body_bytes_sent "$http_referer" '</code>
<code> </code><code>'"$http_user_agent" "$http_x_forwarded_for"'</code><code>;</code>
<code> </code><code>access_log </code><code>/var/log/nginx/access</code><code>.log main;</code>
<code> </code><code>sendfile on;</code>
<code> </code><code>server_tokens off;</code>
<code> </code><code>tcp_nopush on;</code>
<code> </code><code>keepalive_timeout 10;</code>
<code> </code><code>client_header_timeout 10;</code>
<code> </code><code>client_body_timeout 10;</code>
<code> </code><code>reset_timedout_connection on;</code>
<code> </code><code>send_timeout 10;</code>
<code> </code><code>#limit_conn_zone $binary_remote_addr zone=addr:10m;</code>
<code> </code><code>#limit_conn addr 100;</code>
<code> </code><code>gzip</code> <code>on;</code>
<code> </code><code>gzip_min_length 1000;</code>
<code> </code><code>gzip_comp_level 4;</code>
<code> </code><code>include </code><code>/etc/nginx/conf</code><code>.d/*.conf;</code>
<code>[root@localhost playbook]</code><code># cat nginx/site.yml</code>
<code>- name: comment settings</code>
<code> </code><code>hosts: all</code>
<code> </code><code>- common</code>
<code>- name: Deploy webserver</code>
<code> </code><code>hosts: webserver</code>
<code> </code><code>- web</code>
擷取遠端主機系統資訊:Facts
facts是一個非常有用的元件,類似于Saltstack的Grains功能,實作擷取遠端主機的系統資訊,包括主機名,IP位址,作業系統,分區資訊,硬體資訊等。可以配合playbook實作更加個性化和靈活的要求。比如在httpd.conf模闆中引用Facts的主機名資訊作為ServerName參數的值。通過運作 ansible-playbook -m setup 可擷取Facts資訊 例如 擷取192.168.137.8 的Facts資訊需要運作
ansible-playbook 192.168.137.8 -m setup 結果如下:
<code>[root@localhost ~]</code><code># ansible 192.168.137.8 -m setup</code>
<code> </code><code>"ansible_facts"</code><code>: {</code>
<code> </code><code>"ansible_all_ipv4_addresses"</code><code>: [</code>
<code> </code><code>"192.168.137.8"</code>
<code> </code><code>],</code>
<code> </code><code>"ansible_all_ipv6_addresses"</code><code>: [</code>
<code> </code><code>"fe80::20c:29ff:fe7a:596d"</code>
<code> </code><code>"ansible_architecture"</code><code>: </code><code>"x86_64"</code><code>,</code>
<code> </code><code>"ansible_bios_date"</code><code>: </code><code>"05/20/2014"</code><code>,</code>
<code> </code><code>"ansible_bios_version"</code><code>: </code><code>"6.00"</code><code>,</code>
<code> </code><code>"ansible_cmdline"</code><code>: {</code>
<code> </code><code>"KEYBOARDTYPE"</code><code>: </code><code>"pc"</code><code>,</code>
<code> </code><code>"KEYTABLE"</code><code>: </code><code>"us"</code><code>,</code>
<code> </code><code>"LANG"</code><code>: </code><code>"en_US.UTF-8"</code><code>,</code>
<code> </code><code>"SYSFONT"</code><code>: </code><code>"latarcyrheb-sun16"</code><code>,</code>
<code> </code><code>"crashkernel"</code><code>: </code><code>"auto"</code><code>,</code>
<code> </code><code>"quiet"</code><code>: </code><code>true</code><code>,</code>
<code> </code><code>"rd_LVM_LV"</code><code>: </code><code>"vg_serv/lv_root"</code><code>,</code>
<code> </code><code>"rd_NO_DM"</code><code>: </code><code>true</code><code>,</code>
<code> </code><code>"rd_NO_LUKS"</code><code>: </code><code>true</code><code>,</code>
<code> </code><code>"rd_NO_MD"</code><code>: </code><code>true</code><code>,</code>
<code> </code><code>"rhgb"</code><code>: </code><code>true</code><code>,</code>
<code> </code><code>"ro"</code><code>: </code><code>true</code><code>,</code>
<code> </code><code>"root"</code><code>: </code><code>"/dev/mapper/vg_serv-lv_root"</code>
<code> </code><code>},</code>
<code> </code><code>"ansible_date_time"</code><code>: {</code>
<code> </code><code>"date"</code><code>: </code><code>"2016-07-26"</code><code>,</code>
<code> </code><code>"day"</code><code>: </code><code>"26"</code><code>,</code>
<code> </code><code>"epoch"</code><code>: </code><code>"1469546980"</code><code>,</code>
<code> </code><code>"hour"</code><code>: </code><code>"23"</code><code>,</code>
<code> </code><code>"iso8601"</code><code>: </code><code>"2016-07-26T15:29:40Z"</code><code>,</code>
<code> </code><code>"iso8601_basic"</code><code>: </code><code>"20160726T232940834874"</code><code>,</code>
<code> </code><code>"iso8601_basic_short"</code><code>: </code><code>"20160726T232940"</code><code>,</code>
<code> </code><code>"iso8601_micro"</code><code>: </code><code>"2016-07-26T15:29:40.835071Z"</code><code>,</code>
<code> </code><code>"minute"</code><code>: </code><code>"29"</code><code>,</code>
<code> </code><code>"month"</code><code>: </code><code>"07"</code><code>,</code>
<code> </code><code>"second"</code><code>: </code><code>"40"</code><code>,</code>
<code> </code><code>"time"</code><code>: </code><code>"23:29:40"</code><code>,</code>
<code> </code><code>"tz"</code><code>: </code><code>"CST"</code><code>,</code>
<code> </code><code>"tz_offset"</code><code>: </code><code>"+0800"</code><code>,</code>
<code> </code><code>"weekday"</code><code>: </code><code>"Tuesday"</code><code>,</code>
<code> </code><code>"weekday_number"</code><code>: </code><code>"2"</code><code>,</code>
<code> </code><code>"weeknumber"</code><code>: </code><code>"30"</code><code>,</code>
<code> </code><code>"year"</code><code>: </code><code>"2016"</code>
<code> </code><code>"ansible_default_ipv4"</code><code>: {</code>
<code> </code><code>"address"</code><code>: </code><code>"192.168.137.8"</code><code>,</code>
<code> </code><code>"alias"</code><code>: </code><code>"eth1"</code><code>,</code>
<code> </code><code>"broadcast"</code><code>: </code><code>"192.168.137.255"</code><code>,</code>
<code> </code><code>"gateway"</code><code>: </code><code>"192.168.137.1"</code><code>,</code>
<code> </code><code>"interface"</code><code>: </code><code>"eth1"</code><code>,</code>
<code> </code><code>"macaddress"</code><code>: </code><code>"00:0c:29:7a:59:6d"</code><code>,</code>
<code> </code><code>"mtu"</code><code>: 1500,</code>
<code> </code><code>"netmask"</code><code>: </code><code>"255.255.255.0"</code><code>,</code>
<code> </code><code>"network"</code><code>: </code><code>"192.168.137.0"</code><code>,</code>
<code> </code><code>"type"</code><code>: </code><code>"ether"</code>
<code>.......................省略</code>
在模闆檔案中這樣引用Facts資訊
` ansible_device`.`sda`.`model `
` ansible_hostname `
Jinja2過濾器
使用格式:{{ 變量名 | 過濾方法 }}
示例:擷取一個檔案路徑變量過濾出檔案名
{{ path | basename }}
擷取檔案所處的目錄名:
{{ path | dirname }}
下面為一個完整的示例,實作從/etc/profile 中過濾出檔案名 profile 并輸出重定向到/tmp/testshell檔案中
<code>- hosts: 192.168.1.21</code>
<code> </code><code>filename: </code><code>/etc/profile</code>
<code> </code><code>- name: </code><code>"shell"</code>
<code> </code><code>shell: </code><code>echo</code> <code>{{ filename | </code><code>basename</code> <code>}} >> </code><code>/tmp/testshell</code>
本地Facts
我們可以通過Facts來擷取目标主機的系統資訊,當這些資訊不能滿足我們功能需求時,可以通過編寫自定義的facts子產品來實作。當然 還有一個更簡單的辦法 就是通過本地facts來實作。 隻需要在目标裝置/etc/ansible/facts.d目錄定義JSON、INI或可執行檔案的JSON輸出 檔案擴充名使用“.fact” 這些檔案都可以作為Ansible本地Facts 例如 在目标裝置 192.168.137.9 定義三個變量 供以後playbook使用
【/etc/ansible/facts.d/preferences.fact】
[general]
max_memory_size=32
max_user_processes=3730
open_files=65535
在主要端運作ansible 192.168.1.21 -m setup -a "filter=ansible_local" 可以看到定義的結果 傳回結果如下:
<code>[root@localhost ~]</code><code># ansible 192.168.137.9 -m setup -a "filter=ansible_local"</code>
<code> </code><code>"ansible_local"</code><code>: {</code>
<code> </code><code>"preferences"</code><code>: {</code>
<code> </code><code>"general"</code><code>: {</code>
<code> </code><code>"max_memory_size"</code><code>: </code><code>"32"</code><code>,</code>
<code> </code><code>"max_user_processes"</code><code>: </code><code>"3730"</code><code>,</code>
<code> </code><code>"open_files"</code><code>: </code><code>"65535"</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>},</code>
<code> </code><code>"changed"</code><code>: </code><code>false</code>
<code>[root@localhost ~]</code><code>#</code>
注冊變量:
變量的另一個用途是将一條指令的運作結果儲存到變量中,供後面的playbook使用 下面是一個簡單的示例
<code> </code><code>- shell: </code><code>/usr/bin/foo</code>
<code> </code><code>register: foo_result</code>
<code> </code><code>ignore_errors:True</code>
<code> </code><code>- shell: </code><code>/usr/bin/bar</code>
<code> </code><code>when: foo_result.rc == 5</code>
上述例子注冊了一個foo_result的變量 值為shell:/usr/bin/foo的運作結果。ingore_error為忽略錯誤。變量注冊完成後。就可以在後面的playbook中使用了。當條件語句when:foo_result.rc == 5成立時 shell:/usr/bin/bar指令才會運作,其中foo_result.rc為傳回/usr/bin/foo的resultcode 傳回碼 例如 傳回rc=0的傳回碼
<code>[root@localhost ~]</code><code># ansible 192.168.137.9 -a "free -m"</code>
<code>192.168.137.9 | SUCCESS | rc=0 >></code>
<code> </code><code>total used </code><code>free</code> <code>shared buffers cached</code>
<code>Mem: 1989 601 1387 0 63 252</code>
<code>-/+ buffers</code><code>/cache</code><code>: 285 1704</code>
<code>Swap: 2015 0 2015</code>
條件語句:
有時候一個playbook的結果取決于一個變量 或者取決于上一個任務的執行結果.在某些情況下 一個變量的值可以依賴于其他變量的值 當然也會影響Ansible的執行過程。
下面主要介紹when聲明:
有時候我們想跳過某些主機的執行步驟 比如符合特定版本的作業系統将不安裝某個軟體。在Ansible中很容易做到這一點 通過when 子句實作 其中将引用jinja2表達式 如下示例:
<code> </code><code>- name: </code><code>"shutdown Debian flavored systems"</code>
<code> </code><code>command</code><code>: </code><code>/sbin/shutdown</code> <code>-t now</code>
<code> </code><code>when: ansible_os_family == </code><code>"Debian"</code>
通過定義任務的facts本地變量 ansible_os_family 作業系統版本名稱是否為Debian 結果将傳回BOOL類型值,為True時将執行上一條語句 command:/sbin/shutdown -t now 為False時該條語句都不會觸發 。看另一個示例 通過判斷一條指令執行結果做不同的處理。
<code> </code><code>- </code><code>command</code><code>: </code><code>/bin/false</code>
<code> </code><code>register: result</code>
<code> </code><code>ingore_error: True</code>
<code> </code><code>- </code><code>command</code><code>: </code><code>/bin/someting</code>
<code> </code><code>when: result|failed</code>
<code> </code><code>- </code><code>command</code><code>: </code><code>/bin/someting_else</code>
<code> </code><code>when: result|success</code>
<code> </code><code>- </code><code>command</code><code>: </code><code>/bin/still/someting</code>
<code> </code><code>when: result|skipped</code>
when:result|success的意思當變量result的執行結果為成功狀态時 将執行/bin/someting_else指令 其他同理。其中success為ansible内部過濾器方法 傳回True代表運作成功。
循環:
通常一個任務會做很多事情,例如建立大量的使用者,安裝很多包 或者重複特定步驟 直到某種結果條件為止.ansible為我們提供了此支援。示例如下:
<code>- name: add several </code><code>users</code>
<code> </code><code>user: name={{ item }} state=present </code><code>groups</code><code>=wheel</code>
<code> </code><code>with_items:</code>
<code> </code><code>- testuser1</code>
<code> </code><code>- testuser2</code>
這個示例實作了一個批量建立使用者的功能 with_items會自動循環執行上面的語句 user: name=` item ` state=present groups=wheel 循環次數為with_items的元素個數。這裡有兩個元素 分别是testuser1 和 testuser2 會分别替換 ` item `項 這個示例與下面的語句是等價的:
<code>- name: add user testuser1</code>
<code> </code><code>user: name=testuser1 state=present </code><code>groups</code><code>=wheel</code>
<code>- name: add user testuser2</code>
<code> </code><code>user: name=testuser2 state=present </code><code>groups</code><code>=wheel</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>
循環也支援list形式 不過是通過with_flattened語句實作 如下示例:
<code>packages_base:</code>
<code> </code><code>- [ </code><code>'foo-packages'</code><code>,</code><code>'bar-packages'</code><code>]</code>
<code>packages_apps:</code>
<code> </code><code>- [ [</code><code>'one-packages'</code><code>,</code><code>'two-packages'</code><code>] ]</code>
<code> </code><code>- [ [</code><code>'red-packages'</code><code>],[</code><code>'blue-packages'</code><code>] ]</code>
以上定義了兩個清單變量,分别是需要安裝的軟體包名 以便後面如下引用:
<code>- name: flattened loop demo</code>
<code> </code><code>yum: name={{ item }} state=installed</code>
<code> </code><code>with_flattened:</code>
<code> </code><code>- packages_base</code>
<code> </code><code>- packages_apps</code>
<code></code>
本文轉自flyingzf 51CTO部落格,原文連結:http://blog.51cto.com/flyingzf/1828641,如需轉載請自行聯系原作者