程序員如何用代碼徹底終結系統那些事兒?

互聯網發展至今,瞬息萬變的市場要求我們的產品具有更快的響應速度。技術的快速進步,軟件的快速迭代升級,各種軟件基礎設施也不得不隨之進行頻繁的修改。爲更好地適應各各式各樣各樣的需求,將基礎設施、工具、服務以及對基礎設施的管理作爲一個軟件系統,使用軟件工程實踐中的方式來處理各種基礎設施的變化。本文作者在文中詳細講解了軟件設施代碼背後的思想,帶領我們詳細瞭解背後的原理。

作者 | Tylor Borgeson,已獲作者翻譯授權
譯者 | 羅昭成
原文 | What shape is your software infrastructure?
本文首發於 CSDN 微信(ID:CSDNnews)

1. 寫在前面

這是我「流行軟件開發實踐」系列文章中的第六部分,在本系列文章中,我計劃包含軟件工程師通過提升開發流程和實踐來改善軟件開發的一系列方法。我曾在 ThoughtWorks 擔任軟件顧問,現在我在德國一家大型的零售公司工作,這些方法都是我在職業生涯中學習並實踐驗證過的。

我們從小就知道,三角形具有穩定性,當今社會,衆多建築物(如大橋)都使用了這個基礎的結構,來保證建築物的穩定性。

我在 ThoughtWorks 任職期間,我花費了大量的時間來幫助他們處理基礎設施的問題,增強他們基礎設施的穩定性。包括如何將他們”圓形“的基礎設施改成”三角形“ 的基礎設施。

改善基礎設施有很多步驟,這個會和公司當前的基礎設施進行結合,進行調整,但不管最終需要做哪些事情,都有一個都是必須要做的,那就是基礎設施代碼化。

2. 什麼是基礎設施代碼化?

基礎設施代碼化是一種實踐,它處理了基礎架構團隊所面臨的許多挑戰。它關注於使用配置來管理可配置的系統。

我們的軟件可以隨時根據需求,隨時進行變更與修改。那我們的基礎設施是否也可以這樣進行靈活的擴展和升級?基礎設施代碼化的想法正是來源於此。現在,最常見的實現方式是用代碼來控制服務器、雲實例、管道、以及”擴展基礎設施“的接口,在需要的時候,通過代碼來實現更改,不在通過用戶界面進行配置。當然,實現自動化更改之前,都必須經過必要的檢查和驗證。

因爲基礎設施資源由代碼定義,在軟件開發中使用的那些工具(CI/CD, TDD),也能很好地在這上面使用,使系統受益。

基礎設施代碼化致力於實現以下目標:

  • 隨着公司增長,業務變大,基礎設施不會成爲短板;

  • 像軟件升級一樣,基礎設施的更改或升級能夠非常地容易;

  • 冗餘的自動化任務和基礎任務由公司/部門的基礎架構團隊負責;

  • 基礎設施的使用者可以簡單的進行修改並應用於他們的基礎設施;

  • 團隊在基礎設施上的故障恢復時間大大地降低。

3. 基礎設施代碼化的挑戰

  • 服務器與配置不一致

越來越多的團隊將他們的應用遷移到雲上,並在虛擬機中進行運行。團隊頻繁增加服務器的可能性正在增加。這就意味着,我們需要保證所有的機器都運行最新版本的程序,並在相互之間保持一致。不一致的問題會越來越頻繁的給我們帶來問題。如果不同的機器之間出現了不同,那麼就可能會出現同一個腳本在不同的機器上,跑出不同的結果。

想像一下,我們軟件的更新,只在某一臺機器上能夠正常運行。在負載均衡的情況下,只有”非常幸運“的用戶才能將請求落在那臺正常運行的服務器上。

  • 雪花機

因爲雪花是不能被複制,所以沒有任何兩個雪花是相同的。因此我們認爲每一片雪花都是獨特的。在基礎設施上也存在這個問題。

