一、ansible
1.1、ansible
ansible基于Python開發(fā),集合了眾多運維工具(puppet、chef、func、fabric)的優(yōu)點,實現(xiàn)了批量系統(tǒng)配置、批量程序部署、批量運行命令等功能。ansible是基于 paramiko 開發(fā)的,并且基于模塊化工作,本身沒有批量部署的能力。真正具有批量部署的是ansible所運行的模塊,ansible只是提供一種框架。ansible不需要在遠程主機上安裝client/agents,因為它們是基于ssh來和遠程主機通訊的。ansible目前已經已經被紅帽官方收購,是自動化運維工具中大家認可度最高的,并且上手容易,學習簡單。是每位運維工程師必須掌握的技能之一。
1.2、ansible特點
部署簡單,只需在主控端部署Ansible環(huán)境,被控端無需做任何操作;
默認使用SSH協(xié)議對設備進行管理;
有大量常規(guī)運維操作模塊,可實現(xiàn)日常絕大部分操作;
配置簡單、功能強大、擴展性強;
支持API及自定義模塊,可通過Python輕松擴展;
通過Playbooks來定制強大的配置、狀態(tài)管理;
輕量級,無需在客戶端安裝agent,更新時,只需在操作機上進行一次更新即可;
提供一個功能強大、操作性強的Web管理界面和REST API接口——AWX平臺。
1.3、ansible架構圖

Ansible:Ansible核心程序。
HostInventory:記錄由Ansible管理的主機信息,包括端口、密碼、ip等。
Playbooks:“劇本”YAML格式文件,多個任務定義在一個文件中,定義主機需要調用哪些模塊來完成的功能。
CoreModules:核心模塊,主要操作是通過調用核心模塊來完成管理任務。
CustomModules:自定義模塊,完成核心模塊無法完成的功能,支持多種語言。
ConnectionPlugins:連接插件,Ansible和Host通信使用
1.4、ansible任務執(zhí)行
# 1、ad-hoc模式(點對點模式)
使用單個模塊,支持批量執(zhí)行單條命令。ad-hoc 命令是一種可以快速輸入的命令,而且不需要保存起來的命令。就相當于bash中的一句話shell。
# playbook模式(劇本模式)
是Ansible主要管理方式,也是Ansible功能強大的關鍵所在。playbook通過多個task集合完成一類功能,如Web服務的安裝部署、數(shù)據(jù)庫服務器的批量備份等。可以簡單地把playbook理解為通過組合多條ad-hoc操作的配置文件。
簡單理解就是Ansible在運行時, 首先讀取ansible.cfg中的配置, 根據(jù)規(guī)則獲取Inventory中的管理主機列表, 并行的在這些主機中執(zhí)行配置的任務, 最后等待執(zhí)行返回的結果。
二、ansible搭建
2.1、環(huán)境
| ip | hostname | 備注 |
|---|---|---|
| 192.168.13.211 | vm-master-01 | ansible控制端 |
| 192.168.13.12 | vm-master-02 | ansible被控制端 |
| 192.168.13.225 | vm-master-03 | ansible被控制端 |
2.2、安裝
# 官方文檔
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#installing-ansible-on-rhel-centos-or-fedora
yum install epel-release
yum install ansible
# ansible 幫助信息
ansible-doc -a # 顯示所有模塊文檔
ansible-doc -l;--list # 列出可用模塊
ansible-doc -s # 顯示指定模塊的playbook片段
eg:
ansible-doc -l
ansible-doc ping
ansible-doc -s ping
2.3、ansible配置文件
inventory = /etc/ansible/hosts #這個參數(shù)表示資源清單inventory文件的位置
library = /usr/share/ansible #指向存放Ansible模塊的目錄,支持多個目錄方式,只要用冒號(:)隔開就可以
forks = 5 #并發(fā)連接數(shù),默認為5
sudo_user = root #設置默認執(zhí)行命令的用戶
remote_port = 22 #指定連接被管節(jié)點的管理端口,默認為22端口,建議修改,能夠更加安全
host_key_checking = False #設置是否檢查SSH主機的密鑰,值為True/False。關閉后第一次連接不會提示配置實例
timeout = 60 #設置SSH連接的超時時間,單位為秒
log_path = /var/log/ansible.log #指定一個存儲ansible日志的文件(默認不記錄日志)
2.4、ansible常用命令
/usr/bin/ansible Ansibe AD-Hoc 臨時命令執(zhí)行工具,常用于臨時命令的執(zhí)行
/usr/bin/ansible-doc Ansible 模塊功能查看工具
/usr/bin/ansible-galaxy 下載/上傳優(yōu)秀代碼或Roles模塊 的官網平臺,基于網絡的
/usr/bin/ansible-playbook Ansible 定制自動化的任務集編排工具
/usr/bin/ansible-pull Ansible遠程執(zhí)行命令的工具,拉取配置而非推送配置(使用較少,海量機器時使用,對運維的架構能力要求較高)
/usr/bin/ansible-vault Ansible 文件加密工具
/usr/bin/ansible-console Ansible基于Linux Consoble界面可與用戶交互的命令執(zhí)行工具
2.5、ansible控制端環(huán)境配置
# ansible控制端上進行操作
# 1、生成私鑰
ssh-keygen
# 2、向主機分發(fā)私鑰
ssh-copy-id root@vm-master-01
ssh-copy-id root@vm-master-02
ssh-copy-id root@vm-master-03
# 3、配置hosts
[root@vm-master-01 ansible]# cat /etc/ansible/hosts
[test]
vm-master-01 ansible_ssh_host=192.168.13.211 ansible_ssh_port=22
vm-master-02 ansible_ssh_host=192.168.13.12 ansible_ssh_port=22
vm-master-03 ansible_ssh_host=192.168.13.225 ansible_ssh_port=22
三、ansible基本使用
ansible通過ssh實現(xiàn)配置管理、應用部署、任務執(zhí)行等功能,建議配置ansible端能基于密鑰認證的方式聯(lián)系各個管理節(jié)點:
ansible <host-pattern> [-m module_name] [-a args]
--version 顯示版本
-m module 指定模塊,默認為command
-v 詳細過程 -vv -vvv更為詳細
--list-hosts 顯示主機列表,可簡寫為--list
-k,--ask-pass tishi 提示輸入ssh鏈接密碼,默認key驗證
-C,--check 檢查,并不執(zhí)行
-T,-timeout=TIMEOUT 執(zhí)行命令的超時時間,默認10s
-u,--user=REMOTE_USER 遠程執(zhí)行的用戶
# ansible的host-pattern匹配主機的列表
# 1、All: 表示所有Inventory中的所有主機
ansible all -m ping
#2、*: 通配符
ansible "*" -m ping
ansible 10.10.0.* -m ping
ansible "*srs" -m ping
# 3、或
ansible "web1:web2" -m ping
ansible "192.168.1.10:192.168.1.11" -m ping
# 4、邏輯與
ansible "web1:&web2" -m ping # 在web1并且在web2組中的主機
# 5、邏輯非
ansible 'web1:!web2' -m ping # 在web1組中但不在web2組中
# 6、正則
ansible "~(wa|we).*\.baidu\.com" -m ping
ansible命令執(zhí)行過程:

3.1、command模塊
# 遠程執(zhí)行命令,command模塊是默認情況下的模塊,這個模塊不支持shell變量和管道
ansible vm-master-01 -m command -a "ls /" <可自行>
ansible vm-master-01 -m command -a "ls / | grep data" <有管道、不可執(zhí)行>
3.2、shell模塊
# 支持shell變量和管道
ansible vm-master-01 -m shell -a "ls /"
ansible vm-master-01 -m shell -a "ls / | grep data"
3.3、yum模塊
ansible PROD -m yum -a 'name=vsftpd state=present'
常用參數(shù)介紹:
name= #所安裝的包的名稱
state= #present--->安裝, latest--->安裝最新的, absent---> 卸載軟件。
update_cache #強制更新yum的緩存
conf_file #指定遠程yum安裝時所依賴的配置文件(安裝本地已有的包)。
disable_pgp_check #是否禁止GPG checking,只用于presentor latest。
disablerepo #臨時禁止使用yum庫。 只用于安裝或更新時。
enablerepo #臨時使用的yum庫。只用于安裝或更新時。
3.4、service模塊
ansible vm-master-02 -m service -a "name=vsftpd state=started enabled=yes"
常用參數(shù)介紹:
arguments #命令行提供額外的參數(shù)
enabled #設置開機啟動。
name= #服務名稱
runlevel #開機啟動的級別,一般不用指定。
sleep #在重啟服務的過程中,是否等待。如在服務關閉以后等待2秒再啟動。(定義在劇本中。)
state #有四種狀態(tài),分別為:started--->啟動服務, stopped--->停止服務, restarted--->重啟服務, reloaded--->重載配置
3.5、file模塊
# file模塊用于查看文件的屬性,修改文件屬性,查詢文件是否被修改等
ansible vm-master-03 -m file -a 'path=/etc/passwd' -------------->查看文件屬性
ansible vm-master-02 -m file -a 'path=/tmp/fzh state=touch mode=755 owner=fzh' --------------->創(chuàng)建文件
ansible vm-master-02 -m file -a 'dest=/tmp/fzh state=absent' ------------------->刪除文件。
ansible vm-master-02 -m file -a 'dest=/tmp/test.sh mode=777' ------------------->修改遠程服務器上文件的屬性。
ansible vm-master-02 -m file -a 'dest=/tmp/test mode=755 owner=fzh group=fzh state=directory' ------->在客戶端相應位置下創(chuàng)建目錄:fzh。(make -p)
ansible vm-master-02 -m file -a 'dest=/tmp/fzh state=absent' --------------->刪除遠程服務器上的文件,這里是目錄。
3.6、copy模塊
# 從控制節(jié)點上拷貝文件到“受控節(jié)點”上
ansible vm-master-02 -m copy -a 'src=/root/test.sh dest=/tmp/ mode=600 owner=fzh group=fzh'
(把本地/root/test文件cp到PROD主機下的/tmp目錄下。)
常用參數(shù)介紹:
src #被復制到遠程主機的本地文件。可以是絕對路徑,也可以是相對路徑。如果路徑是一個目錄,則會遞歸復制,用法類似于"rsync"
content #用于替換"src",可以直接指定文件的值
dest #必選項,將源文件復制到的遠程主機的絕對路徑
backup #當文件內容發(fā)生改變后,在覆蓋之前把源文件備份,備份文件包含時間信息
directory_mode #遞歸設定目錄的權限,默認為系統(tǒng)默認權限
force #當目標主機包含該文件,但內容不同時,設為"yes",表示強制覆蓋;設為"no",表示目標主機的目標位置不存在該文件才復制。默認為"yes"
others #所有的 file 模塊中的選項可以在這里使用
3.7、script模塊
# 遠程節(jié)點執(zhí)行本地腳本,腳本位于控制節(jié)點,相當于scp+shell
ansible test -m script -a "/root/hostname.sh"
3.8、synchronize模塊
# 將控制節(jié)點的某個目錄推送到受控制節(jié)點目錄下
ansible test -m synchronize -a 'src=/root/test dest=/tmp/ compress=yes'
3.9、fetch模塊
# 將vm-master-02的/root/vm-master-02.txt文件cp到本機的/root目錄下
[root@vm-master-01 ~]# ansible vm-master-02 -m fetch -a "src=/root/vm-master-02.txt dest=/root/ flat=yes"
ansible還有很多模塊,在此不一一介紹,具體可以參考中文指南:
http://www.ansible.com.cn/docs/intro_adhoc.html#managing-packages
四、ansible-playbook
4.1、ansible-playbook
playbook 是 ansible 用于配置,部署,和管理被控節(jié)點的劇本。通過 playbook 的詳細描述,執(zhí)行其中的一系列 tasks ,可以讓遠端主機達到預期的狀態(tài)。執(zhí)行一些簡單的任務,使用ad-hoc命令可以方便的解決問題,但是有時一個設施過于復雜,需要大量的操作時候,執(zhí)行的ad-hoc命令是不適合的,這時最好使用playbook。playbook由YMAL語言編寫。YAML( /?j?m?l/ )參考了其他多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822。
4.2、ansible-playbook yaml文件格式
---
- hosts: vm-03
remote_user: root
tasks:
- name: exec shell
shell: hostname
- name: create dir
file:
path: /root/dir
state: directory
# 解析
host:使用 hosts 指示使用哪個主機或主機組來運行下面的 tasks ,每個 playbook 都必須指定 hosts,hosts也可以使用通配符格式。主機或主機組在 inventory 清單中指定,可以使用系統(tǒng)默認的/etc/ansible/hosts,也可以自己編輯,在運行的時候加上-i選項,指定清單的位置即可。
remote_user:指定遠端主機中的哪個用戶來登錄遠端系統(tǒng),在遠端系統(tǒng)執(zhí)行 task 的用戶,可以任意指定,也可以使用 sudo,但是用戶必須要有執(zhí)行相應 task 的權限。
tasks:指定遠端主機將要執(zhí)行的一系列動作,相當于任務列表。tasks 的核心為 ansible 的模塊,前面已經提到模塊的用法。tasks 包含 name 和要執(zhí)行的模塊,name 是可選的,只是為了便于用戶閱讀,不過還是建議加上去,模塊是必須的,同時也要給予模塊相應的參數(shù)。
name:每個task都有對應的name,當我們省略name時,默認以當前任務調用的模塊的名稱作為任務的名稱,不過建議不要省略name,因為當任務存在name時,可讀性比較高。
# 執(zhí)行上述任務
# 1、–list-hosts: 顯示執(zhí)行任務的主機列表,實際并不執(zhí)行
ansible-playbook -i /etc/ansible/hosts --list-hosts /etc/ansible/test.yaml
# 2、--syntax-check: 語法檢測,實際并不執(zhí)行。執(zhí)行結果顯示playbook名稱即表示沒有語法錯誤。
ansible-playbook -i /etc/ansible/hosts /etc/ansible/test.yaml --syntax-check
# 3、--check: 任務預演,實際并不執(zhí)行
ansible-playbook -i /etc/ansible/hosts /etc/ansible/test.yaml --check
# 執(zhí)行結果:
綠色代表執(zhí)行成功,系統(tǒng)保持原樣
黃色代表系統(tǒng)代表系統(tǒng)狀態(tài)發(fā)生改變
紅色代表執(zhí)行失敗,顯示錯誤輸出
執(zhí)行過程有三個步驟:
1、收集facts (收集對應目標主機的信息)
2、執(zhí)行tasks
3、報告結果
執(zhí)行結果如下圖:

4.3、handlers
4.3.1、handlers初識
handlers是和tasks平級的另一種任務。但handlers中的任務會被tasks中的任務調用。只有當tasks中的任務真正執(zhí)行(黃色,有改變),handlers中被調用的任務才會被執(zhí)行。當服務的配置文件發(fā)生改變,需要重啟的時候,handlers就能解決此類問題。格式見下:
[root@vm-master-01 ansible]# cat handlers.yaml
---
- hosts: vm-03
remote_user: root
tasks:
- name: create dir1
file: path=/root/dir1
state=directory
notify: handler1
- name: create dir2
file: path=/root/dir2
state=directory
notify: handler2
handlers:
- name: handler1
file: path=/root/dir1/file1
state=touch
- name: handler2
file: path=/root/dir2/file2
state=touch
# 解釋:
通過notify關鍵字關聯(lián)tasks和handlers,handlers被執(zhí)行的順序與在playbook中定義的順序是相同的,與被調用執(zhí)行的順序無關。當所有task執(zhí)行完畢后,才會執(zhí)行handlers。如果想改變這種順序需要meta模塊。
4.3.2、handlers meta
[root@vm-master-01 ansible]# cat handlers.yaml
---
- hosts: vm-03
remote_user: root
tasks:
- name: create dir1
file: path=/root/dir1
state=directory
notify: handler1
- name: create dir2
file: path=/root/dir2
state=directory
notify: handler2
- meta: flush_handlers
- name: create dir3
file: path=/root/dir3
state=directory
notify: handler3
handlers:
- name: handler1
file: path=/root/dir1/file1
state=touch
- name: handler2
file: path=/root/dir2/file2
state=touch
- name: handler3
file: path=/root/dir2/file3
state=touch
ansible-playbook -i /etc/ansible/hosts /etc/ansible/handlers.yaml執(zhí)行結果見下:

