1. 程式人生 > >寫了 30 萬行基礎設施程式碼後,我們得出 5 個有用的經驗

寫了 30 萬行基礎設施程式碼後,我們得出 5 個有用的經驗

在 Gruntwork,我們建立並維護著一個包含 30 萬行基礎設施程式碼的庫,有數百家公司在他們的生產環境中使用這個庫。在這篇文章中,我將分享我們在開發和維護這個庫的實踐過程中學到的非常重要的五課。

1 處於石器時代的 DevOps


雖然這個行業充斥著各種前沿的流行語——Kubernetes、微服務、服務網格、不可變基礎設施、大資料、資料湖,等等——但實際情況是,當你在構建基礎設施並陷入困境時,它們看起來一點都不前沿。

對我來說,DevOps 感覺更像這樣:

構建生產級的基礎設施其實很難,壓力很大,而且非常耗時。

根據我們在與數百家不同公司合作時收集的經驗資料,你大致可以估計你的下一個基礎設施專案需要多長時間:

 

2 第 1 課:生產級基礎設施檢查清單


DevOps 專案總是比預期的要長,為什麼會這樣?

第一個原因是 Yak Shaving(給犛牛擼毛),那麼什麼是 Yak Shaving?看看這個場景你就明白了:

經理:你不是在開發使用者登入功能嗎?為什麼現在在搗鼓一個我們根本用不到的資料庫?

工程師:是啊,我是打算開發使用者登入功能。然後我開始評估要用哪個庫,我發現一個非常好的庫,但它只支援 Postgres。於是我試著搭建一個 Postgres,看看值不值得這樣做。但切換資料庫會破壞索引,所以我現在在學習如何建立 Postgres 索引……這樣才能把使用者登入功能做出來,對吧?

第二個原因是構建生產級的基礎設施涉及了太多的細節。絕大多數開發人員並不知道這些細節,因此,當你在估算專案時,你通常會忘記關鍵和耗時的細節。

為避免這個問題,每次你開始使用新的基礎設施時,請檢查以下清單:

並非每個基礎設施都需要檢查清單中的每個專案,但你應該有意識地記錄你已實現的專案、決定跳過的專案以及相應的原因。

 

3 第 2 課:工具集


截至 2018 年,以下是我們在 Gruntwork 中用於構建和管理基礎設施的主要工具:

  • Terraform:我們使用 Terraform 來配置所有的基礎設施,包括網路、負載均衡器、資料庫、使用者、許可權以及我們所有的伺服器。

  • Packer:我們使用 Packer 來定義和構建在伺服器上執行的虛擬機器映象。

  • Docker:我們的一些伺服器組成了叢集,上面執行著託管應用程式作的 Docker 容器。我們使用的主要 Docker 叢集工具是 Kubernetes、ECS 和 Fargate。

現在,所有這些工具都很有用,但這不是重點。重點是,光是有這些工具還不夠,你還需要改變團隊的行為。

特別是,如果你的團隊不信賴這些工具,或者你的團隊沒有足夠的時間學習使用這些工具,那麼即使是世界上最好的工具都無法為你的團隊帶來任何幫助。因此,關鍵的一點是,基礎設施即程式碼是一項投資:需要前期預付成本,但如果你明智地進行投資,將獲得長期的巨大好處。

 

4第 3 課:大模組是有害的


基礎設施即程式碼新手通常在單個檔案或作為一個單元進行部署的一組檔案中定義所有環境(dev、stage、prod 等)的所有基礎設施。這是一種糟糕的做法。