許多系統管理員都嘗試手動檢查來糾正配置不一致的服務器。這樣做帶來的後果是一些針對特定問題的特定更新,並不能留下歷史記錄(當然,有時候,在雲服務器上也是有歷史記錄的。但是,在問題解決之前,還有 100 條是記錄的之前的操作,那麼這個歷史記錄也沒有太大的用處),只有更新服務器的人,才知道服務器更新了什麼東西。所以,有些時候,軟件能正確運行,有些時候,又無法正確的運行,像魔術一樣,很難解釋清楚原因。

這些問題都不是故意造成的。但我們都是人,人都會犯錯。例如有時候我們更新了編號爲 1、2、3、4 的服務器,但因爲一些原因卻忘記了更新編號爲 5 的機器。

  • 不要動它

經過更改的服務器,最終能將軟件按照預期的運行起來,但是,它去像一個紙房子一樣,非常脆弱。所以,請”不要隨意地動它“。

我們很不願意對系統進行升級和改造,而自動化會讓系統管理員更加擔心。因爲他們不知道,這些更改,是否會造成服務器停止服務。

4. 基礎設施代碼化的原則

  • 可複製性

如果,你已經實現了基礎設施代碼化,能夠通過代碼配置來創建基礎設施;而不是通過 Amazon 的 Web 控制檯或者是 Jenkins 來創建。那麼你新建的步驟就簡單多了。所有的創建步驟都記錄在腳本中,任何步驟都不會被遺忘。

當一個其它團隊的同事諮詢你們是如何在 AWS 中配置 Kubernetes 集羣的自動擴展時,你不需要去控制檯找 3 個月前編輯的設置,相反,他們可以直接查看創建設置的代碼,甚至是直接將你們的代碼拷貝到他們的實例中去運行。

當你將你們的數據中心遷移到雲上,或者是從一個雲服務提供商遷移到另一個雲服務提供商時,創建資源的過程會重複多次,代碼化將會非常的有用。

  • 一次性

由於基礎設施的配置步驟是可以通過代碼的方式進行復制,所有不需要擔心由於機器損壞需要更換而帶來的維護成本。

雲服務的一個主要優點就是”動態的基礎設施“,它可以快速的移動、更新、創建、替換、調整大小甚至是刪除。你不需要擔心,在你刪除掉某臺機器而導致你漏掉某些你不知道的設置,我們可以充分利用動態的特性。

  • 一致性和適應性

在更新代碼的,如果我們是通過代碼而非 UI 控制檯來配置基礎設施,那麼使用代碼創建的所有基礎設施也會被同步更新。

這就意味着,我們所有的基礎設施(如服務器)都能夠保持一致,就像是精確的副本一樣。我們無法預測到,隨着軟件的增長和變化,基礎設施將要如何變化。我們能做的是,就是儘可能的積極的、快速的升級更改我們的系統。

當基礎設施代碼化,每一個小的更改都可以用過持續集成的方式進行應用。通過每一個小的更改來提高系統的彈性。

5. 如何開始?

  • 定義文件

要實現基礎設施代碼化,你需要將你所有的基礎設施配置轉換成配置文件,用代碼進行定義。這些定義文件將作爲你基礎設施的真實來源。

推薦一個有用的工具:Terraform

Terraform 可以使用 HCL(Hashicorp 配置語言)定義和配置你的基礎設施。可以像在 UI 控制檯中使用的關鍵字和變量那樣,提供各種資源。在運行代碼時, 將以編程方式供應代碼中定義的資源。

Terraform 設計中最棒的部分在於,它也可以對已經存在的資源進行編碼管理。下面是一個在 Microsoft Azure 中配置 Linux 並分配虛擬網絡的例子:

resource "azurerm_resource_group" "main" {
  name     = "${var.prefix}-resources"
  location = var.location
}

resource "azurerm_virtual_network" "main" {
  name                = "${var.prefix}-network"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
}

