ansible

ansible是一款自動化運維工具,基于python開發,他是基于各個模塊來工作的,主要由以下幾個組件:

  • connection plugins:用來和需要操作的遠程主機通信的,由于ansible是無agent方式,所以需要一種連接方式,一般使用ssh來作為通信方式;
  • host inventory:用來指定需要操作的遠程主機ip地址,配置文件默認為/etc/ansible/hosts;
  • playbook:劇本,就是將事先定義好的需要在哪些遠程主機上執行什么操作,寫到playbook文件中,然后讓ansibles去讀取劇本文件并操作;
  • core modules:核心模塊,ansible是通過模塊去到遠程主機上執行操作的
  • custom modules:自定義模塊,除了自帶的模塊,用戶也可以自定義模塊
  • plugins:一些功能插件,用來實現日志,郵件等功能

結構圖如下:

ansible命令

ansible命令是命令行工具,不需要讀取playbook文件
ansible :

  • -m:指名模塊
  • -a:給模塊指定參數,寫在“”里邊,如果是命令就直接寫進去就行
  • -C:測試執行,不真正執行
  • -f:一批處理幾個,默認為5
  • -i:指定hosts文件
  • --list-hosts:列出這次操作對哪些主機執行,只是列出
  • --syntax-check:檢查語法
  • -t:在文件中定義tags后使用這個選項只運行tags那一部分
  • -c:連接方式 smart為默認,智能選擇合適的方式
  • -u USERNAME:連接時使用的用戶名,默認為none
  • -s:sudo
  • -S:su

ansible-playbook命令

運行playbook使用ansible-playbook命令,常用參數如下:

  • --syntax-check:檢測語法
  • -C:測試運行,檢查錯誤時候使用,不是真正在目標主機上運行
  • --list-hosts:顯示要執行的主機
  • -t TAGS:使用文件中有標簽的地方,只執行標簽處的任務
    -e VARS:使用變量

模塊

ansible是通過模塊來工作的,所以下面介紹各種功能的模塊:
首先用ansible-doc -l命令可以列出模塊,可以看到有非常多的模塊可以使用,這里我們就據介紹一些比較重要的經常用的模塊,使用ansible-doc -s 模塊名可以查看模塊的參數,用來定義模塊的期望值
模塊可以定義期望的目標狀態,而且操作必須時冪等的(重復數次的結果是相同的,都是定義的期望的狀態),如下為一些常用的模塊,例子都是使用命令行工具ansible來寫的:

1.group模塊

ansible all -m group -a "gid=3000 name=mygrp state=present system=no" 

state=absent表示刪除組,present表示創建組,system=no表示不是系統組
2.user模塊

ansible all -m usre -a "uid=5000 name=testuser state=present groups=mygrp shell=/bin/tcsh"

表示用戶的uid為5000,用戶名為testuser,狀態為創建用戶,組名為mygrp,使用默認shell為/bin/tcsh
3.copy模塊
src選項的值為目錄時,最后帶/斜杠表示不復制目錄本身,不帶就表示復制目錄本身,src可以為空,用content表示所跟的內容直接生成到目標遠程主機文件,不跟dest就源是哪里,目標目錄就是哪里,remote_src表示使用遠程的源,state=absent表示刪除

ansible all -m copy -a "src=/etc/fstab dest=/tmp/test mode=600"
ansible all -m  copy -a "content='haha\nhehe\n‘ dest =/tmp/hehe  owner=testuser"

4.fetch模塊
將遠程主機復制到本機,偶爾會用到,不用指定多個主機

command模塊
遠程主機執行命令:chdir,切換目錄;executable,由哪個shell發起執行命令.command命令在執行時不適用shell,所以傳遞|或者>等參數時不識別,所以要使用shell模塊
6.shell模塊
解決了command的不識別,其他和command一樣
7.file模塊
用來創建文件(不推薦,一般用copy,content=空去創建),設定文件屬性,path=定義目標文件,state=file|directory

ansible all -m file  -a "path=/tmp/hello.dir state=directory"

8.cron模塊
指定計劃任務,分時日月周和crontab一樣,要定義哪個就將哪個寫進去

ansible all -m cron -a "minute=*/3 job='/usr/sbin/ntpdate 172.16.0.1 &> /dev/null' name=None "

9.yum模塊
name=要安裝的包名;state=installd|removed|latest;disable_gpg_check=yes表示禁用gpgcheck

ansible all -m yum -a "name=nginx state=installed disabled_gpg_check=yes"

10.service模塊
name=服務名;enabled=yes表示開機啟用;runlevel在設置開機啟用后指定運行的級別;state=started|stopped|restarted|reloaded;

