Ansible 演進史(上):Agentless、YAML 與 Red Hat 收購
2012 年 2 月 23 日晚間,Michael DeHaan 在新建立的 Git 儲存庫裡留下第一個 commit,訊息只有一個字:「Genesis.」那時的程式碼庫僅有 12 個模組;七年後的 2.9 版,模組目錄已膨脹至 3,908 個檔案。
從個人週末專案起步,僅憑 600 萬美元 A 輪融資,三年內便以超過 1 億美元被 Red Hat 收購。但奠定 Ansible 技術版圖的,是專案初期拍板的兩大決定:捨棄常駐 Daemon、改走臨時 SSH 連線,以及不自製專用 DSL、全面採用 YAML。
這兩項選型讓 Ansible 在 Puppet 與 Chef 雙雄稱霸的時代以極低門檻突圍,卻也在日後演變為沉重的架構負債。DeHaan 在 2015 年初離開專案,同年 10 月公司便被收購。此後數年間,他多次坦承:後期的 Ansible 早已偏離他當初追求極簡工具的初衷。
2012 之前:Cobbler、Func 與中間地帶的痛點
Ansible 的誕生並非憑空而來,而是 DeHaan 第三次嘗試解決同一類系統維運難題。
2005 年,DeHaan 進入 Red Hat 的新興技術團隊,開發了佈建工具 Cobbler,透過 PXE 網路開機,自動化裸機的作業系統安裝。Cobbler 解決的是「伺服器從無到有」的安裝流程,但他很快發現,在裸機完成作業系統安裝之後、到組態管理工具正式接手之前,存在一段維運空白。
為了填補這段空白,DeHaan 隨後與 Seth Vidal 等人共同打造了遠端任務執行框架 Func。Func 採用了典型的「常駐程式(daemon)搭配 PKI 憑證體系」架構,也就是由中央簽發憑證、讓機器之間據此驗證身分,甚至直接移植了 Puppet 的憑證管理機制。
這段親手實作的經驗,讓他深刻體會到常駐程式與憑證信任鏈在真實機房運作時有多脆弱。
離開 Red Hat 後,DeHaan 曾短暫加入 Puppet Labs。這段經歷反而成為他另起爐灶的催化劑——他希望能有一種工具,既不必像 Puppet 那樣在每台機器安裝 agent、維護憑證,又能像 Capistrano(Ruby 社群常用的 SSH 部署工具)那樣,直接從控制端把指令推送到遠端機器。
+----------------------+
| Bare-metal Provision |
| (Cobbler, 2005) |
+----------------------+
|
v
+----------------------+
| Remote Execution |
| (Func, Seth/DeHaan) |
+----------------------+
|
|--> [ The Missing Gap ]
| (Ansible born here)
v
+----------------------+
| Config Management |
| (Puppet / Chef) |
+----------------------+
當時由 Puppet(2005)與 Chef(2009)主導的組態管理市場,普遍遵循 CFEngine 的「期望狀態收斂」理論:中央主控端(master)保存設定,各節點安裝常駐程式(agent)定期拉取並修正漂移。
這套架構在設計哲學上極具說服力,但在實務運作時卻伴隨著三筆高昂的初期固定成本:
- 節點鋪設成本:每台目標機器都必須預先安裝 agent,但在受限環境或全新機器上,往往連登入安裝都有困難。
- 憑證維護泥淖:每台節點的憑證都由 master 簽發,並綁定主機名稱與有效期限。DNS 解析不一致、時鐘沒同步(NTP),或重灌機器後沒清掉舊憑證,都會讓驗證失敗、節點斷線,而且往往「明明什麼都沒改」。
- 專用語言門檻:維運人員必須額外學習 Puppet 宣告式 DSL,或是為了 Chef 去精通 Ruby 語法。
DeHaan 曾回憶,光是為了解決憑證與網路設定,就常耗費數天。如果一套自動化工具必須先花三天排除環境問題才能開始運作,它所能節省的效益就大打折扣。
「我希望自動化看起來像購物清單。」
兩大技術賭注:Agentless 與 YAML
2012 年 2 月底,Ansible 的原型在短短兩週內成形。DeHaan 在發布第一個 commit 之後,隨即在 Cobbler 郵件列表中向早期使用者公開了這個專案。
Ansible 的第一個核心賭注,是徹底放棄常駐 agent,改採純粹的「控制端推送(Push)」模型。
[ Controller (Laptop / CI) ]
|
| Temporary SSH / Python script execution
v
+---------------+
| Target Host | (No Daemon, No PKI, Python only)
+---------------+
被管理的目標節點上什麼常駐程式都不留,僅透過系統原本就內建的 SSH 管道(Windows 則走 WinRM),將臨時產生的 Python 腳本推送至遠端執行,取得 JSON 結果後立即清理現場。
這個決定打破了當時的主流慣例。Ansible 不再靠常駐程式定期檢查並自動修正漂移,playbook(描述要做哪些設定的任務清單)只在維運人員手動或由 CI 觸發執行的那一刻確保機器狀態。不過單次執行依然保有模組層級的冪等性(Idempotence):同一份設定重複執行,已符合期望的項目不會被重複修改。
| 比較面向 | Master-Agent 模型(Puppet / Chef) | Agentless Push 模型(Ansible) |
|---|---|---|
| 節點先決條件 | 目標機需預先安裝 Agent 與相依環境 | 僅需目標機內建 SSH 與 Python |
| 信任與安全 | 需獨立維護 master/node PKI 憑證鏈 | 複用既有 SSH 金鑰與 sudo 權限體系 |
| 語言學習曲線 | 需學習專屬 DSL 或精通 Ruby 語法 | 直覺填寫 YAML 結構宣告 |
| 執行與收斂 | 背景 Daemon 定期輪詢自動收斂漂移 | 控制端隨選推送,單次執行保證冪等性 |
| 上手驗證門檻 | 需數小時至數天排除網路與憑證障礙 | 30 分鐘內可由工程師個人筆電直接跑起來 |
早期貢獻者 Seth Vidal(yum 的作者)曾給過 DeHaan 一個關鍵建議:
「如果人們沒辦法在大約 30 分鐘內試成功,他們就會走掉。」
DeHaan 將這句話視為核心準則——用他自己的話說,「你得讓人在午休時間之內就成功一次」——並將早期四成的精力投入撰寫清晰平實的文件。
第二個關鍵賭注,是捨棄自製 DSL,全面採用 YAML 定義 Playbook。
許多人將 YAML 視為刻意的易讀性設計,但 DeHaan 多年後坦承,最現實的原因是他身為個人開發者,不想自己撰寫並長期維護一套專屬的語法解析器(Parser)。
採用現成的 YAML,等於把語法解析與編輯器支援交給成熟的現有工具處理。系統管理員不用學 Ruby 或專用語法,只要照著縮排填寫鍵值對,就能直覺上手。
這兩大賭注很快奏效。RedMonk 於 2015 年的統計顯示,Ansible 的 fork 數以每月約 200 次的速度成長,約為 Salt 的兩倍,2014 年間的社群活躍度也一路領先,Puppet 與 Chef 則大致持平。模組數量也從 1.0 版的 57 個,增加到 DeHaan 離職時的 400 個,約為原本的七倍。
商業化:Open Core、600 萬融資與 Red Hat 收購
隨著專案人氣暴漲,DeHaan 與 Saïd Ziouani 等人於 2013 年 3 月成立了 AnsibleWorks(後更名為 Ansible, Inc.)。
在商業模式上,Ansible 採用 Open Core 策略:自動化引擎完全開源(GPLv3,始終未改授權);提供權限管控(RBAC)、操作稽核與排程介面的 Web 管理平台 Ansible Tower 則採商業閉源,後來才以 AWX 專案的形式開源。
工程師日常使用的 CLI 工具與模組全部免費開源;會付費買單的,則是需要治理與合規紀錄的中大型企業。
2013 年 8 月,公司完成了由 Menlo Ventures 領投的 600 萬美元 A 輪融資。在整個生命週期中,Ansible 僅募集了這一筆資金。相較於大量燒錢行銷的競爭對手,Ansible 靠的是容易導入帶來的自然成長。
2015 年 10 月 16 日,Red Hat 宣布收購 Ansible, Inc.。媒體報導收購金額介於 1 億至 1.5 億美元之間。換算下來,收購金額是總融資的 16 倍以上。
創作者離場:模組失控、三年非競業與 JetPorch
然而在專案進入商業巔峰之際,DeHaan 於 2015 年初選擇離開了公司與專案。
離職後,他簽署了為期三年的非競業條款,自 2015 至 2018 年間被排除在系統自動化領域之外。而這三年,正是 Docker 容器化、Kubernetes 與現代 CI/CD 重塑基礎設施生態的關鍵時期。
在後續的訪談中,DeHaan 毫不避諱地表達了他對專案演進方向的失望:
「我離開的時候大概有 400 個模組左右。實際上應該要更少才對。我們本來可以維持住……但它往太多方向長,沒辦法保持專注。」
更直白的批評則指向程式碼品質與工具定位:
「這很棘手。我說過很多次了,我所有其他專案的程式碼,整體來說都比那一個好。」
「它本來應該是『這是我要裝的套件清單,這是我要複製過去的檔案清單』。(使用者寫出來的那些東西)不是我想要的方向。」
模組數量的失控並非偶然。從 2015 年的 400 個,到 2.9 版爆增至 3,908 個,背後是商業生態系擴張的必然結果。每一家雲端供應商或硬體廠商都想將自己的模組塞進核心儲存庫,導致冷門模組與核心模組綁在同一套版本發布流程中。
官方早期嘗試分拆儲存庫都沒有成功,直到多年後才推動 Collections 架構,把模組拆成可以各自發布的獨立套件。
非競業期滿後,DeHaan 曾於 2023 年 7 月發起名為 JetPorch 的全新開源專案。他選用 Rust 重寫底層引擎以提升效能,但介面依然選擇了 YAML 方言。
然而時代早已改變。2023 年 12 月下旬,DeHaan 宣布終止 JetPorch 開發。2012 年那種得靠 SSH 逐台設定實體機器的痛點已大幅減少,雲端原生與容器化接手了這塊需求。DeHaan 帶著更成熟的工程設計回歸,卻發現戰場早已轉移。
賭注的帳單:SSH 效能天花板與被扭曲的 YAML
Agentless 與 YAML 在早期替 Ansible 壓低了上手門檻,但隨著管理的機器越來越多、自動化邏輯越來越複雜,兩者分別帶來了效能與可維護性的代價。
第一筆帳單,是無常駐 agent 導致的連線效能天花板。
Ansible 預設的執行模型是「逐任務、逐主機」依序執行(Per-Task, Per-Host Loop)。
每執行一個任務,控制端就要把模組程式碼打包、傳到遠端主機的暫存目錄,呼叫遠端 Python 執行,取回 JSON 結果後再刪掉暫存檔。
Ansible Default Task Loop (Per Host, Per Task):
+----------+-->+---------------+-->+---------+-->+-------+
| SSH Conn |-->| Transfer Code |-->| Execute |-->| Clean |
+----------+-->+---------------+-->+---------+-->+-------+
^ |
+------ Next Task Loop -------------------------+
根據效能最佳化工具 Mitogen 的量化分析,光是遠端啟動 Python 行程與模組載入(import),每個 playbook 步驟就要多耗費 300 至 800 毫秒,這還不包括建立 SSH 連線的成本;一份 100 個任務的 playbook,光是這些額外開銷就要 30 至 80 秒。
更麻煩的是,為了相容部分 Linux 發行版的預設 sudo 設定,Ansible 預設關閉了 Pipelining(把程式直接經由連線交給遠端執行、不寫入暫存檔的加速機制),並把同時處理的主機數(forks)保守設為 5。叢集規模一到數百台,這套機制就會碰到明顯的效能天花板。
官方曾嘗試在遠端臨時啟動背景行程(如 fireball 與 accelerate 模式)來加速,但因違背「被管理端不留 daemon」的 agentless 承諾而悉數廢棄。
這促成了第三方外掛 Mitogen 的興起——Mitogen 透過在目標機器記憶體中維持持久的 Python 直譯器,宣稱能帶來 1.25 至 7 倍的速度提升。但一個核心工具必須仰賴第三方外掛修改內部執行機制才能跑得快,恰恰印證了其底層架構模型的固有極限。
第二筆帳單,則是將設定用的標記語言強行推成程式語言。
YAML 原本只適合表達單純的資料結構。但隨著維運邏輯日益複雜,條件判斷(when)、迴圈(loop)、例外捕捉(block/rescue)與變數指派(register)被硬塞進 YAML 欄位,運算式則全數依賴 Jinja2 模板字串:
- name: 複雜邏輯在 YAML 與 Jinja2 之間的拼貼
ansible.builtin.shell: /usr/local/bin/deploy.sh
register: deploy_result
loop: "{{ target_services | selectattr('enabled') | map(attribute='name') | list }}"
when:
- inventory_hostname in groups['production']
- deploy_result.rc is not defined or deploy_result.rc == 0
failed_when: "'CRITICAL' in deploy_result.stderr"
同一段設定混用兩種語法,出錯時也分屬兩套系統:縮排寫錯,得到的是 YAML 解析失敗;邏輯寫錯,得到的是 Jinja2 變數未定義。再加上沒有型別系統、沒有原生除錯器,IDE 也難以做精確的靜態分析。
DeHaan 自己也說過:
「它看起來像一門糟糕的程式語言,因為它從來就不該是一門程式語言。」
即便如此,以純 Python 撰寫設定的同類工具 pyinfra 雖然邏輯更嚴謹,GitHub 星數卻只有 Ansible 的零頭。可見在普及度上,低上手門檻比程式語言的表達力更具決定性。
結語:低門檻的勝利與代價
Ansible 的上半場,是「低認知負擔」勝過「複雜架構」。免裝 agent 的設計與好上手的 YAML,正好回應了 2010 年代初維運人員對 PKI 憑證與專用 DSL 的厭倦,也讓 Ansible 以一輪融資就走到被收購。
然而,將組態宣告硬推為程式邏輯、以臨時 SSH 承載大規模任務的妥協,也為日後的擴充性埋下了技術債。
下篇將探討:當 Terraform 轉向不可變基礎設施、Kubernetes 取代長期運作的伺服器,以及 Ansible 自身經歷 Collections 大拆分之後,Ansible 如何在現代雲端原生生態中重新定位自己。