自動化利器 Ansible – 從了解到應用
本文說明
本系列使用 ansible 2.9.27 版本來說明和匯總相關信息。
# cat /etc/system-release
Red Hat Enterprise Linux Server release 7.8 (Maipo)
#
# uname -a
Linux test01 3.10.0-1160.36.2.el7.x86_64 #1 SMP Wed Jul 21 11:57:15 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
#
# ansible --version # ansible版本
ansible 2.9.27
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/vipxf/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /bin/ansible
python version = 2.7.5 (default, Nov 16 2020, 22:23:17) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
#
# yum info ansible # 包信息
Loaded plugins: fastestmirror, product-id, search-disabled-repos, subscription-manager
Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
Loading mirror speeds from cached hostfile
Installed Packages
Name : ansible
Arch : noarch
Version : 2.9.27
Release : 1.el7
Size : 103 M
Repo : installed
Summary : SSH-based configuration management, deployment, and task execution system
URL : //ansible.com
License : GPLv3+
Description : Ansible is a radically simple model-driven configuration management,
: multi-node deployment, and remote task execution system. Ansible works
: over SSH and does not require any software or daemons to be installed
: on remote nodes. Extension modules can be written in any language and
: are transferred to managed machines automatically.
#
Ansible 概念介紹
Ansible是自由開源的配置和自動化工具。
主要特點
- 無客戶端模式(agentless),無侵入性,只需在主控端部署Ansible環境,被控端無需做任何操作
- 豐富的內置模塊滿足絕大部分場景需求,調用特定模塊可以完成特定任務
- 基於Python研發,支持API及自定義模塊,二次開發相對容易
- 默認使用SSH協議和節點進行通信
- 強大的playbook機制,配置語法使用yaml和Jinja模板語言,便於配置管理和實現複雜功能
- 具有冪等性,自動跳過沒有變化的部分,也就是一個操作執行一次和多次的結果相同
- 對雲計算平台和大數據提供了支持
Ansible 使用模式
- 結合CMDB:通過CMDB下髮指令調用Ansible完成相關操作
- API調用:遠程調用Ansible提供豐富的API接口
- Ad-Hoc命令:直接通過Ad-Hoc命令集執行相關操作,多用於非固化需求、臨時性操作和二次開發接口調用的場景
- playbook執行:運行Playbook按序執行任務集
Ansible由控制主機對被管節點的操作方式為 Ad-Hoc 和 Playbook。
- Ad-Hoc模式使用單個模塊,支持批量執行單條命令。
- Playbook模式是Ansible主要管理方式,Playbook通過多個Task集合完成一類功能,可以簡單地把 Playbook理解為通過組合多條Ad-Hoc操作的配置文件。
Ansible 架構及流程
# Ansible 主要由五部分組成
- Ansible Ansible核心
- Modules 包括核心模塊和自定義模塊
- Plugins 插件,對模塊功能的補充,包含連接插件、郵件插件等
- Playbooks 劇本,定義任務的配置文件
- Inventory 定義管理主機的清單
# ansible 命令執行過程
1. Ansible加載配置文件,默認為/etc/ansible/ansible.cfg
2. Ansible讀取Inventory文件(默認為/etc/ansible/hosts),獲取管理主機列表及相關變量信息
3. 根據參數調用對應配置和模塊,產生臨時py文件
4. 通過SSH方式傳輸到目標主機(默認為~/.ansible/tmp目錄)
5. 設置臨時py文件的執行權限,執行操作並返回結果
6. 刪除臨時py文件並退出
Ansible 基礎信息
Ansible 主要目錄
# 配置文件目錄
/etc/ansible/
- ansible.cfg # Ansible 主配置文件
- hosts # Inventory,定義目標主機清單的文件
- roles # 角色目錄,用於定義角色
# 執行文件目錄
/usr/bin/
# Lib庫依賴目錄
/usr/lib/python2.7/site-packages/ansible
# Help文檔目錄
/usr/share/doc/ansible-2.9.27/
# Ansible模塊目錄
/usr/share/ansible/
- collections # 目錄
- plugins # 插件模塊目錄
- roles # 角色模塊目錄
Ansible 配置文件
默認Ansible配置文件存放在 /etc/ansible/ansible.cfg
# 常見參數
inventory = /etc/ansible/hosts # 主機清單inventory文件的位置
library = /usr/share/ansible # 存放Ansible模塊的目錄,支持用「:」隔開多個目錄
forks = 5 # 並發連接數,默認為5
remote_port = 22 # 連接主機節點的端口,默認為22端口,建議修改
host_key_checking = False # 是否檢查SSH主機的密鑰,值為True/False
timeout = 60 # SSH連接的超時時間,單位為秒
log_path = /var/log/ansible.log # 存儲ansible日誌的文件(默認不開啟)
Ansible 執行文件
$ ll /usr/bin/*ansible* # 相關執行文件
lrwxrwxrwx 1 root root 20 Mar 17 2022 /usr/bin/ansible -> /usr/bin/ansible-2.7
lrwxrwxrwx 1 root root 20 Mar 17 2022 /usr/bin/ansible-2 -> /usr/bin/ansible-2.7
-rwxr-xr-x 1 root root 5933 Jan 16 2022 /usr/bin/ansible-2.7
lrwxrwxrwx 1 root root 7 Mar 17 2022 /usr/bin/ansible-config -> ansible
-rwxr-xr-x 1 root root 13432 Jan 16 2022 /usr/bin/ansible-connection
lrwxrwxrwx 1 root root 28 Mar 17 2022 /usr/bin/ansible-console -> /usr/bin/ansible-console-2.7
lrwxrwxrwx 1 root root 28 Mar 17 2022 /usr/bin/ansible-console-2 -> /usr/bin/ansible-console-2.7
lrwxrwxrwx 1 root root 7 Mar 17 2022 /usr/bin/ansible-console-2.7 -> ansible
lrwxrwxrwx 1 root root 24 Mar 17 2022 /usr/bin/ansible-doc -> /usr/bin/ansible-doc-2.7
lrwxrwxrwx 1 root root 24 Mar 17 2022 /usr/bin/ansible-doc-2 -> /usr/bin/ansible-doc-2.7
lrwxrwxrwx 1 root root 7 Mar 17 2022 /usr/bin/ansible-doc-2.7 -> ansible
lrwxrwxrwx 1 root root 27 Mar 17 2022 /usr/bin/ansible-galaxy -> /usr/bin/ansible-galaxy-2.7
lrwxrwxrwx 1 root root 27 Mar 17 2022 /usr/bin/ansible-galaxy-2 -> /usr/bin/ansible-galaxy-2.7
lrwxrwxrwx 1 root root 7 Mar 17 2022 /usr/bin/ansible-galaxy-2.7 -> ansible
lrwxrwxrwx 1 root root 7 Mar 17 2022 /usr/bin/ansible-inventory -> ansible
lrwxrwxrwx 1 root root 29 Mar 17 2022 /usr/bin/ansible-playbook -> /usr/bin/ansible-playbook-2.7
lrwxrwxrwx 1 root root 29 Mar 17 2022 /usr/bin/ansible-playbook-2 -> /usr/bin/ansible-playbook-2.7
lrwxrwxrwx 1 root root 7 Mar 17 2022 /usr/bin/ansible-playbook-2.7 -> ansible
lrwxrwxrwx 1 root root 25 Mar 17 2022 /usr/bin/ansible-pull -> /usr/bin/ansible-pull-2.7
lrwxrwxrwx 1 root root 25 Mar 17 2022 /usr/bin/ansible-pull-2 -> /usr/bin/ansible-pull-2.7
lrwxrwxrwx 1 root root 7 Mar 17 2022 /usr/bin/ansible-pull-2.7 -> ansible
lrwxrwxrwx 1 root root 26 Mar 17 2022 /usr/bin/ansible-vault -> /usr/bin/ansible-vault-2.7
lrwxrwxrwx 1 root root 26 Mar 17 2022 /usr/bin/ansible-vault-2 -> /usr/bin/ansible-vault-2.7
lrwxrwxrwx 1 root root 7 Mar 17 2022 /usr/bin/ansible-vault-2.7 -> ansible
$
Ansible 常見模塊
Ansible基於模塊工作,本身沒有批量部署的能力。
可以理解為Ansilbe提供了框架來運行具備批量部署能力的指定功能模塊。
# 通過 ansilbe-doc 命令查看模塊幫助信息,類似man命令
ansible-doc -l # List available plugins
ansible-doc -l | grep "copy" # 查找名稱包含copy字符的模塊
ansible-doc <module_name> # 顯示模塊的說明信息
ansible-doc -s <module_name> # Show playbook snippet for specified plugin(s)
# 常見模塊
## command 在指定主機上執行命令(默認模塊),不支持變量、管道、重定向等shell特性
## ping 測試指定主機連接性
## shell 在指定主機上執行命令或運行腳本,打開遠程主機的shell進程的一個子shell運行命令,支持shell的變量、管道、重定向等特性
## script 調用本地腳本在遠程主機執行
## stat 獲取文件信息
## setup 主機系統信息,收集facts
## copy 複製文件到遠程主機的指定位置
## fetch 複製指定主機的文件到本地
## get_url 在遠程主機下載指定的url地址,支持文件校驗
## file 設置文件屬性
## cron 設置計劃任務
## group 管理用戶組
## user 管理用戶
## service 管理服務狀態
## yum 管理程序包
## hostname 管理主機名稱
## git 代碼及版本管理
## B 後台管理
## assemble 文件組裝,可以將多份配置文件組裝成一份配置文件
## ini ini文件管理模塊
## url web請求,發送HTTP協議請求並得到返回的狀態碼
## apt APT包管理模塊
Ansible 命令講解
Ansible 命令集
# 以下所有命令均可使用`-h`參數獲取幫助信息
ansible # Define and run a single task 'playbook' against a set of hosts # 常用命令
ansible-config # View ansible configuration.
ansible-console # REPL console for executing Ansible tasks. # 交互式工具,相當linux中的shell,不常用
ansible-doc # plugin documentation tool # 查詢模塊的文檔說明,類似linux中的man,常用命令
ansible-galaxy # Perform various Role and Collection related operations.
ansible-inventory # Show Ansible inventory information, by default it uses the inventory script JSON format
ansible-playbook # Runs Ansible playbooks, executing the defined tasks on the targeted hosts. # 執行系列任務,類似linux中的sh,常用命令
ansible-pull # pulls playbooks from a VCS repo and executes them for the local host
ansible-vault # encryption/decryption utility for Ansible data files
Ansible 常用命令集
# 常用命令集
ansible
# Ansible指令的核心部分,主要用於執行ad-hoc命令,也就是單條命令
# 默認使用command模塊,默認的使用模塊可以在ansible.cfg中進行定義
ansible-doc
# 用於查看模塊信息,
# 參數 -l 列出可用的插件
# 參數 -s 用於查看指定模塊的用法,例如「ansible-doc -s shell」
ansible-playbook
# 讀取playbook文件內容並執行定義的任務
# 對於固化的需求通常採用playbook方式定義和實現
ansible-vault
# 主要應用於包含敏感信息的場景,可以加密和解密敏感信息
# 經過加密後的playbook,編輯時需要輸入事先設定的密碼才能打開
# 使用 --ask-vault-pass 參數執行加密後的playbook文件
ansible-config
# 查看ansible的配置
# 參數 list 打印所有配置參數,參數 view 查看配置文件
# 結合 grep 使用可以獲取具體配置信息,例如「ansible-config view |grep -v "#" |grep host_key_checking」
Ansible ad-hoc命令
# ansible <host-pattern> [-f forks] [-m module_name] [-a args]
# <host-pattern> 命令生效的主機: <inventory_group_name>/<inventory_host_ip>/all
# 常用選項 通過 ansible -h 命令獲取詳細信息
-v # 輸出詳細執行過程信息 verbose mode (-vvv for more, -vvvv to enable connection debugging)
-i inventory_file # 指定inventory文件,默認為/etc/ansible/hosts
-f forks # 指定並發線程數(一次處理多少個主機),默認5個線程
-m module_name # 指定執行使用的模塊
-M directory # 指定模塊存放路徑,默認為/usr/share/ansible
-a args # 指定模塊參數
-l hosts_ip # 限定主機(只在限定主機上執行任務)
--become-method BECOME_METHOD # 提權方法,默認為sudo,一般為su
--become-user BECOME_USER # 切換用戶,默認為root
-K, --ask-become-pass # 請求提權密碼
--list-hosts # 列出此次的主機列表,但不做任何改變
--syntax-check # 語法檢查
-C, --check # 檢驗可能的錯誤,但不做任何改變
# 主機名文件保留
- "-t"或"--tree"選項可以將ansible的執行結果按主機名保存在指定目錄下的文件中
- 使用"-t"選項可以將第一次執行的結果按主機名保存在文件中, 此後即使不使用"-t"選項也能提升執行速度
# 命令示例
ansible 192.168.56.3 -a 'hostname' # 默認使用command模塊(不支持變量、管道等)
ansible 192.168.56.3 -m command -a 'hostname'
ansible Test --list # 列出Test組所有的主機列表
ansible Test:Test2 -m ping # 通過ping模塊檢查Test組和Test2組的主機是否存活
ansible Test:!Test2 -m ping # 在Test組但不在Test2組的主機
ansible Test:&Test2 -m ping # 同時存在Test組和Test2組的主機
ansible Tes* -m ping # 組名開頭為Tes的主機
ansible all -m shell -a 'hostname && date' # 通過shell模塊在所有主機試行shell命令
ansible all -f 10 -m shell -a 'hostname && date;cat /etc/system-release' # shell模塊支持變量、管道、if判斷等複雜命令
部分參數如果不指定,將採用ansible.cfg中的設置值,或者採用原始默認值。
Ansible ad-hoc常用命令
# ping 測試指定主機連接性
ansible ta -m ping
ansible -i /etc/ansible/hosts ta -m ping # 指定inventory文件
# command 在指定主機上執行命令(默認模塊),不支持變量、管道、重定向等shell特性
ansible ta -m command -a "chdir=/home/ ls ./" # 在遠程主機上切換到home目錄執行ls命令
# shell 在指定主機上執行命令或運行腳本,打開遠程主機的shell進程的一個子shell運行命令,支持shell的變量、管道、重定向等特性
ansible ta -m shell -a 'hostname && date;cat /etc/system-release' # 支持變量、管道、if判斷等複雜命令
ansible ta -m shell -a "echo 'this is a test' > test.txt" -C # 驗證可能的錯誤,但不做任何改變
ansible ta -m shell -a 'echo "123456"|passwd --stdin root' -K # 更改root密碼
# script 調用本地腳本在遠程主機執行,但只能執行腳本,不能調用其他指令,且不支持管道命令
ansible ta -m script -a "/home/vipxf/test.sh"
ansible ta -m script -a "removes=/home/vipxf/test.sh /home/vipxf/test2.sh" -o # 如果遠程主機上test.sh文件存在就執行本地腳本test2.sh,否則就不執行
ansible ta -m script -a "creates=/home/vipxf/test.sh /home/vipxf/test2.sh" -o # 如果遠程主機上test.sh文件存在就不執行本地腳本test2.sh,否則就執行
# raw 類似shell,支持管道命令,可用於沒有python環境的遠程主機
ansible ta -m raw -a "cd /home;pwd"
# stat 獲取文件信息
ansible ta -m stat -a "path=/etc/ansible/hosts"
# setup 系統信息,收集facts
ansible ta -m setup
ansible ta -m setup | grep "xxx" # 獲取主機所有facts然後結合grep命令過濾
ansible ta -m setup -a "filter=ansible_os_family" # 通過filter參數來查看指定信息
ansible ta -m setup -a 'filter="*mem*"' --tree ./facts # 通過filter參數查看指定信息並按主機名保存到facts目錄
# copy 複製文件到遠程主機的指定位置
ansible ta -m copy -a "src=/etc/hosts dest=~/test.hosts mode=664 owner=vipxf group=vipxf" # 複製本地文件到遠程主機並設置權限
ansible ta -m copy -a "content="this is a test" dest=~/test.hosts mode=664 owner=vipxf group=vipxf" # 在遠程主機創建指定內容文件並設置權限
# fetch 複製指定主機的文件到本地
ansible ta -m fetch -a "src=~/testfile.txt dest=~/" # 將在指定目錄下創建對應IP文件夾來存放文件,保留了原目錄結構
# get_url 在遠程主機下載網絡文件,支持文件校驗
ansible ta -m get_url -a "url=//172.20.5.3/pub/soft/docker/docker-19.03.9.tgz dest=~/ mode=655 owner=vipxf" # 下載文件到遠程主機指定目錄並設置權限
# file 設置文件屬性
ansible ta -m file -a "path=~/testfile.txt mode=755 owner=vipxf group=vipxf" # 更新文件屬性
ansible ta -m file -a "path=~/testfile.txt state=touch mode=644" # 創建文件
ansible ta -m file -a "path=~/testfile.txt state=absent" # 刪除文件
ansible ta -m file -a "path=~/testdir mode=755 state=directory" # 創建目錄
# cron 設置計劃任務
ansible ta -m cron -a "minute=0 hour=22 job='/home/vipxf/testcron.sh' name='test cron'" # 創建計劃任務
ansible ta -m cron -a "name='test cron' state=absent" # 刪除計劃任務
# group 管理用戶組
ansible ta -b --become-user root --become-method su -m group -a "name=test system=yes" --ask-become-pass # 創建用戶組
ansible ta -b --become-user root --become-method su -m group -a "name=test state=absent" --ask-become-pass # 刪除用戶組
# user 管理用戶
ansible ta -b --become-user root --become-method su -m user -a "name=test system=yes group=test password=pw@123" -K # 創建用戶
ansible ta -b --become-user root --become-method su -m user -a "name=test state=absent force=yes" -K # 刪除用戶
# service 管理服務
ansible ta -b --become-user root --become-method su -m service -a "name=sshd enabled=yes state=started" -K # 啟動httpd服務並且不設置開機啟動
ansible ta -b --become-user root --become-method su -m service -a "name=sshd state=stopped" -K # 停止httpd服務並且不設置開機啟動
# yum 管理程序包
ansible ta -b --become-user root --become-method su -m yum -a "name=httpd state=present" -K # 安裝包,也可以將state設為installed
ansible ta -b --become-user root --become-method su -m yum -a "name=httpd state=latest disable_gpg_check=no" -K # 關閉完整性校驗,安裝最新版包
ansible ta -b --become-user root --become-method su -m yum -a "name=httpd state=absent" -K # 卸載包,也可以將state設為removed
ansible ta -b --become-user root --become-method su -m yum -a "name=nginx state=latest enablerepo=local" -K # 啟用本地yum源安裝最新版軟件包
# hostname 管理主機名稱
ansible ta -b --become-user root --become-method su -m hostname -a "name=test" --ask-become-pass # 更改遠程主機名
Ansible 變量使用
- Ansible的變量名僅能由字母、數字和下劃線組成,且只能以字母開頭。
- Python關鍵字和playbook關鍵字都不能作為有效的變量名。
- Ansible的變量可以被定義在playbook、inventory、yaml格式文件、角色和命令行中,也可以將任務的輸出定義為變量。
Ansible 自定義變量
# 方式1:在Inventory中為主機或組定義專用變量
[groupname]
192.168.56.1 variable_name=value
[groupname:vars]
variable_name=value
[all:vars]
ansible_ssh_port="2222"
# 方式2:在playbook中通過關鍵字vars或vars_files定義變量
vars:
- var_name: value
- var_name: value
vars_files:
- ./external_vars.yml # 變量文件內容遵循yml格式
# 方式3:在playbook中把任務的輸出通過關鍵字register定義為變量,然後用於其他任務
tasks:
- name: test
shell: /usr/bin/foo
register: foo_result
# 方式4:在playbook中使用變量,執行palybook時通過命令行傳遞變量,通過「-e」或「--extra-vars」參數傳遞的變量優先級更高
ansible-playbook test.yml --extra-vars "hosts=Test user=anliven"
# 方式5:指定主機角色時通過 roles 傳遞變量,並在角色內通過` var_name `調用
roles:
- { role: ROLE_NAME, var: value, ...}
Ansible 系統變量
# 遠程主機的系統信息統稱為facts
# facts信息是JSON格式的數據結構,ansible_facts是最上層,可以使用 ansible_facts 變量查看所有內容
# 此外默認情況下使用 ansible_ 前綴可以將一些fact作為頂級變量訪問
# 通過 setup 模塊可以查看指定主機的所有facts信息,通過使用filter參數來查看指定信息
ansible <host> -m setup # 查看指定主機的facts信息
ansible ta -m setup | grep "xxx" # 獲取主機所有facts然後結合grep命令過濾
ansible ta -m setup -a "filter=ansible_os_family" # 通過filter參數來查看指定信息
ansible ta -m setup -a 'filter="*mem*"' --tree ./facts # 通過filter參數查看指定信息並按主機名保存到facts目錄
Ansible 引用變量
# 普通變量
通過 {{ var_name }} 方式引用
# 關鍵字register或系統fact變量
- 返回結果集通常是嵌套yaml或者json的數據結構
- 通過 {{ var_name.stdout }} 或 {{ ansible_facts["eth0"]["ipv4"]["address"] }} 的方式引用
Ansible 變量優先級
# 優先級
1. 命令行中定義的變量(用-e或--extra-vars定義的變量)
2. 在Inventory中定義的連接變量(比如:ansible_ssh_user)
3. 普通變量(命令行轉換、play中的變量、included的變量、role中的變量等)
4. 在Inventory中定義的其他變量
5. Facts變量
Ansible 清單定義
Ansible 主機清單(Inventory)
Ansible通過Inventory(可管理的主機集合)對遠端服務器或者主機進行統一操作和管理,默認將主機列在一個文本文件中,這個文件稱為Inventory文件。
- 默認的路徑和文件為:
/etc/ansible/hosts
- 可以通過ANSIBLE_HOSTS環境變量、ansible.cfg文件中inventory參數來指定,或者運行ansible和ansible-playbook時使用-i參數臨時指定
- 可以有多個 inventory 文件,也可以通過 Dynamic Inventory 動態生成
- inventory文件為 INI文件格式,中括號中的字符為組名。可以將同一個主機同時歸併到多個不同的組中
- 組名建議使用”_”來連接字符,例如「aaa_bbb_ccc」
Ansible Inventory文件
192.168.56.1 # 未分組
test.example.com
127.0.0.1 ansible_connection=local # 直接訪問本地主機,而不是通過SSH
[Test] # 已分組名稱
192.168.56.1
192.168.56.2
192.168.56.[3:4] # 通過列表方式通配地址
192.168.56.[5:6] # 多個通配地址
anliven-[a:d].example.com # 通配主機域名
[Test:vars] # 定義組變量
ansible_ssh_user="anliven"
ansible_ssh_pass="anliven"
ansible_ssh_port="22"
[Test2] # 在分組中指定變量
192.168.56.[1:2] ansible_ssh_user=anliven ansible_ssh_pass=Anliven
192.168.56.[3:4] ansible_ssh_user=anliven ansible_ssh_pass=Anliven
192.168.56.[3:4]
[Test3] # 在分組中切換root用戶
192.168.56.[1:2] ansible_ssh_port="22" ansible_ssh_user="anliven" ansible_ssh_pass="anliven" ansible_become_pass="Anliven"
[Temp]
192.168.56.1:2222 # 指定端口
192.168.56.2 http_port=8080 var1=test1 var2=test2 # 定義主機時為其添加主機變量以便於在playbook中使用
[Temp:vars]
ansible_ssh_user="anliven"
ansible_ssh_pass="anliven"
[TestGroup:children] # 嵌套組,TestGroup為名稱,其他為固定格式
Test1
Test2
Test3
[TestGroup:vars] # 嵌套組的變量只能在ansible-playbook中使用
var1="test1"
var2="123"
[all:vars] # 類似全局變量,對inventory文件中所有節點都有效
ansible_ssh_port="22"
Ansible Inventory內置參數
Ansible Inventory文件中可使用的行為參數
可以在ansible.cfg中的[defaults]部分更改一些Inventory行為參數的默認值
Ansible Dynamic Inventory
- 動態Inventory也就是Ansible所有的Inventory文件裏面的主機列表和變量信息都支持從外部拉取,例如CMDB等。
- 避免主機列表不準確和頻繁大量的手動更新的問題
- 也可以通過設置ansible.cfg文件中的inventory參數為一個可執行腳本,將CMDB等其他系統的主機信息同步至Ansible中。
- 對動態Inventory腳本的參數和輸出必須遵循格式規則
Ansible Inventory分割
通過Inventory分割滿足如下需要
- 按不同業務/系統分割成的多個Inventory文件
- 同時使用常規Inventory文件和動態Inventory腳本
實現方式
- 配置ansible.cfg文件的hostfile參數,指定放置inventory文件目錄作為Inventory,Ansible將合併目錄里所有文件為一個完整的Inventory
- 也可以在命令行中使用-i命令來指定特定的Inventory文件
[defaults]
hostfile = /etc/ansible/inventory # 指定目錄作為Inventory
Ansible 劇本執行
Ansible Playbook 基礎介紹
劇本(Playbook) 是 ansible 用於配置,部署,和管理被控節點的劇本。
- playbook類似Linux的shell腳本,用於實現和管理大量的、規律的、複雜的操作任務
- playbook方便代碼和配置的重用、移植性好,同時也易於管理
Playbook格式
# playbook文件由YMAL語言編寫,需遵循yaml格式要求
1. 第一行以 "---" 開始,表明YMAL文件的開始(非playbook強制要求,沒有也能通過語法檢查)
2. 列表元素以」-」開頭,後面帶有一個空格,然後元素內容
3. 對象的鍵與值以":"和一個空格來分隔
4. 相同層次內容必須保持相同的縮進和對齊,否則會報錯
5. 在同一行中,「#」 之後的內容表示注釋
6. 文件名應該以.yml或.yaml結尾
# 編寫完成後可以通過 --syntax-check 子命令檢查語法錯誤
ansible-playbook --syntax-check sample.yaml
Playbook組成
- 一個Playbook可以包括一個或多個Play。
- 一個Play由Host的無序集合與Task的有序列表組成。
- 每一個Task僅由一個模塊構成。
# play
- 一個Playbook包括一個或多個Play
- 一個Play由Host的無序集合與Task的有序列表組成
# 目標定義部分:host
- 執行playbook的主機信息
# 變量定義部分:variable
- 執行playbook需要的變量
- 設置的ansible配置變量,例如gather_facts
# 任務定義部分:tasks & module
- 在目標主機執行的任務列表和調用的模塊
- Play的主體部分,Task列表中的各任務按次序逐個在Hosts中的指定主機上執行
- 每一個Task僅由一個模塊構成
- 建議為每一個Task設置一個Name,便於在運行Playbook時從輸出結果辨別task信息
- Ansible的自帶模塊Command模塊和Shell模塊無需使用key=value格式,可以直接編寫要執行的命令
# 觸發器定義部分:handlers
- task執行完成後需要調用的任務,通常結合關鍵字notify
- 由通知者進行的Notify,如果沒有被Notify,則Handlers不會執行,如果被Notify了,則Handlers被執行
- 不管有多少個通知者進行了Notify,等到Play中的所有Task都執行完成之後,Handlers也只會被執行一次
- 實質上也是Task的列表
Ansible Playbook 示例
[root@test01 ansible-test]# pwd
/root/ansible-test
[root@test01 ansible-test]#
[root@test01 ansible-test]# ll
total 4
drwxr-xr-x 2 root root 24 Oct 17 09:47 conf
-rw-r--r-- 1 root root 922 Oct 14 11:24 sample.yaml
[root@test01 ansible-test]#
[root@test01 ansible-test]# tree
.
├── conf
│ └── httpd.conf
└── sample.yaml
1 directory, 2 files
[root@test01 ansible-test]#
[root@test01 ansible-test]# cat conf/httpd.conf
MaxClients {{ maxClients }}
Listen {{ httpd_port }}
[root@test01 ansible-test]#
[root@test01 ansible-test]# cat sample.yaml
- hosts: ta
remote_user: vipxf
gather_facts: no
vars:
- package: vim
tasks:
- name: install vim
yum: name={{ package }} state=latest
- name: install configuration file
become: yes
become_method: su
become_flags: "-"
become_user: root
template: src=/root/ansible-test/conf/httpd.conf dest=/root/test-template.conf
notify:
- check-hostname-date
- name: copy file
copy: src=/root/ansible-test/conf/httpd.conf dest=/home/vipxf/test-copy.conf
handlers:
- name: check-hostname-date
shell: hostname && date
ignore_errors: True
- hosts: ta
remote_user: vipxf
gather_facts: no
become: yes
become_method: su
become_flags: "-"
become_user: root
vars:
- newgroup: testgroup
- newuser: testuser
tasks:
- name: create new group
group: name={{ newgroup }} system=yes
- name: create new user
user: name={{ newuser }} group=testgroup system=yes
[root@test01 ansible-test]#
[root@test01 ansible-test]# cat /etc/ansible/hosts
[ta]
172.20.8.247 ansible_ssh_port=2222 ansible_ssh_user=vipxf ansible_ssh_pass=Anliven09!
[ta:vars]
httpd_port=80 maxClients=10
[root@test01 ansible-test]#
Ansible playbook 示例說明
- hosts: ta # 指定執行指定任務的主機,可以通過一個或多個由冒號分隔主機組
remote_user: vipxf # 指定在遠程主機執行任務的用戶,也能用在task中
gather_facts: no
vars:
- package: vim
tasks: # 任務列表,在指定主機上按順序執行各任務
- name: install vim # 每個任務的名稱,用於輸出執行結果
yum: name={{ package }} state=latest
- name: install configuration file
become: yes
become_method: su
become_flags: "-"
become_user: root
template: src=/root/ansible-test/conf/httpd.conf dest=/root/test-template.conf
notify: # 此任務狀態為changed時採取的操作,在handlers中定義
- check-hostname-date
- name: copy file
copy: src=/root/ansible-test/conf/httpd.conf dest=/home/vipxf/test-copy.conf
handlers: # 觸發器,在被指定任務通知和所有任務完成的情況下只執行一次,實質上也是按序執行的任務列表
- name: check-hostname-date
shell: hostname && date
ignore_errors: True # 如果命令或腳本的退出碼不為零,使用ignore_errors來忽略錯誤信息
- hosts: ta # playbook文件可以有多個play
remote_user: vipxf
gather_facts: no
become: yes
become_method: su
become_flags: "-"
become_user: root
vars:
- newgroup: testgroup
- newuser: testuser
tasks:
- name: create new group
group: name={{ newgroup }} system=yes
- name: create new user
user: name={{ newuser }} group=testgroup system=yes
相關命令
# Ansible具有冪等性,會自動跳過沒有變化的部分
# 建議使用絕對路徑來執行playbook的yaml文件
# 語法檢查 和 預測試 不能保證結果絕對正確,實際的運行測試是有必要的
# 特別注意yml文件的內容格式(空格、縮進)、特殊字符等,必要時重寫重建
--------------------------------------------------------------------------------
## 列出主機列表、任務列表和標籤列表
ansible-playbook --list-hosts --list-tasks --list-tags sample.yaml
--------------------------------------------------------------------------------
## 檢查內容語法錯誤
ansible-playbook --syntax-check sample.yaml
## 預測試(不改變目標主機的任何設置)
ansible-playbook --check sample.yaml --ask-become-pass
ansible-playbook -C sample.yaml --ask-become-pass
--------------------------------------------------------------------------------
## 選擇playbook開始執行的任務
ansible-playbook sample.yaml --start-at-task="common" # 從名稱為common的任務開始執行playbook
## 詳細模式下執行playbook,根據提示輸入root密碼
ansible-playbook -v sample.yaml --ask-become-pass
## verbose mode (-vvv for more, -vvvv to enable connection debugging)
ansible-playbook -vvv sample.yaml --ask-become-pass
返回結果
# 一般以紅色、黃色、綠色來表示執行結果
- 綠色:執行成功,未更改目標主機狀態
- 黃色:執行成功,對目標主機完成變更,目標主機狀態有變化
- 紫色:執行結果出現警告或提示信息
- 紅色:執行失敗,結果出現異常
# 在playbook執行後,會明確列出任務執行狀態的匯總信息
# 任務執行狀態包括:ok、changed、unreachable、failed、skipped、rescued、ignored
結果示例
[root@test02 ~]# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:50:56:a1:07:78 brd ff:ff:ff:ff:ff:ff
inet 172.20.8.247/24 brd 172.20.8.255 scope global noprefixroute ens192
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fea1:778/64 scope link
valid_lft forever preferred_lft forever
[root@test02 ~]#
[root@test02 ~]# vim -h | head -n 1
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Jun 14 2019 10:43:10)
[root@test02 ~]#
[root@test02 ~]# pwd
/root
[root@test02 ~]# ll test-template.conf
-rw-r--r-- 1 root root 38 Oct 17 18:18 test-template.conf
[root@test02 ~]#
[root@test02 ~]# ll /home/vipxf/test-copy.conf
-rw-rw-r-- 1 vipxf vipxf 66 Oct 17 18:18 /home/vipxf/test-copy.conf
[root@test02 ~]#
[root@test02 ~]# cat /etc/group |grep test
testgroup:x:995:
testuser:x:994:
[root@test02 ~]# cat /etc/passwd |grep test
testuser:x:997:995::/home/testuser:/bin/bash
[root@test02 ~]#
Ansible Playbook 條件判斷(When)
when語句可以將變量、facts或此前任務的執行結果作為指定task是否執行的前提條件,也可以判斷變量是否被定義。
示例-1:when
- hosts: ta
remote_user: vipxf
gather_facts: yes
tasks:
- name: test
shell: echo "test"
when: ansible_os_family == "RedHat" and ansible_distribution_version == "7.8" # 可以使用facts、playbook 或Inventory中定義的變量
- name: test1
shell: echo "step1"
register: result # 將執行結果定義為變量
- name: test2
shell: echo "step2"
when: result.rc == 0 # 基於先前任務的結果來執行
- name: test3
shell: echo "step3"
when: result.stderr != ""
- name: test4
shell: echo "step4"
when: result.changed == "true"
示例-2:結合fail語句
test.sh
[vipxf@test02 ~]$ pwd
/home/vipxf
[vipxf@test02 ~]$
[vipxf@test02 ~]$ ll test.sh
-rw-rw-r-- 1 vipxf vipxf 127 Oct 21 00:11 test.sh
[vipxf@test02 ~]$
[vipxf@test02 ~]$ cat test.sh
#!/bin/bash
if [ "$1" = "Anliven" ];then
echo "Success"
else
echo "Failed"
fi
[vipxf@test02 ~]$
when2.yaml
[root@test01 ansible-test]# cat when2.yaml
- hosts: ta
remote_user: vipxf
gather_facts: yes
vars:
- teststring: Failed
tasks:
- name: test1
shell: sh /home/vipxf/test.sh {{ testvar }}
register: result
- name: test2
shell: echo "rc 0"
when: result.rc == 0 # 基於先前任務的結果來執行
- name: test3
shell: echo "Success"
when: '"Success" in result.stdout' # 對stdout結果進行判斷
- name: test4
fail: msg="Check Failed" # 任務報錯並拋出msg信息
when: result.stdout == (( teststring )) # 在when使用playbook中定義的變量
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-playbook -v when2.yaml -e testvar=Anliven
Using /etc/ansible/ansible.cfg as config file
PLAY [ta] *********************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************
ok: [172.20.8.247]
TASK [test1] ******************************************************************************************************************************************************************************************
changed: [172.20.8.247] => {"changed": true, "cmd": "sh /home/vipxf/test.sh Anliven", "delta": "0:00:00.003638", "end": "2022-10-21 18:05:00.273596", "rc": 0, "start": "2022-10-21 18:05:00.269958", "stderr": "", "stderr_lines": [], "stdout": "Success", "stdout_lines": ["Success"]}
TASK [test2] ******************************************************************************************************************************************************************************************
changed: [172.20.8.247] => {"changed": true, "cmd": "echo \"rc 0\"", "delta": "0:00:00.002893", "end": "2022-10-21 18:05:00.722340", "rc": 0, "start": "2022-10-21 18:05:00.719447", "stderr": "", "stderr_lines": [], "stdout": "rc 0", "stdout_lines": ["rc 0"]}
TASK [test3] ******************************************************************************************************************************************************************************************
changed: [172.20.8.247] => {"changed": true, "cmd": "echo \"Success\"", "delta": "0:00:00.002632", "end": "2022-10-21 18:05:01.172659", "rc": 0, "start": "2022-10-21 18:05:01.170027", "stderr": "", "stderr_lines": [], "stdout": "Success", "stdout_lines": ["Success"]}
TASK [test4] ******************************************************************************************************************************************************************************************
skipping: [172.20.8.247] => {"changed": false, "skip_reason": "Conditional result was False"}
PLAY RECAP ********************************************************************************************************************************************************************************************
172.20.8.247 : ok=4 changed=3 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-playbook -v when2.yaml -e testvar="test"
Using /etc/ansible/ansible.cfg as config file
PLAY [ta] *********************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************
ok: [172.20.8.247]
TASK [test1] ******************************************************************************************************************************************************************************************
changed: [172.20.8.247] => {"changed": true, "cmd": "sh /home/vipxf/test.sh test", "delta": "0:00:00.003612", "end": "2022-10-21 18:06:49.907767", "rc": 0, "start": "2022-10-21 18:06:49.904155", "stderr": "", "stderr_lines": [], "stdout": "Failed", "stdout_lines": ["Failed"]}
TASK [test2] ******************************************************************************************************************************************************************************************
changed: [172.20.8.247] => {"changed": true, "cmd": "echo \"rc 0\"", "delta": "0:00:00.002721", "end": "2022-10-21 18:06:50.338001", "rc": 0, "start": "2022-10-21 18:06:50.335280", "stderr": "", "stderr_lines": [], "stdout": "rc 0", "stdout_lines": ["rc 0"]}
TASK [test3] ******************************************************************************************************************************************************************************************
skipping: [172.20.8.247] => {"changed": false, "skip_reason": "Conditional result was False"}
TASK [test4] ******************************************************************************************************************************************************************************************
fatal: [172.20.8.247]: FAILED! => {"changed": false, "msg": "Check Failed"}
PLAY RECAP ********************************************************************************************************************************************************************************************
172.20.8.247 : ok=3 changed=2 unreachable=0 failed=1 skipped=1 rescued=0 ignored=0
[root@test01 ansible-test]#
changed_when 與 failed_when
# changed_when
# 在條件成立時,將對應任務的執行狀態設置為changed
# 先執行task,並對task返回的值進行判斷,當滿足changed_when指定的條件時說明是執行成功的
# 默認情況下執行命令完成的主機狀態都為changed
- name: all host run this task
shell: hostname
register: info
changed_when: '"webserver01" in info.stdout' # 輸出包含某個特定字符才能將主機狀態設為changed
# failed_when
# 在條件成立時,將對應任務的執行狀態設置為失敗
# 當執行失敗後會將信息存在register的stderr中,通過判斷指定的字符是否在stderr中來確定是否真的失敗
# 其實是ansible的一種錯誤處理機制:由fail模塊組合了when條件語句的效果
- name: this command prints FAILED when it fails
command: echo "FAILED"
register: command_result
failed_when: "'FAILED' in command_result.stdout"
Ansible Playbook 循環迭代(with_items)
用來在playbook中實現循環迭代的功能。
支持元素列表、文件名(with_fileglob)、複合(with_together)、步進(with_sequence)、隨機(with_random_choice)、until等多種類型循環。
- name: test with_items
hosts: ta
remote_user: vipxf
gather_facts: yes
tasks:
- name: test1
shell: echo {{ item }} # 通過引用item變量來迭代
with_items:
- one
- two
- three
- name: test2
shell: echo {{ item.name }} with {{ item.value }} # 通過字典來迭代
with_items:
- { name: 'one', value: '111'}
- { name: 'two', value: '222'}
- { name: 'three', value: '333'}
- name: test3
copy: src={{ item }} dest=~/ mode=664 owner=vipxf group=vipxf # 把文件名作為變量循環
with_fileglob:
- /playbook/files/*
Ansible Playbook 角色(Roles)
- 角色(roles)用於層次性、結構化地組織playbook
- 通過規範的目錄存儲結構將變量、文件、任務、模板以及觸發器等放置於單獨目錄
- 通過獨立的role目錄將不同的playbook任務單一化,從而實現高效的代碼復用
- 在playbook中調用roles,根據層次型結構自動轉載roles的變量文件、tasks以及handlers等要素信息
- 一般用於基於主機構建服務和進程的場景
- 可以在 /etc/ansible/ansible.cfg 中設置 roles_path 來設置roles文件路徑
創建role
1. 創建 roles 名稱的目錄
2. 在 roles 目錄中分別創建各角色命名的目錄,如webserver等
3. 在每個角色命名的目錄中分別創建defaults、files、handlers、meta、tasks、templates和vars等目錄;如果為空目錄則不被引用
4. 在roles的整體編排文件playbook中調用各角色
目錄結構說明
site.yml # playbook文件,roles的整體編排文件
roles/ # 定義各角色的總目錄
common/ # 角色role模塊名,在playbook中需要調用時使用的名稱
default/ # 默認變量文件目錄(定義此角色的默認變量),至少包含一個main.yml文件,在main.yml文件中可以用include指令將其他yml文件包含進來
files/ # 存放由copy或script等模塊調用的文件
handlers/ # 觸發器文件目錄,至少包含一個main.yml文件,在main.yml文件中可以用include指令將其他yml文件包含進來
meta/ # 此角色的元數據(特殊設定及其依賴關係),至少包含一個main.yml文件,在main.yml文件中可以用include指令將其他yml文件包含進來
tasks/ # 任務文件目錄,至少包含一個main.yml文件,在main.yml文件中可以用include指令將其他yml文件包含進來
templates/ # 模板文件目錄,template模塊會自動在此目錄中尋找
vars/ # 變量文件目錄,至少包含一個main.yml文件,在main.yml文件中可以用include指令將其他yml文件包含進來
webserver/ # 角色 webserver 目錄
default/
files/
handlers/
meta/
tasks/
templates/
vars/
調用方式
在playbook中可以通過關鍵字 roles 來調用角色role。
- hosts: webserver
remote_user: anliven
roles: # 使用關鍵字roles調用角色role
- common # 調用role
- webserver # 調研多個role
- hosts: webserver
remote_user: anliven
roles:
- common
- { role: foo_app_instance, dir:'/opt/a',port:5000} # 可以向roles傳遞參數
- { role: foo_app_instance, dir:'/opt/b',port:5001}
- hosts:webserver
remote_user: anliven
roles:
- { role: some_role, when: "ansible_so_family == 'RedHat" } # 指定調用roles的條件
Ansible Playbook 標籤(Tags)
- 通過標籤(tags)可以選擇運行或跳過playbook中的指定任務
- 在playbook為任務定義一個”標籤”,在通過ansible-playbook命令執行此playbook時使用 –tags 或 –skip-tags選項選擇運行或跳過這個任務
- 可以使用系統特殊標籤,也可以自定義標籤
- 可以為同一個任務設定多個標籤,也可以為不同的任務設定相同的標籤
語法格式
# 格式1
tags:
- testtag
- t2
# 格式2
tags: testtag,t2
# 格式3
tags: ['testtag','t2']
特殊標籤
always 除非--skip-tags選項指定,否則 always 標籤的task會一直執行
never 除非--tags選項指定,否則 never 標籤的task都不會執行
tagged 不包括never的所有標籤
untagged 所有無標籤和always標籤
all 包括非never標籤和無標籤
選項
# 如果執行 ansible-playbook 時不指定標籤,則會執行所有非 never 標籤的任務
--tags "tag1,tag2..." 執行指定標籤和always標籤的tasks
--tags always 只執行always標籤的tasks
--tags all 執行所有非never標籤和無標籤的tasks
--tags never 執行always和never標籤的tasks
--tags tagged 執行所有標籤的tasks,但不包括never標籤的tasks
--tags untagged 執行所有無標籤和always標籤的tasks
--skip-tags "tag1,tag2..." 跳過指定標籤的tasks
--list-tags 查看playbook中哪些tags會被執行
tags示例
tasks:
- name: install package
yum: name={{ packagename }} state=latest
tags:
- always
- name: copy configuration file
copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
tags: conf,http
命令示例
ansible-playbook nginx_tags.yaml --tags "testtag,t2"
Ansible Playbook 調試(Debug)
- Print statements during execution
- 在Ansible Playbook中常使用debug模塊,可以在Playbook執行過程打印調試信息
- 結合when條件語句一起使用時,可以調試特定條件下的執行過程
注意:在setup模塊中查詢出來的變量,直接可以在debug中直接作為變量引用。
# msg
輸出自定義信息,如果不指定或不寫msg的話,默認也會輸出「null」
# var
- 指定要打印的變量名,與msg參數互斥,二者只能有一個
- var參數中的變量不需要使用{{}}表達式,而msg中需要
# verbosity
- debug的調試級別,默認0是全部顯示,級別調整到3是忽略內容不顯示
- 在命令中使用-vvv參數,可以在設置為3情況下仍然顯示debug內容
示例
tasks:
- name: Host run this task
debug: 'msg="{{ ansible_fqdn }} and {{ ansible_default_ipv4.address }}"' # 打印必要信息
when: ansible_memtotal_mb < 500 and ansible_processor_cores == 2 # 結合when使用
- name: all host run this task
shell: hostname
register: info
- name: Hostname is webserver01 Machie run this task
debug: 'msg="{{ ansible_fqdn }}"'
when: info['stdout'].startswith('Success')
- name: Show debug info
debug: var=info verbosity=1 # 打印var變量信息,調試級別為1
Ansilbe 加密解密
ansible-vault 用途
- encryption/decryption utility for Ansible data files
- 主要應用於包含敏感信息的場景,可以加密和解密敏感信息
- See ‘ansible-vault
–help’ for more information on a specific command.
# ansible-vault -h
usage: ansible-vault [-h] [--version] [-v]
{create,decrypt,edit,view,encrypt,encrypt_string,rekey}
...
encryption/decryption utility for Ansible data files
positional arguments:
{create,decrypt,edit,view,encrypt,encrypt_string,rekey}
create Create new vault encrypted file
decrypt Decrypt vault encrypted file
edit Edit vault encrypted file
view View vault encrypted file
encrypt Encrypt YAML file
encrypt_string Encrypt a string
rekey Re-key a vault encrypted file
optional arguments:
--version show program's version number, config file location, configured module search path, module location, executable location and exit
-h, --help show this help message and exit
-v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging)
See 'ansible-vault <command> --help' for more information on a specific command.
ansible-vault 常用命令
# 加密文件
ansible-vault encrypt test-vault.yml
ansible-vault encrypt test-vault.yml --vault-password-file pwdfile
# 解密文件
ansible-vault decrypt test-vault.yml
ansible-vault decrypt test-vault.yml --vault-password-file pwdfile
# 查看文件
ansible-vault view test-vault.yml
ansible-vault view test-vault.yml --vault-password-file pwdfile
# 重置文件密碼
ansible-vault rekey test-vault.yml
ansible-vault rekey test-vault.yml --vault-password-file pwdfile --new-vault-password-file pwdfilenew
# 創建加密文件
ansible-vault create test-vault.yml
ansible-vault create test-vault.yml --vault-password-file pwdfile
# 編輯加密文件
ansible-vault edit test-vault.yml
ansible-vault edit test-vault.yml --vault-password-file pwdfile
# 加密字符串
ansible-vault encrypt_string 'test123456'
ansible-vault encrypt_string 'test123456' --name 'ansible_ssh_pass'
ansible-vault encrypt_string 'test123456' --name 'ansible_ssh_pass' --vault-id anliven@pwdfile
ansible-vault “–vault-id”選項
# 從ansible2.4版本開始,官方推薦使用"--vault-id"選項代替"--vault-password-file"選項指定密碼文件
# 「--vault-id prompt」功能上等同於"--ask-vault-pass"選項
# 支持同時使用多個密碼文件進行解密,適用於「引用其他文件」的場景
# 可以在被加密文件中包含特定字符「做記號」
ansible-vault encrypt_string 'test123456' --name 'ansible_ssh_pass' --vault-id pwdfile # 加密字符串
ansible-vault encrypt test-vault.yml --vault-id pwdfile # 加密文件
ansible-vault encrypt test-vault.yml --vault-id anliven@pwdfile # 加密完成後的文件內容包含anliven字符
ansible-vault decrypt test-vault.yml --vault-id pwdfile # 解密文件
ansible-vault view test-vault.yml --vault-id pwdfile # 查看文件
ansible-vault edit test-vault.yml --vault-id pwdfile # 編輯文件
ansible-vault rekey test-vault.yml --vault-id pwdfile # 交互式密碼重置
ansible-vault rekey test-vault.yml --vault-id pwdfile --new-vault-id pwdfilenew # 通過新密碼文件重置
ansible-playbook test-vault.yml --vault-id pwdfile # 運行playbook
ansible-playbook test-vault.yml --vault-id pwdfile1 --vault-id pwdfile2 # 提供多個密碼文件來解密,test-vault.yml中引用其他vault加密文件
ansible-playbook test-vault1.yml test-vault2.yml --vault-id pwdfile1 --vault-id pwdfile2 # 提供多個加密文件來解密多個文件
ansible-vault 示例
示例-1 交互式密碼
[root@test01 ansible-test]# cat test-vault.yml
- hosts: ta
gather_facts: no
tasks:
- debug:
msg: "test ansible-vault"
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-playbook test-vault.yml
PLAY [ta] *********************************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************
ok: [172.20.8.247] => {
"msg": "test ansible-vault"
}
PLAY RECAP ********************************************************************************************************************************************************************************************
172.20.8.247 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-vault encrypt test-vault.yml
New Vault password:
Confirm New Vault password:
Encryption successful
[root@test01 ansible-test]#
[root@test01 ansible-test]# cat test-vault.yml
$ANSIBLE_VAULT;1.1;AES256
32656239643632646139633938613430326139636636333235346361643161393131396661366534
6636386331316239616632316137316266316266646432360a366366643232313033343835346638
38616331636639643731633766333335613763623636333363336238353931616263313637313834
3135656632343034340a316238656238336432386638373236653738306530383232626231333438
38666338346130333561316535353637616230633634346162303730393166396230616533396435
38346536306433653566373438303565373036663138366330313836356666656639393438396134
35333465623365636531653562363366323065316238333333353863376236373362373832633636
62613732666263306531653231353931326635303533623934633235396239613838613230323862
3134
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-vault view test-vault.yml
Vault password:
- hosts: ta
gather_facts: no
tasks:
- debug:
msg: "test ansible-vault"
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-playbook --ask-vault-pass test-vault.yml
Vault password:
PLAY [ta] *********************************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************
ok: [172.20.8.247] => {
"msg": "test ansible-vault"
}
PLAY RECAP ********************************************************************************************************************************************************************************************
172.20.8.247 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-vault decrypt test-vault.yml
Vault password:
Decryption successful
[root@test01 ansible-test]#
[root@test01 ansible-test]# cat test-vault.yml
- hosts: ta
gather_facts: no
tasks:
- debug:
msg: "test ansible-vault"
[root@test01 ansible-test]#
示例-2 密碼文件
[root@test01 ansible-test]# echo "This-is_a#Test!2o22" > pwdfile
echo "This-is_a#Testhistoryo22" > pwdfile
[root@test01 ansible-test]#
[root@test01 ansible-test]# cat pwdfile
This-is_a#Testhistoryo22
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-vault encrypt test-vault.yml --vault-password-file pwdfile
Encryption successful
[root@test01 ansible-test]#
[root@test01 ansible-test]# cat test-vault.yml
$ANSIBLE_VAULT;1.1;AES256
63343030376661643237653266366133313735363630353564363631376563613236383863346264
6163303562643831636237633038373265616334343234630a613466663138396334303463623665
30353632396236306435633062383864646466616261393064313633373635353633656161393266
3234326635323438610a376631323634316663313130356466306238306638613261663138333663
30363461616433643530656562313139303831346365346531303530666236373038306435636338
39666432326465313834613164356436653366656138613634303339346130353033313330303733
30643934383363333261646366396330343164393236633138383137316166643966393838396464
64323863306539333534663938393962326231373137613630623635313534356163363261626262
3765
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-vault view test-vault.yml --vault-password-file pwdfile
- hosts: ta
gather_facts: no
tasks:
- debug:
msg: "test ansible-vault"
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-playbook test-vault.yml --vault-password-file pwdfile
PLAY [ta] *********************************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************
ok: [172.20.8.247] => {
"msg": "test ansible-vault"
}
PLAY RECAP ********************************************************************************************************************************************************************************************
172.20.8.247 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-vault decrypt test-vault.yml --vault-password-file pwdfile
Decryption successful
[root@test01 ansible-test]#
[root@test01 ansible-test]# cat test-vault.yml
- hosts: ta
gather_facts: no
tasks:
- debug:
msg: "test ansible-vault"
[root@test01 ansible-test]#
示例-3 加密字符串
[root@test01 ansible-test]# ansible-vault encrypt_string "test123456"
New Vault password:
Confirm New Vault password:
!vault |
$ANSIBLE_VAULT;1.1;AES256
33383336353737346430653165326665393430346539376334396335336530613330643764313962
3438366538366262316666353962663564666532393333300a333934633664393262653065343864
63653361666133363862353061323238376335666165313130393664623761393033343136343265
6166663630353038380a666164643565343336373062323135643038363436343938383363303632
6230
Encryption successful
[root@test01 ansible-test]#
[root@test01 ansible-test]# vim test-encrypt_string.yaml
[root@test01 ansible-test]#
[root@test01 ansible-test]# cat test-encrypt_string.yaml
- hosts: ta
gather_facts: no
vars:
test_user: "testuser"
test_passwd: !vault |
$ANSIBLE_VAULT;1.1;AES256
33383336353737346430653165326665393430346539376334396335336530613330643764313962
3438366538366262316666353962663564666532393333300a333934633664393262653065343864
63653361666133363862353061323238376335666165313130393664623761393033343136343265
6166663630353038380a666164643565343336373062323135643038363436343938383363303632
6230
tasks:
- debug:
msg: "{{test_user}}"
- debug:
msg: "{{test_passwd}}"
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-playbook test-encrypt_string.yaml --ask-vault-pass
Vault password:
PLAY [ta] *********************************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************
ok: [172.20.8.247] => {
"msg": "testuser"
}
TASK [debug] ******************************************************************************************************************************************************************************************
ok: [172.20.8.247] => {
"msg": "test123456"
}
PLAY RECAP ********************************************************************************************************************************************************************************************
172.20.8.247 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@test01 ansible-test]#
示例-4 通過密碼文件加密字符串
[root@test01 ansible-test]# ansible-vault encrypt_string "test123456" --name "test_passwd" --vault-id anliven@pwdfile
test_passwd: !vault |
$ANSIBLE_VAULT;1.2;AES256;anliven
61646130623833333634646632393432326431383864663134356530323536663165303061313661
3365343837623564343037663236316635666565613730350a393731646238376638363365363561
35383465336137313134306363363139386537633839393363653465333161303634313832383136
3038326464613935350a383565343261363833333631663862336464303538323561363237326637
3431
Encryption successful
[root@test01 ansible-test]#
[root@test01 ansible-test]# vim test-encrypt_string.yaml
[root@test01 ansible-test]# cat test-encrypt_string.yaml
- hosts: ta
gather_facts: no
vars:
test_user: "testuser"
test_passwd: !vault |
$ANSIBLE_VAULT;1.2;AES256;anliven
61646130623833333634646632393432326431383864663134356530323536663165303061313661
3365343837623564343037663236316635666565613730350a393731646238376638363365363561
35383465336137313134306363363139386537633839393363653465333161303634313832383136
3038326464613935350a383565343261363833333631663862336464303538323561363237326637
3431
tasks:
- debug:
msg: "{{test_user}}"
- debug:
msg: "{{test_passwd}}"
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-playbook test-encrypt_string.yaml --vault-id pwdfile
PLAY [ta] *********************************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************
ok: [172.20.8.247] => {
"msg": "testuser"
}
TASK [debug] ******************************************************************************************************************************************************************************************
ok: [172.20.8.247] => {
"msg": "test123456"
}
PLAY RECAP ********************************************************************************************************************************************************************************************
172.20.8.247 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@test01 ansible-test]#
Ansible 性能優化
在默認設置的情況下,Ansible的執行效率已經可以滿足大多數場景。
面對巨量目標主機時,可以通過一些配置優化去再提高ansible的執行效率。
Ansible 基本設置
# 通過 time 命令統計執行時間
time <ansible-command>
# 關閉SSH密鑰檢測
- 以SSH登錄遠程設備時,默認該設備會檢查遠程主機的公鑰,並且將該公鑰記錄在~/.ssh/known_hosts文件中
- 當下次該主機訪問時會核對公鑰,如果公鑰不同則會發出警告,如果公鑰相同,則會提示輸入密碼
- 對主機公鑰的檢查是根據StrictHostKeyChecking變量的檢查級別確定:no(不檢查)、ask(是否檢查要詢問)、yes(每次都檢查)、False(關閉檢查)
- 設置 /etc/ansible/ansible.cfg 中參數 host_key_checking = False
# 並發數forks
- Ansible默認只會創建5個進程並發執行任務,所以在任務中只能同時控制5台主機執行
- forks是線程數,受限於CPU的核心數,加大forks值能讓CPU盡量提升並發數量,一定程度上提高執行效率
- 設置 /etc/ansible/ansible.cfg 中 forks 參數,默認值為5
- 在執行命令時通過 -f 參數指定並發數
# 關閉 gather_facts
- playbook默認執行第一個tasks是gather_facts,用於收集主機信息
- 如果任務並不需要調用主機信息變量,建議關閉可以減少Ansible在收集客戶端信息的時間,提高運行速度
- 可以在playbook文件中設置gather_facts參數為false或no(不區分大小寫)
gather_facts: False
gather_facts: no
- 也可以設置 /etc/ansible/ansible.cfg 中參數
gather_facts: no
# 設置 facts緩存
- 不過禁用facts,可以採用facts緩存保證一定的運行效率來使用facts信息
- 在ansible.cfg中可以配置多種facts緩存的方式:json文件,redis,memcache等
- 使用redis存儲facts文件需安裝redis和響應的python庫
- 以json文件方式為例
gathering=smart
fact_caching_timeout=86400
fact_caching=jsonfile
fact_caching_connection=/path/to/ansible_fact_cache
# serial滾動更新
- 並發可以在ansible.cfg里修改配置,也可以在playbook中限制服務端的並發數量
- Ansible默認將嘗試並行管理playbook中所有的機器,可以使用serial關鍵字定義一次應管理多少主機
- 常應用與負載均衡環境下,不能一次性停止所有主機的場景
- 在play或者task下都可以設置serial參數,但其值對應的主機數不應大於forks值
serial: "30%" # 按百分比執行
serial: 2 # 指定單次執行數量
# OpenSSH鏈接優化(非必要,不建議)
- 默認情況下,使用OpenSSH時,服務器端會根據客戶端的IP地址進行DNS反向解析,然後根據獲取到的主機名再次進行DNS查詢得到IP地址,比較這兩個IP地址是否一致
- 可以在一定程度上提高安全性,但會花費更多時間,可以關閉這一特性來實現加速SSH鏈接速度
- 設置 /etc/ssh/sshd_config 中參數 UseDNS no
# 開啟pipeling
- 發送執行命令代替命令臨時文件(針對不使用sudo的場景,建議以單獨ansible.cfg文件方式開啟)
- 設置 /etc/ansible/ansible.cfg 中參數 pipelining = True
Ansible 異步async與輪詢polling特性
# Ansible的異步async與輪詢polling特性
# 適合使用到ansible的polling特性的場景
# - task需要運行很長的時間,這個task很可能會達到timeout
# - 任務需要在大量的機器上面運行
# - 任務是不需要等待它完成的
# 不適合使用polling特性的場景
# - task任務是需要運行完後才能繼續另外的任務的
# - task任務能很快的完成
# 注意:需在ansible服務端的/etc/ansible/ansible.cfg文件里配置"host_key_checking = False"
- hosts: all
max_fail_percentage: 30 # 主機數最大失敗百分比,只有在大於時中止tasks的執行,結合serial參數則以serial值為基準
serial: 7 # 定義同時執行操作的主機數,一般要小於forks的值,否則會按forks值進行「分片」執行任務
tasks:
- name: test-1
shell: sleep 5 && echo "test-1 done" && hostname && date
async: 9 # 任務執行時間的上限值,超時則任務失敗,建議設置為略大於任務正常實際執行時長,設置為0時表示一直等待任務結束
poll: 2 # 檢查任務結果的間隔時長,建議設置為小於任務實際執行時長,設置為0表示不用等待結果繼續執行後續任務
register: script_result
- name: test-2
async_status: jid={{ script_result.ansible_job_id }} # 通過模塊async_status查看輪詢結果
register: job_result
until: job_result.finished #
retries: 10 # 重試10次
- name: test-3 # 將在所有主機執行完成後一次性返回結果
shell: echo "test-3 done" && hostname && date
Ansible 圖形界面
Ansible Web UI目前主要有官方商業版Tower、官方開源版AWX 和 開源免費版semaphore。
Ansible Tower
- Ansible官方Web UI
- 文檔: //docs.ansible.com/ansible-tower/#tower-translated-zh
- 安裝包: //releases.ansible.com/ansible-tower/setup-bundle/
- 支持docker-compose部署
Ansible AWX
- Ansible Tower的免費開源版本
- GitHub://github.com/ansible/awx
- 包://github.com/ansible/awx/releases
- 支持docker-compose部署
semaphore
- 開源的Ansible Web UI
- GitHub://github.com/ansible-semaphore/semaphore
- 文檔://docs.ansible-semaphore.com/administration-guide/installation
- 支持Docker-compose部署
Ansible 技巧提示
1 – Ansible 免密登錄
# 通過秘鑰方式連接
ssh-keygen -t rsa
ssh-copy-id -i /vipxf/.ssh/id_rsa.pub [email protected]
ssh-copy-id -i /vipxf/.ssh/id_rsa.pub [email protected]
2 – Ansible playbook輸入root密碼
[root@test01 ansible-test]# cat test-temp.yaml
---
- name: test-root
hosts: ta
remote_user: vipxf
gather_facts: no
become: yes
become_user: root
become_method: su
become_flags: "-"
vars:
ansible_become_pass: "{{ root_pass_input }}"
tasks:
- name: test
shell: date && sleep 3
ignore_errors: True
[root@test01 ansible-test]#
[root@test01 ansible-test]# ansible-playbook test-temp.yaml -e root_pass_input=redhat
PLAY [test-root] **************************************************************************************************************************************************************************************************************
TASK [test] *******************************************************************************************************************************************************************************************************************
changed: [172.20.8.247]
PLAY RECAP ********************************************************************************************************************************************************************************************************************
172.20.8.247 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@test01 ansible-test]#
3 – Ansible 簡單的復用方式
通過關鍵字include可以實現簡單的代碼復用。
# 在playbook中,Include 指令可以跟task 混合在一起使用
- tasks:
- include: tasks/foo.yml # 引用配置文件
# 參數化的include
- tasks:
- include: aaa.yml user=anliven # 引用配置文件的同時傳入變量
- include: bbb.yml pwd=P@ssw0rd
4 – Ansible task通知多個handlers任務
通過關鍵字listen為handlers中的一個或多個觸發器任務指定主題,task就可以按主題名進行通知。
觸發順序按照handler定義的先後順序執行。
---
- hosts: ta
remote_user: vipxf
gather_facts: no
vars:
- package: vim
tasks:
- name: test-step one
shell: echo "111"
notify: "test listen" # task通知handlers主題
- name: test-step two
shell: echo "222"
handlers:
- name: check-hostname-date
shell: hostname && date
ignore_errors: True
listen: "test listen" # 按照定義順序被觸發
- name: who-am-i
shell: whoami && date
ignore_errors: True
listen: "test listen" # 按照定義順序被觸發
獨立章節索引
- Ansible – 1 – 概念介紹 : //www.cnblogs.com/anliven/p/16850434.html
- Ansible – 2 – 命令講解 : //www.cnblogs.com/anliven/p/16850503.html
- Ansible – 3 – 變量使用 : //www.cnblogs.com/anliven/p/16850555.html
- Ansible – 4 – 清單定義 : //www.cnblogs.com/anliven/p/16850578.html
- Ansible – 5 – 劇本執行 : //www.cnblogs.com/anliven/p/16857755.html
- Ansible – 6 – 加密解密 : //www.cnblogs.com/anliven/p/16850607.html
- Ansible – 7 – 性能優化 : //www.cnblogs.com/anliven/p/16857814.html
- Ansible – 8 – 圖形界面 : //www.cnblogs.com/anliven/p/16857902.html
- Ansible – 9 – 技巧提示 : //www.cnblogs.com/anliven/p/16857920.html