信息采集到自動(dòng)化實(shí)戰(zhàn))
剛接手一個(gè)新環(huán)境時(shí)我習(xí)慣先看看手上這批機(jī)器到底是什么底細(xì)——操作系統(tǒng)版本、CPU架構(gòu)、內(nèi)存多大、磁盤剩多少、Python裝在哪個(gè)路徑。放在以前要么登錄每臺(tái)機(jī)器敲命令要么寫個(gè)腳本批量去跑怎么都不夠優(yōu)雅。后來(lái)用上Ansible我發(fā)現(xiàn)自己可以在完全不了解目標(biāo)主機(jī)的情況下直接寫playbook去操作它全靠facts在背后幫我兜底。這篇文章就圍繞Ansible facts展開(kāi)講清楚它是什么、怎么用、能拿哪些關(guān)鍵信息以及我在實(shí)際項(xiàng)目中踩過(guò)的那些坑。適合剛學(xué)Ansible不久、想真正掌控inventory的讀者也適合已經(jīng)寫了不少playbook但總覺(jué)得糊里糊涂的人。1. 理解factsAnsible為什么自帶“主機(jī)體檢報(bào)告”1.1 facts到底是什么Ansible在運(yùn)行playbook時(shí)默認(rèn)會(huì)在執(zhí)行任務(wù)之前先把目標(biāo)主機(jī)“掃”一遍收集這臺(tái)機(jī)器幾乎所有的基本信息——主機(jī)名、操作系統(tǒng)、IP地址、內(nèi)存和磁盤容量、CPU型號(hào)與核數(shù)、已安裝的軟件包、掛載的文件系統(tǒng)、系統(tǒng)啟動(dòng)時(shí)間等等。這一整套自動(dòng)采集到的信息就是facts。聽(tīng)起來(lái)很抽象你可以把它理解成Ansible給每臺(tái)被管機(jī)器自動(dòng)生成的一份“體檢報(bào)告”。報(bào)告內(nèi)容包括硬件配置、系統(tǒng)環(huán)境、網(wǎng)絡(luò)狀態(tài)等幾十個(gè)大類、幾百個(gè)小項(xiàng)。這些數(shù)據(jù)會(huì)被放進(jìn)一個(gè)叫ansible_facts的變量結(jié)構(gòu)中后續(xù)的任務(wù)可以直接引用比如“只在CentOS系統(tǒng)上執(zhí)行某操作”“獲取這臺(tái)機(jī)器的默認(rèn)IPv4地址并寫入配置”。我在剛開(kāi)始學(xué)Ansible時(shí)有個(gè)認(rèn)知誤區(qū)以為inventory文件里寫的那些ansible_host、ansible_user就是facts。其實(shí)那是連接參數(shù)作用在使用SSH連上目標(biāo)機(jī)器。而facts是在連接成功之后由Ansible主動(dòng)在遠(yuǎn)端執(zhí)行內(nèi)置模塊采集來(lái)的真實(shí)信息兩者完全不同。1.2 孤立的facts與全局變量體系facts之所以重要首先是因?yàn)樗宲laybook具備了“感知環(huán)境”的能力。同一套playbook下發(fā)到不同的機(jī)器組它會(huì)根據(jù)facts自動(dòng)調(diào)整行為不需要人為為每組機(jī)器各寫一套邏輯。其次facts是臨時(shí)性的。主機(jī)重啟、網(wǎng)絡(luò)變更、軟件安裝之后facts都會(huì)隨之變化。每次執(zhí)行playbook時(shí)重新采集能拿到機(jī)器的最新?tīng)顟B(tài)這一點(diǎn)對(duì)自動(dòng)化運(yùn)維很關(guān)鍵。另外facts不只是給“自動(dòng)化任務(wù)”用的。你可以利用gather_facts收集到的信息做資產(chǎn)盤點(diǎn)把機(jī)器信息導(dǎo)出成清單輔助運(yùn)維報(bào)表或設(shè)備臺(tái)賬建設(shè)。要理解facts的定位它是Ansible從inventory靜態(tài)描述走向動(dòng)態(tài)感知的關(guān)鍵橋梁。2. 如何采集facts并查看完整信息2.1 使用setup模塊手動(dòng)采集執(zhí)行playbook時(shí)facts默認(rèn)是自動(dòng)采集的。如果你想單獨(dú)查看某一臺(tái)機(jī)器或一組機(jī)器的facts不需要寫playbook直接用setup模塊就能完成ansible test_host -m setup這條命令會(huì)對(duì)test_host主機(jī)執(zhí)行facts收集并把完整結(jié)果以JSON格式打印到終端。由于信息量很大終端輸出會(huì)非常長(zhǎng)。我常用參數(shù)來(lái)精確過(guò)濾需要的內(nèi)容ansible test_host -m setup -a filteransible_os_family ansible test_host -m setup -a filteransible_memtotal_mb注意這里的filter是“包含匹配”不是精確匹配。比如filteransible_eth會(huì)把所有網(wǎng)卡相關(guān)字段都匹配出來(lái)。想知道這臺(tái)機(jī)器有哪些虛擬網(wǎng)卡、哪些物理網(wǎng)卡嗯用這個(gè)filter直接列出來(lái)了。2.2 playbook中控制facts的采集在playbook里facts采集由gather_facts控制默認(rèn)值為true- hosts: all gather_facts: true tasks: - name: Show hostname debug: var: ansible_facts[hostname]新版Ansible2.5推薦通過(guò)ansible_facts[hostname]這種形式訪問(wèn)不用再裸用老式的ansible_hostname。兩種寫法目前都兼容但建議在新項(xiàng)目里統(tǒng)一用ansible_facts字典語(yǔ)義更清晰也能避免變量名沖突。還有一個(gè)值得注意的點(diǎn)setup模塊支持參數(shù)所以你可以強(qiáng)制刷新緩存里的factsansible test_host -m setup --flush-cache這個(gè)命令會(huì)忽略已有的facts緩存強(qiáng)制重新采集一遍。后面講緩存機(jī)制時(shí)這個(gè)操作很有用。2.3 gather_facts設(shè)為false的場(chǎng)景不是每個(gè)playbook都需要facts。比如你只是批量重啟服務(wù)、拷貝幾個(gè)靜態(tài)文件機(jī)器的操作系統(tǒng)版本、內(nèi)存情況根本用不上。這種情況下把gather_facts關(guān)掉能省掉不少時(shí)間尤其是管理幾百臺(tái)機(jī)器時(shí)效果非常明顯。- hosts: all gather_facts: false tasks: - name: Copy a file copy: src: /local/path/file dest: /opt/file從反饋時(shí)間上看關(guān)閉facts采集后單臺(tái)機(jī)器可以省下1到3秒。機(jī)器數(shù)量越多節(jié)省的時(shí)間越可觀。但有一個(gè)前提任務(wù)里千萬(wàn)不能引用任何facts變量否則會(huì)直接報(bào)“變量未定義”的錯(cuò)誤到時(shí)候還得回頭開(kāi)啟采集。2.4 哪些facts值得關(guān)注的一覽表facts字段非常多為了不讓初學(xué)者迷路我整理了一份高頻字段速查分類字段名含義系統(tǒng)ansible_facts[distribution]發(fā)行版名稱如CentOS、Ubuntu系統(tǒng)ansible_facts[distribution_version]發(fā)行版版本號(hào)系統(tǒng)ansible_facts[os_family]系統(tǒng)家族如RedHat、Debian網(wǎng)絡(luò)ansible_facts[default_ipv4][address]默認(rèn)路由對(duì)應(yīng)的IPv4地址網(wǎng)絡(luò)ansible_facts[dns][nameservers]當(dāng)前使用的DNS服務(wù)器列表硬件ansible_facts[memtotal_mb]總內(nèi)存大小MB硬件ansible_facts[processor_cores]物理CPU核心數(shù)硬件ansible_facts[processor_count]邏輯CPU數(shù)量存儲(chǔ)ansible_facts[mounts]掛載點(diǎn)詳細(xì)信息列表存儲(chǔ)ansible_facts[devices][sda][size]第一塊磁盤容量時(shí)間ansible_facts[date_time][iso8601]系統(tǒng)當(dāng)前時(shí)間ISO格式包管理ansible_facts[pkg_mgr]使用的包管理器名稱這份表只是冰山一角。實(shí)際上facts里還包含每個(gè)網(wǎng)卡的MAC地址、IPv6地址、系統(tǒng)時(shí)區(qū)、SELinux狀態(tài)、Python解釋器路徑等幾百個(gè)字段。能用好其中二三十個(gè)日常自動(dòng)化任務(wù)基本就夠了。3. 核心字段解析從系統(tǒng)到網(wǎng)絡(luò)、從存儲(chǔ)到虛擬化3.1 系統(tǒng)基礎(chǔ)信息判斷寫playbook時(shí)最常見(jiàn)的需求是“根據(jù)系統(tǒng)類型做不同處理”。比如同一套部署腳本在RedHat系用yum安裝依賴在Debian系用apt。以下是兩種判斷寫法- name: Install package according to OS family yum: name: httpd state: present when: ansible_facts[os_family] RedHat - name: Install package according to OS family apt: name: apache2 state: present when: ansible_facts[os_family] Debian使用場(chǎng)景再寬一點(diǎn)比如某個(gè)任務(wù)只允許在CentOS 7以上執(zhí)行直接組合使用when: - ansible_facts[distribution] CentOS - ansible_facts[distribution_major_version] is version(7, )要留意一個(gè)問(wèn)題CentOS和RedHat的os_family都是RedHat而某些Linux分支比如Fedora也是RedHat家族但軟件包管理上有差異。判斷時(shí)需要組合多個(gè)字段切忌只憑一個(gè)os_family下結(jié)論。3.2 網(wǎng)絡(luò)信息與IP地址獲取另一個(gè)高頻需求是把目標(biāo)機(jī)器的IP地址動(dòng)態(tài)寫入配置或服務(wù)注冊(cè)。假設(shè)我要獲取默認(rèn)IPv4地址可以這樣寫- name: Show default IP debug: msg: The default IP is {{ ansible_facts[default_ipv4][address] }}如果你有多個(gè)網(wǎng)卡要單獨(dú)獲取字段會(huì)變成這樣ansible_facts[ansible_eth0][ipv4][address]不過(guò)這里我需要特別提醒在Ansible 2.12之前的版本里ansible_facts[ansible_eth0]這種寫法可能會(huì)因?yàn)閮?nèi)部變量排序問(wèn)題出現(xiàn)錯(cuò)誤推薦使用無(wú)前綴形式ansible_facts[eth0]。我當(dāng)時(shí)升級(jí)Ansible版本時(shí)踩過(guò)這個(gè)坑查了很久才發(fā)現(xiàn)是facts索引的問(wèn)題。獲取所有網(wǎng)卡的所有地址可以對(duì)ansible_facts[interfaces]列表做遍歷。這個(gè)字段返回的是所有網(wǎng)卡名稱的列表你可以結(jié)合具體網(wǎng)卡繼續(xù)向下讀取。3.3 硬件資源與存儲(chǔ)信息在做容量規(guī)劃或資源檢查時(shí)內(nèi)存和磁盤是最常關(guān)注的。以下是我檢查物理內(nèi)存和磁盤的常用片段- name: Check memory threshold debug: msg: Memory too low! Current {{ ansible_facts[memtotal_mb] }} MB when: ansible_facts[memtotal_mb] 2048磁盤掛在facts里比較復(fù)雜mounts是一個(gè)列表每個(gè)元素包含mount、device、fstype、size_total、size_available等信息。想判斷根分區(qū)是否剩余空間不足用when引用when: item.size_available 1073741824這里size_available的單位是字節(jié)不要和人的直覺(jué)搞混。1GB等于1073741824字節(jié)但有些文件系統(tǒng)會(huì)按1024進(jìn)制直接用這個(gè)裸數(shù)字比較更準(zhǔn)確。如果你只關(guān)心磁盤設(shè)備本身而不關(guān)心掛載點(diǎn)devices字典里按塊設(shè)備名稱排列比如/dev/sda的對(duì)應(yīng)鍵是sda里面包含分區(qū)表、大小、旋轉(zhuǎn)類型等字段。遍歷時(shí)會(huì)非常詳細(xì)。3.4 內(nèi)核與虛擬化、云環(huán)境信息知道目標(biāo)機(jī)器是虛擬機(jī)還是物理機(jī)對(duì)不少運(yùn)維場(chǎng)景很重要。比如某些驅(qū)動(dòng)安裝、性能調(diào)優(yōu)任務(wù)需要區(qū)分虛擬化平臺(tái)。可以通過(guò)virtualization_type字段做判斷- name: Run only on virtual machines debug: msg: This is a VM running on {{ ansible_facts[virtualization_type] }} when: ansible_facts[virtualization_type] in [VMware, kvm, xen]如果機(jī)器部署在云平臺(tái)上比如AWS或阿里云facts里還有對(duì)應(yīng)的ansible_facts[ec2]或廠商特定的元數(shù)據(jù)字段能拿到的信息比物理機(jī)豐富不少。這在自動(dòng)擴(kuò)縮容或云資源自動(dòng)化場(chǎng)景下很有用。值得注意的是不同平臺(tái)收集到的facts覆蓋范圍不一樣比如在容器環(huán)境下virtualization_type可能是docker或containerd。寫playbook時(shí)不要想當(dāng)然認(rèn)為某些字段一定存在必要時(shí)先打印一遍實(shí)測(cè)數(shù)據(jù)。4. facts的實(shí)戰(zhàn)應(yīng)用條件判斷、模板渲染與自省4.1 條件判斷讓playbook“看懂”機(jī)器facts最常見(jiàn)的用途就是配合when做條件執(zhí)行。除了基礎(chǔ)的OS判斷我舉一個(gè)更實(shí)際的生產(chǎn)場(chǎng)景某服務(wù)基于systemd管理但老舊的CentOS 6并沒(méi)有systemd需要退回到service模塊??梢赃@樣實(shí)現(xiàn)- name: Start service with systemd systemd: name: my_service state: restarted when: ansible_facts[service_mgr] systemd - name: Start service with sysvinit service: name: my_service state: restarted when: ansible_facts[service_mgr] sysvinit這里的service_mgr字段記錄了系統(tǒng)使用哪種服務(wù)管理器Ansible收集facts時(shí)自動(dòng)識(shí)別。利用這種機(jī)制同一套playbook可以覆蓋新舊兩代系統(tǒng)不用維護(hù)兩套文件。4.2 把facts渲染進(jìn)模板文件另一個(gè)高頻場(chǎng)景是把facts變量帶進(jìn)Jinja2模板中。比如我要在每臺(tái)機(jī)器上生成一個(gè)包含自身主機(jī)名和IP的配置文件# server.conf hostname{{ ansible_facts[hostname] }} ip{{ ansible_facts[default_ipv4][address] }} platform{{ ansible_facts[distribution] }} {{ ansible_facts[distribution_version] }}對(duì)應(yīng)的playbook任務(wù)如下- name: Generate config with facts template: src: server.conf.j2 dest: /etc/my_app/server.conf這種做法可以動(dòng)態(tài)生成每臺(tái)機(jī)器專屬的配置不需要在inventory里手工定義一堆變量。模板中還可以使用Jinja2過(guò)濾器比如把內(nèi)存大小從字節(jié)轉(zhuǎn)成GB或者對(duì)字符串做拼接處理讓配置更易讀。4.3 用facts做動(dòng)態(tài)資產(chǎn)清單我見(jiàn)過(guò)不少團(tuán)隊(duì)用Ansible做資產(chǎn)盤點(diǎn)。其實(shí)不需要額外開(kāi)發(fā)直接利用setup模塊加上模板就可以生成一份格式化的服務(wù)器清單。下面是一個(gè)思路- hosts: all tasks: - name: Generate inventory report local_action: module: template src: inventory_report.j2 dest: ./reports/{{ inventory_hostname }}_{{ ansible_facts[date_time][date] }}.txt模板里按表格列出主機(jī)名、IP、CPU、內(nèi)存、磁盤等信息。當(dāng)機(jī)器數(shù)量增多時(shí)還可以直接用add_host和group_by基于facts動(dòng)態(tài)分組實(shí)現(xiàn)真正的“inventory自適應(yīng)”。這種玩法對(duì)我來(lái)說(shuō)幫助最大因?yàn)樗岇o態(tài)的inventory變成了一套能實(shí)時(shí)反映真實(shí)環(huán)境的數(shù)據(jù)源省去了額外開(kāi)發(fā)CMDB的成本。5. 性能優(yōu)化與緩存大型環(huán)境下的facts策略5.1 默認(rèn)采集的代價(jià)每執(zhí)行一次playbookAnsible都會(huì)對(duì)每臺(tái)目標(biāo)機(jī)器生成一個(gè)新的SSH連接并運(yùn)行fact收集。在管理幾十臺(tái)以內(nèi)的機(jī)器時(shí)這個(gè)開(kāi)銷并不明顯但當(dāng)你管理幾百上千臺(tái)機(jī)器時(shí)facts收集時(shí)間會(huì)成為整個(gè)playbook運(yùn)行的大頭。我自己在一組約300臺(tái)機(jī)器的環(huán)境里實(shí)測(cè)過(guò)僅gather_facts階段就要占用整個(gè)執(zhí)行時(shí)間的三分之一左右。如果你的任務(wù)根本用不到facts關(guān)掉它是零成本優(yōu)化如果必須要用則需要考慮緩存方案。5.2 啟用facts緩存redis方案Ansible支持多種fact緩存后端我用得最順的是redis適合中大型環(huán)境。配置方法在ansible.cfg中完成[defaults] gathering smart fact_caching redis fact_caching_timeout 86400這里gathering smart表示如果facts緩存存在且未過(guò)期就直接使用緩存結(jié)果只有緩存缺失或過(guò)期時(shí)才重新采集。fact_caching_timeout設(shè)置緩存有效期單位為秒86400就是24小時(shí)。使用redis作為緩存后端需要提前在控制機(jī)安裝redis并啟動(dòng)服務(wù)。另外一個(gè)容易被忽略的細(xì)節(jié)如果修改了目標(biāo)機(jī)器的網(wǎng)絡(luò)或系統(tǒng)配置舊的facts緩存不會(huì)自動(dòng)失效需要手動(dòng)執(zhí)行ansible test_host -m setup --flush-cache來(lái)刷新否則任務(wù)會(huì)一直基于舊數(shù)據(jù)運(yùn)行。如果你不想引入redis用JSON文件做緩存也可以適合小型環(huán)境[defaults] fact_caching jsonfile fact_caching_connection /tmp/ansible/facts_cache fact_caching_timeout 86400這種方式配置更簡(jiǎn)單不需要額外的服務(wù)依賴。5.3 減少facts采集的另一條路按需加載除了緩存我還會(huì)配合gather_facts: false然后在具體任務(wù)里按需用setup模塊手動(dòng)采集個(gè)別機(jī)器甚至用booleans精簡(jiǎn)。setup模塊還支持gather_subset參數(shù)只采集特定子集例如只采集硬件信息ansible test_host -m setup -a gather_subsethardwaregather_subset可用的值包括all、min、hardware、network、virtual等。min是最小集速度最快。如果只需要少數(shù)幾個(gè)字段它比全量采集快出不少。但注意gather_subset和filter并不完全相同。filter是在收集結(jié)果之后做字段過(guò)濾數(shù)據(jù)采集動(dòng)作依然全量執(zhí)行g(shù)ather_subset則是在源頭控制采集范圍性能收益更大。6. 自定義facts讓機(jī)器匯報(bào)私有狀態(tài)6.1 local facts機(jī)制有些信息Ansible的默認(rèn)采集是拿不到的比如你只有通過(guò)某個(gè)腳本才能獲取的業(yè)務(wù)自定義狀態(tài)像是數(shù)據(jù)庫(kù)集群的主備角色、應(yīng)用當(dāng)前的運(yùn)行模式。這時(shí)候可以用local facts把信息注入facts體系。local facts的存放位置是目標(biāo)機(jī)器的/etc/ansible/facts.d/目錄。目錄下的每個(gè).fact文件會(huì)被Ansible在收集facts時(shí)解析并把文件內(nèi)容放進(jìn)ansible_facts[local]字典中。假設(shè)你寫了一個(gè)腳本輸出以下JSON到/etc/ansible/facts.d/cluster_info.fact{ role: primary, status: healthy, sync_lag_seconds: 0 }之后在playbook里就可以直接引用- name: Check cluster role debug: msg: This node is {{ ansible_facts[local][cluster_info][role] }}local facts的價(jià)值是把業(yè)務(wù)信息變成Ansible原生可讀的數(shù)據(jù)結(jié)構(gòu)既可以用在條件判斷里也可以渲染到模板中。6.2 用INI格式定義local factslocal facts文件除了JSON還支持INI格式。比如[web] port 8080 ssl_enabled false引用方式變?yōu)閍nsible_facts[local][web][port]INI格式更簡(jiǎn)潔適合寫少量鍵值對(duì)JSON格式表達(dá)能力更強(qiáng)適合嵌套結(jié)構(gòu)。兩種混用場(chǎng)景也存在看團(tuán)隊(duì)習(xí)慣。6.3 寫local facts文件的注意事項(xiàng)寫local facts時(shí)有幾個(gè)坑我踩過(guò)文件擴(kuò)展名必須是.fact但內(nèi)容既可以是可以直接解析的靜態(tài)數(shù)據(jù)也可以是可執(zhí)行腳本Ansible會(huì)判斷文件內(nèi)容類型。如果是腳本需要確保該腳本有執(zhí)行權(quán)限并且以輸出合法JSON為最終結(jié)果否則會(huì)被Ansible當(dāng)作普通文件嘗試解析報(bào)錯(cuò)率很高。local facts目錄如果不存在Ansible會(huì)自動(dòng)創(chuàng)建但目標(biāo)機(jī)器必須有寫權(quán)限。使用非root用戶管理時(shí)需要檢查sudo規(guī)則。腳本型local facts不能使用Jinja2模板渲染因?yàn)樗趂acts收集階段只是被執(zhí)行。如果你需要?jiǎng)討B(tài)渲染建議把渲染好的配置文件用template模塊下發(fā)到.fact路徑。local facts用得好可以讓每臺(tái)機(jī)器把自己最核心的業(yè)務(wù)狀態(tài)主動(dòng)告訴Ansible而不用通過(guò)復(fù)雜的inventory變量或外部CMDB去同步。7. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄7.1 為什么我拿不到某個(gè)facts字段新手常遇到“明明在文檔里看到這個(gè)字段但執(zhí)行playbook時(shí)報(bào)變量未定義”。原因通常有幾個(gè)Ansible版本差異。不同版本的facts字段名可能有調(diào)整過(guò)濾字段時(shí)建議先跑一次setup模塊看實(shí)際輸出用哪個(gè)字段直接對(duì)照結(jié)果來(lái)。平臺(tái)差異。Windows、網(wǎng)絡(luò)設(shè)備的facts結(jié)構(gòu)和Linux完全不同不能照搬Linux字段。使用了gather_facts: false但某個(gè)任務(wù)里又引用了facts變量。排查時(shí)先檢查play的gather_facts設(shè)置。namespaced版本問(wèn)題。老式寫法ansible_hostname在某些情況下還能用但如果你用ansible_facts[ansible_hostname]反而可能取不到值因?yàn)榍短钻P(guān)系變了。推薦寫ansible_facts[hostname]。排查這類問(wèn)題最快的辦法就是先用setup模塊過(guò)濾一下實(shí)際看看數(shù)據(jù)長(zhǎng)什么樣而不是反復(fù)猜字段名。7.2 變量?jī)?yōu)先級(jí)沖突同名變量覆蓋facts在Ansible中playbook中定義的變量?jī)?yōu)先級(jí)高于facts。如果你在vars里定義了一個(gè)server_ip而facts里也有同名key任務(wù)里引用時(shí)會(huì)優(yōu)先使用vars里的值。這一點(diǎn)需要小心避免引發(fā)“看起來(lái)沒(méi)生效”的詭異現(xiàn)象。建議給自定義變量起有區(qū)分度的名字盡量不要和facts字段重合。如果確實(shí)需要覆蓋要清楚自己正在做什么否則排查半天找不到原因。7.3 gather_facts超時(shí)問(wèn)題管理大量機(jī)器時(shí)gather_facts偶爾出現(xiàn)超時(shí)或連接中斷。主要誘因是目標(biāo)機(jī)器的SSH配置、網(wǎng)絡(luò)延遲、Python版本差異等??梢詮膸追矫嫒胧挚刂茩C(jī)到目標(biāo)機(jī)器的網(wǎng)絡(luò)質(zhì)量如果SSH本身連接慢facts采集自然慢。目標(biāo)機(jī)器的Python路徑不一致時(shí)Ansible會(huì)自動(dòng)探測(cè)解釋器這會(huì)增加耗時(shí)。可以在ansible.cfg中顯式設(shè)置ansible_python_interpreter。嘗試用gather_subsetmin減少采集范圍。調(diào)高超時(shí)時(shí)間配置如timeout 30。實(shí)際項(xiàng)目中我發(fā)現(xiàn)很多超時(shí)并不是Ansible本身慢而是因?yàn)槟繕?biāo)機(jī)器負(fù)載過(guò)高導(dǎo)致執(zhí)行環(huán)境響應(yīng)慢。這種情況下適當(dāng)調(diào)低并發(fā)數(shù)用串行分批執(zhí)行反而更穩(wěn)定。7.4 緩存中的facts過(guò)期使用facts緩存后有一個(gè)很容易被忽略的問(wèn)題目標(biāo)機(jī)器變化了Ansible卻仍然按舊數(shù)據(jù)執(zhí)行。比如新加了IP、擴(kuò)容了內(nèi)存、裝了新網(wǎng)卡但緩存沒(méi)刷新。這時(shí)候手動(dòng)刷新單臺(tái)機(jī)器ansible target_host -m setup --flush-cache刷新后重新跑playbook就能看到新數(shù)據(jù)。如果大批量刷新注意控制并發(fā)避免短時(shí)間內(nèi)對(duì)大量目標(biāo)機(jī)器發(fā)起密集的fact收集請(qǐng)求導(dǎo)致目標(biāo)機(jī)器或網(wǎng)絡(luò)負(fù)載過(guò)高。7.5 常見(jiàn)問(wèn)題速查表問(wèn)題現(xiàn)象可能原因解決辦法變量未定義引用了不存在的facts字段用setup模塊過(guò)濾觀察實(shí)際字段與文檔字段不一致Ansible版本差異升級(jí)到較新版本或按實(shí)際輸出為準(zhǔn)每次playbook執(zhí)行很慢未使用facts緩存在ansible.cfg開(kāi)啟redis或jsonfile緩存任務(wù)里取不到factsgather_facts被設(shè)為false檢查playbook開(kāi)頭gather_facts配置修改了主機(jī)信息但沒(méi)變化facts緩存未刷新執(zhí)行setup --flush-cachelocal facts不生效文件擴(kuò)展名不對(duì)或沒(méi)有執(zhí)行權(quán)限檢查.fact后綴和權(quán)限8. 經(jīng)驗(yàn)總結(jié)我的facts使用守則寫到這里我把這幾年使用facts的幾條個(gè)人心得整理一下不一定都是大道理但都是實(shí)操換來(lái)的。第一不到萬(wàn)不得已不要全量打印facts。很多云平臺(tái)的日志系統(tǒng)會(huì)收集完整執(zhí)行輸出直接debug一個(gè)完整的ansible_facts會(huì)把幾百行JSON灌進(jìn)日志排查問(wèn)題反而困難。需要什么就filter什么。第二facts采集不是免費(fèi)的午餐。如果你管理的主機(jī)比較多且每個(gè)playbook都默認(rèn)采集facts批量任務(wù)的整體耗時(shí)會(huì)上漲得非???。用不到facts的playbook第一行就寫gather_facts: false按需開(kāi)啟。第三local facts是你的好朋友。當(dāng)你覺(jué)得默認(rèn)facts不夠用時(shí)先別急著引入復(fù)雜的外部系統(tǒng)寫一個(gè)腳本輸出JSON放到facts.d目錄事情就解決了一大半。第四版本升級(jí)后務(wù)必回歸測(cè)試facts用法。Ansible在2.5、2.8、2.12這幾個(gè)版本里都對(duì)facts做了結(jié)構(gòu)調(diào)整老寫法不一定在新版本還能跑。每次升級(jí)Ansible主版本我都會(huì)先跑一遍setup模塊的抽樣測(cè)試確認(rèn)核心字段沒(méi)有變化。最后分享一個(gè)小技巧在編寫新的playbook時(shí)我會(huì)先加一個(gè)臨時(shí)的debug任務(wù)把需要引用的字段先打出來(lái)跑一遍確認(rèn)無(wú)誤后再刪掉。這個(gè)方法幫我省掉了大量“靠猜字段名排錯(cuò)”的時(shí)間。