#從上面結果可以看出:
meta是一種特殊的任務,可以影響ansible內部的工作順序,"meta: flush_handlers"表示立即執(zhí)行之前的task所對應的handler。當對應的handler執(zhí)行完畢后,接著執(zhí)行meta下面后續(xù)的task,這些task執(zhí)行完畢后,在執(zhí)行對應的handlers。
4.3.3、一個task對應多個handlers<listen>
[root@vm-master-01 ansible]# cat handlers2.yaml
---
- hosts: vm-03
remote_user: root
tasks:
- name: create dir1
file: path=/root/dir1
state=directory
notify: handler-group
handlers:
- name: handler1
listen: handler-group
file: path=/root/dir1/file1
state=touch
- name: handler2
listen: handler-group
file: path=/root/dir1/file2
state=touch
- name: handler3
listen: handler-group
file: path=/root/dir1/file3
state=touch
ansible-playbook -i /etc/ansible/hosts /etc/ansible/handlers2.yaml執(zhí)行結果如下:

可以將"listen"和“notify”后面的handler-group看成組,命中組的handler就可以被調用執(zhí)行。
注意:如果不采用上面listen的方式,當定義多個具有相同name的handlers時,只會有一個handler會被執(zhí)行。
4.4、tags
tags: 為任務列表中的指定任務打上標簽,然后可以選擇性的執(zhí)行某一部分或者某一類的任務。
4.4.1、tags定義
[root@vm-master-01 ansible]# cat cat tags.yaml
cat: cat: No such file or directory
---
- hosts: vm-03
remote_user: root
tasks:
- name: create dir1
file: path=/root/dir1
state=directory
notify: handler1
tags: t1
- name: create dir2
file: path=/root/dir2
state=directory
notify: handler2
tags: t2
- name: create dir3
file: path=/root/dir3
state=directory
notify: handler3
tags: t3
handlers:
- name: handler1
file: path=/root/dir1/file1
state=touch
- name: handler2
file: path=/root/dir2/file2
state=touch
- name: handler3
file: path=/root/dir3/file3
state=touch
ansible-playbook -i /etc/ansible/hosts --tags=t3 /etc/ansible/tags.yaml執(zhí)行結果如下:

從結果可以看出:只有tags: t3的task和其handler被執(zhí)行了,也可以一次性指定多個標簽
# t2、t3執(zhí)行
ansible-playbook -i /etc/ansible/hosts --tags t2,t3 /etc/ansible/tags.yaml
# --skip-tags指定不執(zhí)行的task<下面:t2不執(zhí)行,t1、t3執(zhí)行>
ansible-playbook -i /etc/ansible/hosts --skip-tags="t2" /etc/ansible/tags.yaml
# 定義標簽的方式:
[root@vm-master-01 ansible]# cat tags2.yaml
---
- hosts: vm-03
remote_user: root
tasks:
- name: create dir1
file: path=/root/dir1
state=directory
notify: handler1
tags:
- t1
- name: create dir2
file: path=/root/dir2
state=directory
notify: handler2
tags: ['t2']
- name: create dir3
file: path=/root/dir3
state=directory
notify: handler3
tags:
- t3
- t4
- name: create dir4
file: path=/root/dir4
state=directory
tags: t5,t6
- name: create dir4
file: path=/root/dir4
state=directory
tags: ['t7', 't8']
handlers:
- name: handler1
file: path=/root/dir1/file1
state=touch
- name: handler2
file: path=/root/dir2/file2
state=touch
- name: handler3
file: path=/root/dir3/file3
state=touch
4.4.2、tags查看
ansible-playbook -i /etc/ansible/hosts --list-tags /etc/ansible/tags.yaml
4.4.3、相同標簽
[root@vm-master-01 ansible]# cat tags3.yaml
---
- hosts: vm-03
remote_user: root
tasks:
- name: create dir1
file: path=/root/dir1
state=directory
tags:
- t1
- dir
- name: create dir2
file: path=/root/dir2
state=directory
tags: ['t2', 'dir']
上面兩個task都有標簽:dir,我們可以以另一種方式表示:
[root@vm-master-01 ansible]# cat tags4.yaml
---
- hosts: vm-03
remote_user: root
tags: dir
tasks:
- name: create dir1
file: path=/root/dir1
state=directory
tags:
- t1
- name: create dir2
file: path=/root/dir2
state=directory
tags: ['t2']
當我們執(zhí)行:ansible-playbook -i /etc/ansible/hosts --tags=dir /etc/ansible/tags4.yaml,兩個tasks都會被執(zhí)行,結果見下:

4.4.4、內置tags
4.4.4.1、always
當tags=always時,我們用ansible-playbook執(zhí)行任務,即便我們沒有指定--tags=always,這個任務也會被執(zhí)行,除非使用了'--skip-tags'。
4.4.4.2、never
和always相反,我們執(zhí)行所有任務的時候,加了never標簽的任務不執(zhí)行。
4.4.4.3、tagged
# 下面命令表示只執(zhí)行有標簽的任務,沒有任何標簽的任務不會被執(zhí)行。這里加了never標簽的不會執(zhí)行
ansible-playbook --tags tagged tags.yaml
# 下面命令表示跳過包含標簽的任務,即使對應的任務包含always標簽,也會被跳過
ansible-playbook --skip-tags tagged tags.yaml
4.4.4.4、untagged
# 下面命令表示只執(zhí)行沒有標簽的任務,但是如果某些任務包含always標簽,那么這些任務也會被執(zhí)行
ansible-playbook --tags untagged tags.yaml
# 下面命令表示跳過沒有標簽的任務。意思是只執(zhí)行有標簽的任務。但是加了never標簽的任務不會被執(zhí)行
ansible-playbook --skip-tags untagged tags.yaml
4.4.4.5、all
特殊標簽all表示所有任務會被執(zhí)行,不用指定,默認情況下就是使用這個標簽。
4.5、ignore_errors
# 假如ansible-playbook中的某個task出錯,則按照順序執(zhí)行的后續(xù)任務都不會再執(zhí)行,假如是handler報錯,則不會影響剩下的流程,如果需要忽略此錯誤,可以用ignore_errors
[root@vm-master-01 ansible]# cat ignore_errors.yaml
---
- hosts: vm-03
remote_user: root
tasks:
- name: create dir1
file: path=/root/dir1
state=directory
notify: handler1
- name: create dir2
command: hostnameeeeee
notify: handler2
ignore_errors: True
- name: create dir3
file: path=/root/dir3
state=directory
notify: handler3
handlers:
- name: handler1
file: path=/root/dir1/file1
state=touch
- name: handler2
file: path=/root/dir2/file2
state=touch
- name: handler3
file: path=/root/dir3/file3
state=touch
執(zhí)行命令: ansible-playbook -i /etc/ansible/hosts /etc/ansible/ignore_errors.yaml 結果如下:

在第二個任務,人為制造一個報錯,由于目錄/root/dir2/不存在,所以handler2也會出錯,但只在第二個任務處添加"ignore_errors: True"后,后續(xù)的步驟都沒背中斷,即便handler2有報錯,也沒有影響后續(xù)的步驟。
4.6、limit
# 當有多臺主機被命中時,限制其中的某一臺執(zhí)行playbook,但必須在命中的主機列表中:
[root@vm-master-01 ansible]# cat limit.yaml
---
- hosts: test
remote_user: root
tasks:
- name: limit test
command: hostname
執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/limit.yaml --limit vm-master-02的結果如下:

雖然test命中了三臺主機,但使用limit可以限制playbook在指定的主機上執(zhí)行。
4.7、playbook變量
# 1、變量名:
僅能由字母、數(shù)字、下劃線組成,且只能以字母開頭
# 2、變量來源:
1.1、 ansible setup facts 遠程主機的所有變量都可直接調用
1.2、/etc/ansible/hosts定義
1.2.1、普通變量:主機組中主機單行定義,優(yōu)先級高于公共變量
1.2.2、公共(組)變量:針對主機組中所有主機定義的統(tǒng)一變量
1.3、命令行指定的變量,優(yōu)先級最高
1.4、playbook中定義
1.5、role中定義
4.7.1、命令行變量
# 1、var_command_line.yaml文件內容
[root@vm-master-01 ansible]# cat var_command_line.yaml
---
- hosts: test
remote_user: root
tasks:
- name: exec shell echo {{ var }}
shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt
執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts -e "prefix=pre1" -e "var=command-line-var" -e "suffix=suf1" /etc/ansible/var_command_line.yaml結果如下:

4.7.2、playbook變量
# 1、var_playbook.yaml文件內容
[root@vm-master-01 ansible]# cat var_playbook.yaml
---
- hosts: test
remote_user: root
vars:
- prefix: pre2
- var: playbook-var
- suffix: suf2
tasks:
- name: exec shell echo {{ var }}
shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt
執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_playbook.yaml結果如下:

4.7.3、普通變量
# 1、/etc/ansible/hosts文件內容
[root@vm-master-01 ansible]# head -n 4 /etc/ansible/hosts
[test]
vm-master-01 ansible_ssh_host=192.168.13.211 ansible_ssh_port=22 prefix=vm01_pre3 var=common-var suffix=vm01_suf3
vm-master-03 ansible_ssh_host=192.168.13.225 ansible_ssh_port=22 prefix=vm03_pre3 var=common-var suffix=vm03_suf3
# 2、var_common.yaml文件內容
[root@vm-master-01 ansible]# cat var_common.yaml
---
- hosts: test
remote_user: root
tasks:
- name: exec shell echo {{ var }}
shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt
執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_common.yaml結果如下:

4.7.4、公共(組)變量
# 1、hosts文件內容
[root@vm-master-01 ansible]# head -n 7 hosts
[test]
vm-master-01 ansible_ssh_host=192.168.13.211 ansible_ssh_port=22
vm-master-03 ansible_ssh_host=192.168.13.225 ansible_ssh_port=22
[test:vars]
prefix=test_pre4
var=group-var
suffix=test_suf4
# 2、var_group.yaml文件內容
[root@vm-master-01 ansible]# cat var_group.yaml
---
- hosts: test
remote_user: root
tasks:
- name: exec shell echo {{ var }}
shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt
執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_group.yaml結果若下:

4.7.5、變量優(yōu)先級比較
# 1、hosts文件內容
[root@vm-master-01 ansible]# head -n 8 /etc/ansible/hosts
[test]
vm-master-01 ansible_ssh_host=192.168.13.211 ansible_ssh_port=22 prefix=vm01_pre3 var=common-var suffix=vm01_suf3
vm-master-03 ansible_ssh_host=192.168.13.225 ansible_ssh_port=22 prefix=vm03_pre3 var=common-var suffix=vm03_suf3
[test:vars]
prefix=test_pre4
var=group-var
suffix=test_suf4
# 2、var_priority.yaml文件內容
[root@vm-master-01 ansible]# cat /etc/ansible/var_priority.yaml
---
- hosts: test
remote_user: root
vars:
- prefix: pre2
- var: playbook-var
- suffix: suf2
tasks:
- name: exec shell echo {{ var }}
shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt
命令行傳入變量執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts -e "prefix=pre1" -e "var=command-line-var" -e "suffix=suf1" /etc/ansible/var_priority.yaml結果如下:

命令行不傳入變量執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_priority.yaml 結果如下:

# 只修改/etc/ansible/var_priority.yaml將playbook變量刪掉:
[root@vm-master-01 ansible]# cat /etc/ansible/var_priority.yaml
---
- hosts: test
remote_user: root
tasks:
- name: exec shell echo {{ var }}
shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt
命令行不傳入變量數(shù)執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_priority.yaml 結果如下:

補充:對于"ansible setup facts"中的變量,我們可以借助于:ansible vm-01 -m setup命令查看,我做了實驗,但沒有截圖在這里,他的優(yōu)先級要高于普通變量低于playbook變量
由以上例子可證明優(yōu)先級排序為:命令行變量>playbook變量>ansible setup facts中的變量>普通變量>公共(組)變量,在執(zhí)行playbook時會使用優(yōu)先級高的變量。
4.7.6、將變量寫入單獨的yaml文件中
[root@vm-master-01 ansible]# cat vars.yaml
prefix: file_pre5
var: var-file
suffix: file_suf5
[root@vm-master-01 ansible]# cat var_file.yaml
---
- hosts: test
remote_user: root
vars_files:
- vars.yaml
tasks:
- name: exec shell echo {{ var }}
shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt
# 此時的變量相當于playbook的變量,優(yōu)先級也一樣,變量文件和var_file.yaml放在同級目錄。
4.8、templates
4.8.1、templates語法
文本文件,嵌套有腳本(使用模版編程語言編寫)
jinja2語言,使用字面量,有下面形式:
字符串:使用單引號或雙引號
數(shù)字:整數(shù),浮點數(shù)
列表:[item1,item2,...]
元組:{item1,item2,...}
字典:{key1:value1,key2:value2,...}
布爾型:true、false
算術運算:+,-,*,/,//,%,**
比較操作:==,!=,>,>=,<,<=
邏輯運算:and,or,not
流表達式:for if when
template文件必須以.j2結尾
4.8.2、一個例子
需要在vm-03上安裝nginx,并將其開啟的worker進程數(shù)量在auto(cpu的核心數(shù))的基礎上+2
# 1、ansible setup模塊確定auto的變量名稱
[root@vm-master-01 ansible]# ansible vm-03 -m setup | grep ansible_processor_vcpus
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
"ansible_processor_vcpus": 8, # vm-03有8個core
# 2、nginx.conf.j2配置<次文件放在templates目錄下,templates目錄和nginx.yaml文件平級,執(zhí)行playbook時會自動尋找到對應名稱的模版文件>
[root@vm-master-01 ansible]# head -n 6 templates/nginx.conf.j2
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes {{ ansible_processor_vcpus + 2 }}; # ansible_processor_vcpus由"1"獲取
# 3、nginx.yaml
[root@vm-master-01 ansible]# cat nginx.yaml
---
- hosts: vm-03
remote_user: root
tasks:
- name: install nginx
yum: name=nginx
- name: copy templates nginx.conf.j2
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: start nginx
service: name=nginx state=started enabled=true
執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/nginx.yaml結果如下:


執(zhí)行命令:ansible vm-03 -m shell -a "grep worker_processes /etc/nginx/nginx.conf"查看vm-03上nginx的配置文件:

4.9、when
1、條件測試:如果需要根據(jù)變量、facts或者此前任務的執(zhí)行結果來做為某個task執(zhí)行與否的前提時要用到條件測試,通過when語句實現(xiàn),在task中使用jinja2的語法格式
2、使用:在task后添加when子句即可使用條件測試;when語句支持jinja2表達式語法
3、例子:
name: "if RedHat exec command"
command: hostname
when: ansible_os_family == "RedHat"
# 1、需求:我們修改上面nginx配置文件的需求,假如vm-03中"ansible_os_family!=RedHat",我們就不傳遞vm-01上修改過的nginx.conf文件,而使用vm-03上原有的配置文件
# 2、說明:vm-03上ansible_os_family為"RedHat",可以通過setup模塊獲取,作為演示:我已經卸載了vm-03上面已經安裝過的nginx
# 2、nginx.yaml
[root@vm-master-01 ansible]# cat nginx.yaml
---
- hosts: vm-03
remote_user: root
tasks:
- name: install nginx
yum: name=nginx
- name: copy templates nginx.conf.j2
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
when: ansible_os_family != "RedHat"
- name: start nginx
service: name=nginx state=started enabled=true
執(zhí)行相關命令結果如下:

從上面例子可以看出:由于when條件不成立,并沒有執(zhí)行template操作。
4.10、with_items
with_items表迭代:當有重復執(zhí)行的任務時,可以使用迭代機制
使用固定變量"item"作為迭代項的引用
使用with_items給定迭代的元素列表:
字符串
字典等
# 下面yaml文件將在vm-03主機的/tmp目錄下創(chuàng)建三個文件:f1、f2、f3
[root@vm-master-01 ansible]# cat with_items.yaml
---
- hosts: vm-03
remote_user: root
tasks:
- name: create files
file: name=/tmp/{{ item }} state=touch
when: ansible_os_family == "RedHat"
with_items:
- f1
- f2
- f3
執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/with_items.yaml得到的結果如下:

4.11、for流程控制
# 1、for.yaml文件內容
[root@vm-master-01 ansible]# cat for.yaml
---
- hosts: vm-03
remote_user: root
vars:
people:
- name: zhangsan
age: 23
high: 1.68
- name: lisi
high: 1.70
- name: wangwu
age: 25
high: 1.71
tasks:
- name: copy file
template: src=for1.txt.j2 dest=/tmp/for1.txt
# 2、for1.txt.j2文件內容:
[root@vm-master-01 ansible]# cat templates/for1.txt.j2
{% for p in people %}
info of people {
name: {{ p.name }}
{% if p.age is defined %}
age: {{ p.age }}
{% endif %}
hige: {{ p.high }}
}
{% endfor %}
執(zhí)行yaml文件并查看vm-03下的文件/tmp/for1.txt的內容:

4.12、register
假如有這樣一個需求,使用shell命令檢查nginx進程是否存在,當不存在時就重啟。我們可以通過register將使用ps命令抓取的進程數(shù)賦值給info,然后通過info的相應字段(從下面截圖中應該可以看出相應的字段為info.stdout)來判斷進程數(shù)是否為0,為0則重啟。
[root@vm-master-01 ansible]# cat sum_process_nginx.yml
---
- hosts: vm-master-03
gather_facts: no
tasks:
- name: get nginx process
shell: ps -ef | grep nginx | grep -v grep | wc -l
register: info
- name: display vars
debug:
var: info
- name: if sum(nginx process) < 1 then start it
service: name=nginx
state=started
when: info.stdout == "0"
- name: check if nginx started success or not
shell: systemctl status nginx
執(zhí)行命令:ansible-playbook sum_process_nginx.yml結果如下:

五、ansible-playbook生產實踐
5.1、說明
基于上面介紹,對于nginx的安裝,做一個生產級別的介紹
5.2、項目結構
[root@vm-master-01 ansible]# pwd
/etc/ansible
[root@vm-master-01 ansible]# tree ./
./
├── ansible.cfg
├── hosts
├── nginx_role.yml
└── roles
├── mysql
├── nginx
│ ├── files
│ │ └── index.html
│ ├── handlers
│ │ ├── main.yml
│ │ └── restart.yml
│ ├── tasks
│ │ ├── copyfile.yml
│ │ ├── group.yml
│ │ ├── main.yml
│ │ ├── start.yml
│ │ ├── template.yml
│ │ ├── user.yml
│ │ └── yum.yml
│ ├── templates
│ │ └── nginx.conf.j2
│ └── vars
│ └── main.yml
├── redis
└── supervisor
├── files
├── handlers
├── tasks
├── templates
└── vars
15 directories, 15 files
下面我分別貼下沒個文件的內容。
5.2.1、role
關于role的各個目錄做下簡要的概述
files:存放由copy、script模塊等調用的文件
templates:template模塊查找所需要模塊文件的目錄
tasks:定義task,至少包含一個名為main.yml的文件,其他文件需要再次文件中通過include進行包含
handlers:至少應該包含一個名為main.yml的文件,其他文件需要在此文件中通過include進行包含
vars:定義變量,至少包含一個名為main.yml的文件,其他文件需要在此文件中通過include進行包含
meta:定義當前角色的特殊設定以及其依賴關系,至少應該包含一個名為main.yml的文件,其它文件需要在此文件中通過include進行包含
default:設定默認變量時使用此目錄中的main.yml文件
[root@vm-master-01 ansible]# cat nginx_role.yml
- hosts: vm-03
remote_user: root
roles:
- { role: nginx, tags: ['app', 'ops'], when: ansible_os_family == 'RedHat' }
- { role: mysql, tags: 'app' }
5.2.2、files目錄
[root@vm-master-01 files]# ls
index.html
[root@vm-master-01 files]# cat index.html
nginx playbook
5.2.3、handlers目錄
[root@vm-master-01 handlers]# ls
main.yml restart.yml
[root@vm-master-01 handlers]# cat main.yml
- include: restart.yml
[root@vm-master-01 handlers]# cat restart.yml
- name: nginx restart
service: name=nginx state=restarted
5.2.4、tasks目錄
[root@vm-master-01 tasks]# ls
copyfile.yml group.yml main.yml start.yml template.yml user.yml yum.yml
[root@vm-master-01 tasks]# cat copyfile.yml
- name: copy index.html
copy: src=index.html dest=/usr/share/nginx/html/
notify: nginx restart
[root@vm-master-01 tasks]# cat group.yml
- name: create group
group: name={{ username }} gid=88
[root@vm-master-01 tasks]# cat main.yml
- include: group.yml
- include: user.yml
- include: yum.yml
- include: template.yml
- include: start.yml
- include: copyfile.yml
[root@vm-master-01 tasks]# cat start.yml
- name: start service
service: name=nginx state=started enabled=yes
[root@vm-master-01 tasks]# cat template.yml
- name: copy file
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
[root@vm-master-01 tasks]# cat user.yml
- name: create user
user: name={{ username }} group={{ groupname }} system=yes shell=/sbin/nologin
[root@vm-master-01 tasks]# cat yum.yml
- name: install nginx
yum: name=nginx
5.2.5、templates目錄
[root@vm-master-01 templates]# ls
nginx.conf.j2
[root@vm-master-01 templates]# cat nginx.conf.j2
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user {{ username }};
worker_processes {{ ansible_processor_vcpus + 2 }};
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
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;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
5.2.6、vars目錄
[root@vm-master-01 vars]# ls
main.yml
[root@vm-master-01 vars]# cat main.yml
groupname: nginx
username: nginx
5.3、執(zhí)行playbook
執(zhí)行命令:ansible-playbook -i /etc/ansible/hosts --tags=app nginx_role.yml結果如下:

5.4、瀏覽器訪問

六、注意
1、我上面執(zhí)行ansible或ansible-playbook時,結果中多處有提示:[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
是因為我hosts中資源清單的組中有使用符號“-",這不符合相關語法規(guī)范,修改掉即可。