ansible all -m service -a "name=nginx enabled=true state=started"

11.script模塊
本地文件在遠程執行,遠程自己的腳本用shell模塊就行

ansible all -m script  -a "腳本路徑"

12.setup模塊
用來收集對應主機的信息,信息中有很多內建變量可以直接使用,下面講到變量時候再說這個模塊

playbook

命令行方式不能復用,我們可以講每臺主機需要執行的操作寫入配置文件playbook,讓ansible去讀取并執行。
YAML格式:ansible相關文件的格式為YAML,是一種可讀性高,用來表達數據序列的格式,基本數據結構為:標量,數組,關聯數組.

playbook基本元素:

  • hosts:運行指定任務的目標主機
    remoute_user:遠程主機上執行任務的用戶
    sudo_user:sudo的用戶
  • tasks:任務
    name:任務名字
    module:模塊參數
    tags:標簽,可以使用ansible-playbook 的-t選項來指定,只執行本標簽的任務
  • handlers:特定條件觸發的任務,在一個任務中定義notify,然后這個任務觸發之后會通知這個handlers執行操作

還有一些別的元素我們在下面的大標題中挨個講解,我們先來看這些基礎元素的用法:

下面我們來創建一個playbook文件,并執行,注意,一定要縮進:

[root@localhost ansible]# vim /etc/ansible/test.yml
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: install redis
    yum: name=redis state=latest
  - name: start redis
    service: name=redis state=started

然后去檢測

[root@localhost ansible]# ansible-playbook --syntax-check  test.yml

playbook: test.yml
[root@localhost ansible]# ansible-playbook -C  test.yml

PLAY [172.16.200.107] **********************************************************

TASK [setup] *******************************************************************
ok: [172.16.200.107]

TASK [install redis] ***********************************************************
ok: [172.16.200.107]

TASK [start redis] *************************************************************
changed: [172.16.200.107]

PLAY RECAP *********************************************************************
172.16.200.107             : ok=3    changed=1    unreachable=0    failed=0   

檢測成功后就可以執行了

ansible-playbook  test.yml

執行成功的返回結果和測試的一樣,所以就不再顯示了

變量variables:

變量有四種:
1.內建變量
facter -p:收集本機信息,ansible中有個同樣功能的模塊,叫做setup,用ansible-doc -s setup查看這個模塊
用ansible 172.16.200.107 -m setup 就可以收集目標主機的很多信息了,比facter收集到的信息更多,有很多內建的變量,直接就可以使用了.
使用示例:

[root@localhost ansible]# vim /etc/ansible/test1.yml                                                                         
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: copy file
    copy: content={{ ansible_env }} dest=/tmp/ansible_env    #{{}}和變量名字之間要加上空格
[root@localhost ansible]# ansible-playbook --syntax-check  test1.yml
[root@localhost ansible]# ansible-playbook -C  test1.yml
[root@localhost ansible]# ansible-playbook   test1.yml

然后到172.16.200.107的/tmp目錄中查看ansible_env文件,看到里邊是本機的各種信息,這個ansible_env就是變量

2.自定義變量
先在文件中定義變量

[root@localhost ansible]# vim /etc/ansible/test2.yml
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: install {{ packgs }}    #{{}}和變量名字之間要加上空格
    yum: name={{ packgs }} state=latest

然后使用的時候調用定義的變量就可以了

[root@localhost ansible]# ansible-playbook --syntax-check test2.yml
[root@localhost ansible]# ansible-playbook  -e packgs=httpd  -C test2.yml
[root@localhost ansible]# ansible-playbook  -e packgs=httpd test2.yml

3.Host Inventory主機文件變量
就是定義在主機文件中的變量,主機文件默認為/etc/ansible/hosts文件,其格式分為兩種,變量也有兩種,一種可以自定義變量,在模板文件中可以調用,另一種是使用系統本身自帶的invertory參數,這個參數是用于定義ansible遠程連接目標主機時使用的參數,而非傳遞給playbook的變量,常用的有以下幾種:
ansible_ssh_host
ansible_ssh_port
ansible_ssh_user
ansible_ssh_pass
ansbile_sudo_pass
兩種格式:
(a) 單臺主機變量
向不同的主機傳遞不同的變量,在每臺主機之后加上變量=值就可以調用了,格式為
IP/HOSTNAME varaiable=value var2=value2
為了驗證,首先,我們給172.16.200.107上創建用戶feng,密碼設置為123

