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