前天我的文章〈CI 是條不歸路〉提到:「CI/CD/DevOps 既是條不歸路,更是大躍進之路:一旦踏出第一步,就注定你會不斷接觸『遠離平庸』的新觀點、新技術。」

為了避免陳義過高,這篇文章就來講一個具體的軟體研發故事吧。

護城河

我用 Ansible,也用 Prometheus,因此,我寫了一個 Ansible role williamyeh.prometheus 來安裝 Prometheus。

上個禮拜,我隱約覺得對它感興趣的人似乎變多了,便好奇的去 GitHub 後台調數據來看,發現:

原來是被 Prometheus 官網列入 “Using configuration management systems” 清單了,難怪最近 PR 變多,品質更是超越其他幾家 CM 的例子。

— Quote: 2015-12-16 Tweet

被 Prometheus 官方欽點了,能見度提高了,就表示,三不五時會有人提出 bug report,提出 feature request;甚至更勤勞一點的,可能直接就會送出 PR (pull request)。

面對 PR,其實要花很大的力氣去檢驗:檢驗對錯,檢驗風格,甚至 conceptual integrity(語出《人月神話》)。而且,對方既然已經很勤勞的送出 PR 了,他會預期你高度重視他的提案。

我需要一道護城河,讓我不必每次都事必躬親,回應每一則 PR。

所幸我早就建立好個人的 discipline:要替自己寫的 Ansible role 加上 CI。即使只是做一點點小小的 smoke test,總是聊勝於無。

CI 是高度客觀中立不帶感情的守門員。它,幫我初步過濾一些攸關對錯、風格的 PR。於是,我可以優先禮貌性回應已經被 CI 初步打勾放行的 PR;至於被打叉叉的,那就謝謝再聯絡等有充裕時間精力時再說:

Pull requests

Pull requests

CI,小小的投資,大大的省事。

當 Ansible 遇見 Docker

個人還有另一項執念:自己寫的 Ansible role,要盡可能支援多種 Linux distributions 環境。

這又是一條不歸路。

在本機端研發時,我可以用各種 Vagrant box 來模擬各種 Linux (譬如:bento/centos-6.7bento/centos-7.1debian/jessie64),但這沒辦法 scale 到正式的 CI 流程上。此刻 Travis CI 及 CircleCI 只提供 Ubuntu 12.04 及 14.04 兩種 instance,也沒支援 Test Kitchen

所幸 Travis CI 和 CircleCI 都有支援 Docker,因此,我設計了 williamyeh/ansible 這一系列的 Docker images,可在 Travis CI 及 CircleCI 上面模擬出 CentOS 6 & 7、Debian 7 & 8、Ubuntu 12.04 & 14.04 環境,來測試我的 Ansible roles。

這下子,我的 CI 護城河就更穩固了。CI 這位高度客觀中立不帶感情的守門員,協助我冷靜面對以下這則算是大工程等級的 PR,不帶批判情緒的進行對話,一起搞定 CentOS/Ubuntu 雙系統:

Discussion around a pull request

Discussion around a pull request

CI,小小的投資,大大的省事。

對我而言,原本 williamyeh/ansible 只是為了其他目的而順帶設計出來的副產品。但由於 Ansible 官方已不再維護它的 Docker images;而在非官方版當中,我的 williamyeh/ansible 下載量居冠(統計數據在此),也持續有人提出 feature request⋯⋯該說是無心插柳嗎?

吃自己的狗食

再拿另一個很受歡迎的 Ansible role:williamyeh.oracle-java 為例。它在 Ansible Galaxy 已經得到 4.8 的高分,是一個已經為人所知,甚至為人所用的元件。

因此,我必須維持良好的向後相容性,以對用戶負責。

也因此,連我自己想對原始程式做更動,也不敢貿然造次。必須遵守 Git FlowGitHub Flow 之類的 workflow discipline,一樣要看 CI 這位高度客觀中立不帶感情的守門員的臉色。

Network graph

Network graph

專業,就是對自己也有 discipline。CI,就是強制幫助你建立 discipline

不要輕看 CI 的紅燈

對這個 Ansible role,有一點我一直耿耿於懷:Travis CI 和 CircleCI 的測試結果,時好時壞。

像以下截圖顯示,同樣都是針對 6598bed 這個 commit,Travis CI 一次就通過,但 CircleCI 居然會出現一堆紅燈。不死心的我,一直按 rebuild 好幾次,總算才出現綠燈:

奇怪的是,同樣都是針對 a9c105e 這個 commit,這回 CircleCI 一次就通過,反倒是 Travis CI 出狀況:

前幾天,我終於忍不住出手。

反覆比對兩邊的 log,發現,Oracle 疑似會對 jdk 下載點做 rate limiting。每次 Travis CI 及 CircleCI 的 CI 大隊一啟動,Oracle 就惱了。

所以,不是我的 Ansible role 有問題,是 Oracle 太神經兮兮了。

怪罪 Oracle 於事無補,問題總得解決⋯⋯

為了解決這問題,我設計一個 prefetch 機制:只向 Oracle 抓一次需要的 rpm 及 tar.gz 檔案,存放在 role 的 files 目錄裡面。如此一來,不僅避開 rate limiting 的限制,連帶的也降低整體的 build time,更讓整個 role 架構 refactor 得更乾淨。

CI,小小的投資,大大的省事。

卻顧所來徑

這一切的一切,濫觴都只是一個小起步:要替自己寫的 Ansible role 加上 CI。

一旦踏出第一步,就注定你會不斷接觸『遠離平庸』的新觀點、新技術。

你同意嗎?