[root@localhost ansible]# ansible 172.16.200.107  -m user -a "name=feng"    #注意,這里使用password=密碼的選項,設置的密碼不是登陸密碼,所以還是要使用下一步這種方式
[root@localhost ansible]# ansible 172.16.200.107 -m shell -a "echo 123|passwd --stdin feng"

然后,修改/etc/ansible/hosts文件,這里我們用invertory參數來演示,自定義變量在說到模板時候在用

[web]
172.16.200.107 ansible_ssh_user=feng ansible_ssh_pass=123
172.16.200.108

測試

[root@localhost ansible]# ansible 172.16.200.107 -m ping
172.16.200.107 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

(b)組變量
向組中的主機傳遞相同的變量,就是當組中的每個元素需要設定一個相同的變量時,就可以用這種方式來實現
[groupname:vars]
variable=value
如果107和108兩個主機都需要使用feng用戶登陸,而密碼都是123,那么使用組變量,將之前的設置改一下就可以了,到/etc/ansible/hosts文件中

[web]
172.16.200.107
172.16.200.108 
[web:vars]
 ansible_ssh_user=feng ansible_ssh_pass=123

這樣,組變量就定義好了,組中的每個元素都使用這個定義的變量

4.roles定義變量
在playbook中,加入如下這一段

vars:
 - pbvar: playbook var

就可以直接調用了,這種方式主要是在定義角色中使用,詳細的在說到角色時候在說明
注意:命令行中調用的變量中間有空格會只顯示空格之前的內容

模板templates

ansible-doc -s templates
內嵌一段代碼,由模板引擎解析,可以實現變量替換,算數運算等功能,文件中其他內容不變,這種文件叫做模板文件。他們是用模板模塊生成的,著名的模板模塊叫做python-jinja2,python-jinja2是一個模板引擎,用配置文件后綴為.j2,然后寫的時候用python的語法來寫.
下面我們創建一個顯示本主機ip地址的文件,發給172.16.200.107和108,所以每個主機收到文件內容都是不同的,就實現了模板文件的用法:

root@localhost ansible]# ansible 172.16.200.107 -m setup |less    #隨便找一臺主機獲取顯示主機ip的變量名為ansible_ens33.ipv4.address
[root@localhost ansible]# vim /etc/ansible/ip.j2    #定義模板文件,加入如下內容
ipaddress: {{ ansible_ens33.ipv4.address }}
[root@localhost ansible]# vim /etc/ansible/test3.yml    #寫playbook文件,注意template模板不能在命令行中被調用
- hosts: all
  remote_user: root
  tasks:
  - name: template test
    template: src=/etc/ansible/ip.j2 dest=/tmp/
[root@localhost ansible]# ansible-playbook -C test3.yml 
[root@localhost ansible]# ansible-playbook  test3.yml 

然后到107和108中查看/tmp/ip.j2文件,發現分別為172.16.200.107和172.16.200.108,證明模板引擎已經將變量解析為本機ip了。

條件測試when

可以在tasks中使用,判定條件滿足時候才會執行當前任務,我們用版本號舉例,當107的版本為7時,就執行寫一個centos7字符串到107主機的/tmp/versions文件中,6的話就寫6

[root@localhost ansible]# vim test4.yml
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: test when
    copy: content="centos7" dest=/tmp/versions
    when: ansible_distribution_major_version == "7"
  - name: test when
    copy: content="centos6" dest=/tmp/versions
    when: ansible_distribution_major_version == "6"
[root@localhost ansible]# ansible-playbook test4.yml     #執行

PLAY [172.16.200.107] **********************************************************

TASK [setup] *******************************************************************
ok: [172.16.200.107]

TASK [test when] ***************************************************************
changed: [172.16.200.107]

TASK [test when] ***************************************************************
skipping: [172.16.200.107]    

PLAY RECAP *********************************************************************
172.16.200.107             : ok=2    changed=1    unreachable=0    failed=0   

我們看到第二個任務skip跳過了,就是因為107是centos7的系統,當檢測不是6的時候,第二個任務就跳過了,我們也可以在107中查看/tmp/versions文件,顯示的為"centos7"

循環迭代with_items

當有很多需要重復執行而任務內容不變的參數時候,重復的寫任務會很麻煩,這個時候需要用到循環,更加高效的來寫參數不同,但是任務過程相同的任務

[root@localhost ansible]# vim /etc/ansible/test5.yml
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: install {{ item }}  packges
    yum: name={{ item }} state=latest
    with_items:
    - nginx
    - varnish
[root@localhost ansible]# ansible-playbook  test5.yml

完成后,我們會看到nginx和varnish都被安裝上了

