Ansible 簡單入門

安裝:

先安裝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常用模塊

  1. 遠程命令模塊

   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


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