resource "azurerm_subnet" "internal" {
  name                 = "internal"
  resource_group_name  = azurerm_resource_group.main.name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefix       = "10.0.2.0/24"
}

resource "azurerm_network_interface" "main" {
  name                = "${var.prefix}-nic"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.internal.id
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_linux_virtual_machine" "main" {
  name                            = "${var.prefix}-vm"
  resource_group_name             = azurerm_resource_group.main.name
  location                        = azurerm_resource_group.main.location
  size                            = "Standard_F2"
  admin_username                  = "adminuser"
  admin_password                  = "P@ssw0rd1234!"
  disable_password_authentication = false
  network_interface_ids = [
    azurerm_network_interface.main.id,
  ]

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "16.04-LTS"
    version   = "latest"
  }

  os_disk {
    storage_account_type = "Standard_LRS"
    caching              = "ReadWrite"
  }
}
  • 版本控制

一但你的資源在代碼中進行了定義,你的基礎設施也將受到版本管理帶來的好處。

歷史記錄將會被保存下來,是誰在什麼時候更新了它,這些都將變得有據可查。當出現問題,需要調試甚至是回滾時,這些信息能夠提供非常大的幫助。

我們還能從版本記錄中看到更改的日誌,輕鬆的看到已經更改的內容。當提交被更新到代碼庫中時,我們可以觸發一些編譯任務或一些自定義事件,這讓基礎設施在 CI/CD 中進行測試變成可能。

需要記住的是,與其它代碼一樣,儘可能小的提交更改。小的更改比大的更改具有更多的好處。較小的更改更容易測試和調試,並且容易修復問題。在基礎設施中進行的修改與之相同。

6. 工具推薦

  • Terraform

如上面的描述,Terraform 是一個好用的工具,它可以用於各種基礎設施的定義、管理及部署。在它的官網上是如下描述的:

Terraform 是一種用於安全,高效地構建、更改和版本化基礎設施的工具。Terraform 可以管理現有流行的服務提供商以及定製的內部解決方案。配置文件向 Terraform 描述了運行單個應用程序或整個數據中心所需的組件。Terraform 將生成一個能夠達到描述中預期狀態的執行計劃,然後執行該計劃,以構建描述中基礎設施。隨着配置文件的更改,Terraform 能夠確定更改的內容並創建可以執行的增量執行計劃。

  • Packer

Packer 也是基於 Hashicorp 的工具,它允許快速自動創建機器鏡像。過去創建鏡像通常是通過創建虛擬機,手動配置(安裝所需的軟件包和依賴項)然後複製這個虛擬機來完成的。現在可以單個文件來定義該鏡像,並通過 Packer 程序進行構建。它甚至可以使用 Chef 和 Puppet 這類的工具將應用安裝到鏡像上。

  • Concourse

一個具有用戶界面的構建管道,但用戶只能在上面查看狀態和日誌。整個管道必須通過配置文件進行配置。我認爲它是市場上最酷的管道工具之一,並且它是開源的

  • 其它

如果你想了解有關基礎設施代碼化的更多細節,我強烈建議閱讀以下內容:

https://www.hashicorp.com/resources/what-is-infrastructure-as-code — Hashicorp

https://docs.microsoft.com/en-us/azure/devops/learn/what-is-infrastructure-as-code — Microsoft

https://www.thoughtworks.com/de/insights/blog/infrastructure-code-reason-smile — Thoughtworks

7. 寫在最後

本文僅涉及基礎設施代碼化背後的思想。如果您還有其他問題和意見,請隨時與我聯繫!感謝您的閱讀!

8. 系列閱讀

1. 爲什麼持續集成和部署在開發中非常重要?

2. 被高估了的測試驅動開發?

3. 爲什麼程序員如此“嫌棄”主幹開發模式?

4. 程序員爲什麼千萬不要瞎努力?

5. 爲什麼許多程序員討厭結對編程?

6. 程序員如何用代碼徹底終結系統那些事兒?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章