也可以用字典來迭代:
user: name={{item.name}} group={{item.group}}
with_items:
- {name: 'feng',group:'fengkp'}
- ...
這里就不在列出字典的用法了。

角色

自包含的目錄結構,就是在一個目錄中放入部署這一套服務的各種需要的組件.說白了就是將playbook中的各項組件拆分在各個子文件夾中,由一個主目錄將所有內容包含在其中,這樣做的好處是條理清楚,修改時候比較方便。
目錄結構如下:

  • files/ :存放由copy或script模塊等調用的文件;
  • templates/:template模塊查找所需要模板文件的目錄;
  • tasks/:至少應該包含一個名為main.yml的文件;其它的文件需要在此文件中通過include進行包含;
  • handlers/:至少應該包含一個名為main.yml的文件;其它的文件需要在此文件中通過include進行包含;
  • vars/:至少應該包含一個名為main.yml的文件;其它的文件需要在此文件中通過include進行包含;
  • meta/:至少應該包含一個名為main.yml的文件,定義當前角色的特殊設定及其依賴關系;其它的文件需要在此文件中通過include進行包含;
  • default/:設定默認變量時使用此目錄中的main.yml文件;

下面我們來創建一個nginx角色:

mkdir -pv /etc/ansible/roles/nginx/{files,templates,tasks,vars,handlers,meta,default}
[root@localhost ansible]# cd /etc/ansible/roles/nginx/
[root@localhost nginx]# vim tasks/main.yml
- name: install nginx
  yum: name=nginx state=latest
  when: ansible_os_family == "RedHat"

有一個任務,我們就可以使用了,使用的話在playbook中調用需要使用roles 加上角色名就可以:

[root@localhost nginx]# vim /etc/ansible/nginx.yml
- hosts: 172.16.200.107
  remote_user: root
  roles:
  - nginx

測試

[root@localhost ansible]# ansible-playbook nginx.yml

當然,這里只使用了tasks元素,如果由其他元素的話,就寫在相應的目錄下的main.yml文件中就可以,注意寫腳本的main.yml的文件時候,由于腳本沒有鍵值,所以不是list,不用加前邊的-符號。下面我們通過一個大實驗來熟練ansible的操作

實驗

通過ansible來實現一個架構,架構圖如下:

環境:

  • 各個節點時間同步,selinux和iptables關閉
  • ansible服務器:172.16.200.109
  • 172.16.200.102:部署nginx反代調度器1,部署keepalived,部署varnish服務1
  • 172.16.200.103:部署nginx反代調度器2,部署keepalived,部署varnish服務2
  • vip:172.16.200.200
  • 172.16.200.104:后端nginx節點1,tomcat節點1,mysql主節點,redis主節點
  • 172.16.200.105:后端nginx節點2,tomcat節點2,mysql從節點和redis從節點

實現步驟:
我們將結構拆分為靜態和動態兩條,靜態的結構如下:

先來實現靜態這條路線上的nginx,tomcat和redis
1.幾臺主機之間設置ssh密鑰互信
在ansible服務端172.16.200.109執行

[root@localhost ansible]# ssh-keygen -t rsa -P ""
[root@localhost ansible]# for i in {2..5};do ssh-copy-id 172.16.200.10$i;done

分別用ssh登陸上去測試是否已經互信,成功后進入下一步
2.在ansible主機設置/etc/ansible/hosts文件,將主機分組

[director]
172.16.200.10[2:3]

[node]
172.16.200.10[4:5]

3.實現nginx角色,并安裝
在ansible主機上
設置nginx配置文件