以下是這種做法的一些缺點:

  1. 速度慢:如果你的所有基礎設施都在同一個地方定義,那麼執行任何命令都需要很長時間。我們已經看到公司的 terraform plan 需要 5-6 分鐘才能執行完畢!

  2. 不安全:如果你的所有基礎設施都是一起管理的,那麼在更改內容時都需要可以訪問所有內容的許可權。這意味著幾乎每個使用者都必須是管理員。

  3. 風險:如果所有雞蛋都在一個籃子裡,那麼任意一個錯誤都可能會破壞整個系統。你可能正在對 dev 中的前端應用程式進行微小更改,但由於輸入錯誤或運行了錯誤的命令,可能把生產資料庫給刪掉了。

  4. 難以理解:在一個地方擁有的程式碼越多,人們理解它們的難度就越大。如果將它們捆綁在一起,你不理解的部分可能會影響到你。

  5. 難以測試:測試基礎設施程式碼很難,測試大量基礎設施程式碼幾乎是不可能的。

  6. 難以評審:諸如 terraform plan 之類的命令的輸出變得毫無用處,因為沒有人想要檢視數千行輸出。程式碼評審也變得毫無用處。

你應該使用小型、獨立、可重用、可組合的模組來構建程式碼。這不是什麼有爭議的新觀點。你之前可能已經聽過無數次了:

“一次做一件事,並把它做好”——Unix 哲學。

“函式的第一條規則是它們應該很小。函式的第二個規則是它們應該比小更小。”——《整潔程式碼之道》

 

5 第 4 課:沒有自動化測試的基礎設施程式碼太脆弱


如果你的基礎設施程式碼沒有經過自動化測試就很容易出問題。你只是不知道一些暗藏的問題。也就是說,測試基礎設施程式碼很難。你沒有“localhost”(例如,你無法在膝上型電腦上部署 AWS VPC),也沒有“單元測試”(例如,你無法將“Terraform”程式碼與“外部”隔離開來,因為 Terraform 所做的事情就是與外界互動)。

因此,要正確測試你的基礎設施程式碼,通常需要將程式碼部署到真實環境,執行真實的基礎設施,驗證它們做它們該做的事情(對於這種測試方式,請參考 Terratest,一個開源庫,包括用於測試 Terraform、Packer 和 Docker 程式碼的工具)。因此,對於基礎設施測試,你必須重新定義一些術語:

  • 單元測試是指部署和測試來自一種基礎設施的一個或少量密切相關的模組(例如,測試單個數據庫模組)。

  • 整合測試是指部署和測試來自不同型別的基礎設施的多個模組,以驗證它們是否能夠正常協同工作(例如,測試 Web 服務模組和資料庫模組)。

  • 端到端測試是指部署並測試整個架構。

這張圖是一個金字塔,我們有很多單元測試、較少數量的整合測試和極少數的端到端測試。為什麼?這是由每種型別的測試所需要的時間來決定的:

基礎設施測試的週期時間很慢,特別是金字塔越往上就越慢,所以你會想盡可能多地在金字塔底層捕捉到錯誤。這意味著你應該:

  1. 構建小巧、簡單的獨立模組,併為它們編寫大量單元測試。

  2. 將這些小型、簡單、經過實戰檢驗的構建塊組合在一起,建立更復雜的基礎設施,並進行少量的整合和端到端測試。

6第 5 課:釋出過程

現在讓我們把這一切都放在一起。以下是你從現在開始應該採用的構建和管理基礎設施的方法:

  • 對照生產級基礎設施檢查清單,確保你正在構建正確的東西。

  • 使用 Terraform、Packer 和 Docker 等工具將你的基礎設施定義為程式碼。確保你的團隊有時間掌握這些工具。

  • 使用小型、獨立、可組合的模組構建程式碼(或使用基礎設施中的現成模組作為程式碼庫)。

  • 使用 Terratest 為你的模組編寫自動化測試。

  • 提交拉取請求,讓別人來評審你的程式碼。

  • 釋出新版本程式碼。

  • 將你的程式碼從一個環境推到另一個環境。

 

英文原文

https://blog.gruntwork.io/5-lessons-learned-from-writing-over-300-000-lines-of-infrastructure-code-36ba7fadeac1