[root@localhost ansible]# mkdir -p /etc/ansible/roles/nginx/{files,templates,tasks,vars,handlers,meta,default}
[root@localhost ansible]# cd /etc/ansible/roles/nginx/
[root@localhost nginx]# vim files/nginx_ansible.conf
upstream varnish {
        server 172.16.200.102:6081;
        server 172.16.200.103:6081;
}
upstream tomcat {
        server 172.16.200.104:8080;
        server 172.16.200.105:8080;
}
server {
        listen 80;
        server_name www.feng.com;

        location  ~ .*\.(js|css|htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$ {
                proxy_pass http://varnish;
        }
        location ~ \.(jsp|jspx|do|action)(\/.*)?$ {
                proxy_pass http://tomcat;
        }
}

設置nginx任務文件

[root@localhost nginx]# vim tasks/main.yml
- name: install nginx
  yum: name=nginx state=latest
  when: ansible_os_family == "RedHat"
- name: delete default.conf
  shell: rm -f /etc/nginx/conf.d/default.conf
- name: install nginx config
  copy: src=nginx_ansible.conf dest=/etc/nginx/conf.d/
- name: start nginx
  service: name=nginx state=started

設置執行nginx的playbook文件

[root@localhost nginx]# vim nginx.yml
- hosts: director
  remote_user: root
  roles:
  - nginx

然后執行安裝

[root@localhost nginx]# ansible-playbook --syntax-check nginx.yml
[root@localhost nginx]# ansible-playbook  nginx.yml 

PLAY [director] ****************************************************************

TASK [setup] *******************************************************************
ok: [172.16.200.102]
ok: [172.16.200.103]

TASK [nginx : install nginx] ***************************************************
changed: [172.16.200.103]
changed: [172.16.200.102]

TASK [nginx : delete default.conf] *********************************************
changed: [172.16.200.103]
 [WARNING]: Consider using file module with state=absent rather than running rm

changed: [172.16.200.102]

TASK [nginx : install nginx config] ********************************************
changed: [172.16.200.103]
changed: [172.16.200.102]

TASK [nginx : start nginx] *****************************************************
changed: [172.16.200.103]
changed: [172.16.200.102]

PLAY RECAP *********************************************************************
172.16.200.102             : ok=5    changed=4    unreachable=0    failed=0   
172.16.200.103             : ok=5    changed=4    unreachable=0    failed=0

第一步成功
4.實現tomcat角色并安裝
創建目錄結構并設置任務文件

[root@localhost nginx]# mkdir -p /etc/ansible/roles/tomcat/{files,templates,tasks,vars,handlers,meta,default}
[root@localhost nginx]# cd /etc/ansible/roles/tomcat/
[root@localhost tomcat]# vim tasks/main.yml
- name: install openjdk
  yum: name=java-1.8.0-openjdk-devel state=latest
  when: ansible_os_family == "RedHat"
- name: install tomcat
  yum: name={{ item }} state=latest
  with_items:
  - tomcat-lib
  - tomcat-admin-webapps
  - tomcat-docs-webapp
  - tomcat-webapps
- name: start tomcat
  service: name=tomcat state=started

設置tomcat的playbook文件

[root@localhost tomcat]# vim tomcat.yml
- hosts: node
  remote_user: root
  roles:
  - tomcat

執行安裝

[root@localhost tomcat]# ansible-playbook  tomcat.yml

PLAY [node] ********************************************************************

TASK [setup] *******************************************************************
ok: [172.16.200.105]
ok: [172.16.200.104]

TASK [tomcat : install openjdk] ************************************************
changed: [172.16.200.104]
changed: [172.16.200.105]

TASK [tomcat : install tomcat] *************************************************
changed: [172.16.200.105] => (item=[u'tomcat-lib', u'tomcat-admin-webapps', u'tomcat-docs-webapp', u'tomcat-webapps'])
changed: [172.16.200.104] => (item=[u'tomcat-lib', u'tomcat-admin-webapps', u'tomcat-docs-webapp', u'tomcat-webapps'])

TASK [tomcat : start tomcat] ***************************************************
changed: [172.16.200.104]
changed: [172.16.200.105]

PLAY RECAP *********************************************************************
172.16.200.104             : ok=4    changed=3    unreachable=0    failed=0   
172.16.200.105             : ok=4    changed=3    unreachable=0    failed=0  

成功,可以接著下一步了
5.動態的安裝完成后安裝靜態這條線
首先要安在兩個調度器節點上安裝varnish
創建目錄并設置varnish配置文件

[root@localhost tomcat]#  mkdir -p /etc/ansible/roles/varnish/{files,templates,tasks,vars,handlers,meta,default}
[root@localhost tomcat]# cd /etc/ansible/roles/varnish/
[root@localhost varnish]# vim files/default.vcl
import directors;
backend web1 {
    .host="172.16.200.104";
    .port="80";
}

backend web2 {
    .host="172.16.200.105";
    .port="80";
}

sub vcl_init {
        new server = directors.round_robin();
        server.add_backend(web1);
        server.add_backend(web2);
}
sub vcl_recv {
    if (req.method == "PURGE") {
        return(purge);
}
    set req.backend_hint = server.backend();

}
sub vcl_pipe {
        return (pipe);
}

sub vcl_pass {
        return (fetch);
}

設置任務文件

[root@localhost varnish]# vim tasks/main.yml
- name: install varnish
  yum: name=varnish state=latest
  when: ansible_os_family == "RedHat"
- name: install varnish config
  copy: src=default.vcl dest=/etc/varnish
- name: start varnish
  service: name=varnish state=started

設置varnish的playbook

- hosts: director
  remote_user: root
  roles:
  - varnish
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容