基礎設施程式碼化:超越傳統檔案的實踐

在現代雲端環境中,基礎設施程式碼化(Infrastructure as Code,IaC)已成為管理複雜系統的關鍵策略。這種方法不僅改變了我們建置和維護基礎設施的方式,也徹底轉變了檔案管理的概念。

程式碼作為檔案的優勢

傳統檔案的最大問題在於維護的困難性。隨著系統變更,檔案往往無法及時更新,導致資訊過時。相比之下,基礎設施程式碼本身就是一種永遠保持最新與準確的檔案形式,具有以下優點:

  • 新進人員學習工具:新團隊成員可以直接瀏覽程式碼,快速瞭解系統架構和運作方式
  • 團隊協作與知識分享:團隊成員可以閱讀程式碼和檢視提交記錄,瞭解他人的工作內容
  • 技術審查的基礎:技術審查人員可以透過程式碼評估需要改進的地方
  • 稽核的可靠依據:稽核人員可以檢視程式碼和版本歷史,獲得系統的準確影像

然而,基礎設施程式碼通常不是唯一需要的檔案。高階檔案對於提供背景和策略仍然很有價值。某些利害關係人可能需要了解系統的特定方面,但不熟悉技術堆積積疊。

檔案即程式碼的實踐

許多團隊選擇將其他型別的檔案也以程式碼方式管理:

架構決策記錄 (ADR-001)

標題:採用微服務架構

日期:2025-01-15

狀態:已接受

背景

我們的單體應用程式面臨擴充套件性挑戰…

決策

我們決定採用微服務架構,將系統拆分為獨立服務…

後果

這將提高系統的可擴充套件性,但增加了網路複雜性…


這種方法將架構決策記錄(ADRs)以標記語言編寫,並儲存在版本控制系統中。更進一步,還可以從程式碼自動生成有用的資料,如架構圖和引數參考。這些可以放入變更管理管道中,每當有人對程式碼進行變更時自動更新檔案。

## 基礎設施堆積積疊的核心概念

基礎設施堆積積疊(Infrastructure Stack)是一組基礎設施資源的集合,這些資源被定義、佈建和更新為一個單元。理解堆積積疊的概念對於有效管理雲端資源至關重要。

### 堆積積疊的定義與組成

堆積積疊是透過程式碼定義的,這些程式碼宣告了堆積積疊應包含的基礎設施元素。這些元素是由基礎設施平台提供的資源和服務,例如:

- 虛擬機器(計算資源)
- 磁碟卷(儲存資源)
- 子網路(網路資源)

當執行堆積積疊管理工具時,它會讀取堆積積疊程式碼,並使用雲端平台的API來組裝程式碼中定義的元素,從而佈建堆積積疊的例項。

#### 常見的堆積積疊管理工具

市場上有多種堆積積疊管理工具可供選擇:

- HashiCorp Terraform
- AWS CloudFormation
- Azure Resource Manager
- Google Cloud Deployment Manager
- OpenStack Heat
- Pulumi
- Bosh

某些伺服器設定工具也有擴充套件功能可以處理基礎設施堆積積疊,例如Ansible Cloud Modules、Chef Provisioning(現已停止支援)、Puppet Cloud Management和Salt Cloud。

### 堆積積疊程式碼與例項

每個堆積積疊都由宣告基礎設施元素的程式碼定義。例如,Terraform程式碼(.tf檔案)和CloudFormation範本都是基礎設施堆積積疊程式碼的例子。堆積積疊專案包含定義堆積積疊基礎設施的程式碼。

以下是一個使用虛構工具Stackmaker的堆積積疊程式碼專案的資料夾結構:

stack-project/ ├── src/ │ ├── dns.infra │ ├── load_balancers.infra │ ├── networking.infra │ └── webserver.infra └── test/


#### 堆積積疊例項的生命週期

單一堆積積疊專案可以佈建多個堆積積疊例項。當為專案執行堆積積疊工具時,它使用平台API確保堆積積疊例項存在,並使其與專案程式碼比對:

1. 如果堆積積疊例項不存在,工具會建立它
2. 如果堆積積疊例項存在但與程式碼不完全比對,工具會修改例項使其比對
3. 如果再次執行工具而未對程式碼進行任何更改,它應該保持堆積積疊例項不變

這個過程通常被描述為將程式碼「應用」到例項。

### 在堆積積疊中設定伺服器

對於非完全容器化或無伺服器應用程式架構的系統,基礎設施程式碼通常包含大量用於佈建和設定伺服器的程式碼。即使是容器化系統也需要建置主機伺服器來執行容器。

最好將建置伺服器的程式碼與建置堆積積疊的程式碼解耦。這樣做可以使程式碼更容易理解,透過解耦簡化變更,並支援伺服器程式碼的重用和測試。

以下是一個堆積積疊定義呼叫虛構的servermaker工具來設定伺服器的例子

```yaml
virtual_machine:
  name: appserver-waterworks-${environment}
  source_image: shopspinner-base-appserver
  memory: 4GB
  provision:
    tool: servermaker
    parameters:
      maker_server: maker.shopspinner.xyz
      role: appserver
      environment: ${environment}

這個堆積積疊定義了一個應用程式伺服器例項,從名為shopspinner-appserver的伺服器映像建立,具有4GB的RAM。定義包括一個觸發執行Servermaker的佈建過程的子句。程式碼還傳遞了Servermaker工具使用的幾個引數,包括設定伺服器的地址、角色和環境名稱。

基礎設施語言的層次與選擇

基礎設施程式碼可以使用不同層次的語言來表達,這些語言在抽象程度和靈活性上有所不同。選擇適合的語言層次對於建立有效的基礎設施至關重要。

低階基礎設施語言

大多數流行的堆積積疊管理工具語言都是低階基礎設施語言。這意味著語言直接暴露了基礎設施平台提供的資源。作為基礎設施程式設計師,你的工作是編寫將這些資源連線在一起的程式碼,使其變得有用。

以下是低階基礎設施堆積積疊程式碼的例子:

address_block:
  name: application_network_tier
  address_range: 10.1.0.0/24"
  vlans:
    - appserver_vlan_A
      address_range: 10.1.0.0/16

virtual_machine:
  name: shopspinner_appserver_A
  vlan: application_network_tier.appserver_vlan_A

gateway:
  name: public_internet_gateway
  address_block: application_network_tier

inbound_route:
  gateway: public_internet_gateway
  public_ip: 192.168.99.99
  incoming_port: 443
  destination:
    virtual_machine: shopspinner_appserver_A
    port: 8443

這個簡化的偽程式碼定義了一個虛擬機器、一個地址區塊和VLAN,以及一個網際網路閘道。然後它將它們連線在一起,並定義了一個入站連線,將進入https://192.168.99.99的連線路由到虛擬機器上的8443連線埠。

高階基礎設施語言

高階基礎設施語言定義的實體不直接對映到底層平台提供的資源。例如,上述低階程式碼的高階版本可能只需宣告應用程式伺服器的基本訊息:

application_server:
  public_ip: 192.168.99.99

在這個例子中,應用程式碼時,工具會佈建前面例子中的網路和伺服器資源,或者發現有資源來使用。呼叫此程式碼的工具或函式庫決定網路連線埠和VLAN的值,以及如何建置虛擬伺服器。

許多應用程式託管解決方案,如PaaS平台或封裝叢集,提供這種抽象層次。你為應用程式編寫佈署描述符,平台分配基礎設施資源來佈署它。

在其他情況下,你可以透過編寫函式庫或模組來建立自己的抽象層。

堆積積疊結構的模式與反模式

基礎設施設計的一個挑戰是決定如何調整和結構化堆積積疊。你可以建立單一堆積積疊程式碼專案來管理整個系統,但隨著系統增長,這變得難以處理。以下是結構化基礎設施堆積積疊的模式和反模式。

反模式:單體堆積積疊

單體堆積積疊是一個包含太多元素的基礎設施堆積積疊,使其難以維護。

應用程式執行層和基礎設施平台

應用程式執行層提供執行應用程式的環境。而應用程式層則是為你的組織和使用者提供價值的軟體。

這個模型有助於理解基礎設施即程式碼的範圍。基礎設施平台層是基礎,提供你組裝應用程式執行層所需的資源。應用程式執行層則是託管和執行你的應用程式的環境。

基礎設施即程式碼就是使用程式碼來定義、佈建和管理基礎設施平台和應用程式執行層。應用程式層通常使用應用程式佈署和交付工具與實踐來管理,這些不在本章的討論範圍內。

基礎設施平台

基礎設施平台提供你可用來建立應用程式執行環境的資源。這些平台包括:

  • 公有雲平台,如AWS、Azure、Google Cloud Platform (GCP)等
  • 私有雲平台,如OpenStack和VMware
  • 裸機基礎設施,包括實體伺服器、儲存和網路裝置

這些平台透過API提供基礎設施資源,你可以使用這些API以程式化方式佈建和管理資源。這就是使基礎設施即程式碼成為可能的關鍵。

基礎設施平台通常提供包含以下功能的管理階層:

  • 用於佈建和管理資源的API
  • 身分和存取管理
  • 監控和日誌記錄
  • 計費和成本管理
  • 安全控制

圖3-2顯示了基礎設施平台管理階層與其提供的基礎設施資源之間的關係。

  graph TD
    A[基礎設施平台管理階層] --> B[計算資源]
    A --> C[儲存資源]
    A --> D[網路資源]
    A --> E[其他基礎設施資源]
    
    subgraph "基礎設施資源"
    B
    C
    D
    E
    end

基礎設施平台管理階層提供讓你佈建和管理基礎設施資源的API和服務。這些資源是你用來建立應用程式執行環境的構建塊。

不同的基礎設施平台提供不同層級的抽象。一些平台,如裸機基礎設施,提供低層級的資源,需要更多工作來組裝成應用程式執行環境。其他平台,如公有雲,提供更高層級的抽象,使建立應用程式執行環境變得更容易。

例如,AWS提供了像Elastic Beanstalk和Lambda這樣的服務,模糊了基礎設施平台和應用程式執行層之間的界限。這些服務讓你可以佈署應用程式而無需明確佈建底層基礎設施資源。

選擇哪種基礎設施平台會影響你如何實施基礎設施即程式碼。不同平台有不同的API、資源模型和功能。不過,無論你選擇哪個平台,基礎設施即程式碼的原則和實踐都適用。

實施基礎設施即程式碼時,你會使用與基礎設施平台的API互動的工具來佈建和管理資源。這些工具包括:

  • 基礎設施佈建工具,如Terraform、AWS CloudFormation和Azure Resource Manager
  • 組態管理工具,如Ansible、Chef和Puppet
  • 容器協調工具,如Kubernetes和Docker Swarm
  • 無伺服器框架,如AWS SAM和Serverless Framework

這些工具讓你能夠將基礎設施定義為程式碼,你可以對其進行版本控制、測試和佈署,就像對應用程式碼一樣。

這些工具與基礎設施平台之間的關係如圖3-3所示。

  graph TD
    A[基礎設施即程式碼工具] --> B[基礎設施平台API]
    B --> C[基礎設施資源]
    
    subgraph "基礎設施平台"
    B
    C
    end

基礎設施即程式碼工具使用基礎設施平台的API來佈建和管理資源。你使用這些工具編寫的程式碼定義了基礎設施的期望狀態,而工具確保實際狀態與期望狀態相符。

基礎設施資源

基礎設施資源是你用來建立應用程式執行環境的構建塊。這些資源包括計算、儲存和網路資源,以及基礎設施平台提供的其他專門資源。

讓我們更詳細地探討每種基礎設施資源。

計算資源

計算資源為執行應用程式提供處理能力。這些資源包括:

  • 虛擬機器(VM)
  • 容器
  • 無伺服器函式
  • 實體伺服器

虛擬機器是雲端環境中最常見的計算資源。它們提供具有專用CPU、記憶體和儲存資源的虛擬化伺服器。VM可以執行各種作業系統和應用程式,使它們靈活適應不同的工作負載。

容器是輕量級、可移植的計算單元,封裝了應用程式及其依賴項。容器分享主機作業系統核心,使它們比VM更高效。像Kubernetes這樣的容器協調平台管理容器的佈署和擴充套件。

無伺服器函式是小型、事件驅動的計算資源,回應事件執行程式碼。無伺服器平台管理底層基礎設施,讓開發人員可以專注於編寫程式碼。例如AWS Lambda、Azure Functions和Google Cloud Functions。

實體伺服器是傳統的計算資源,為執行應用程式提供專用硬體。雖然在雲端環境中較不常見,但實體伺服器仍用於需要專用硬體或無法虛擬化的特定工作負載。

使用基礎設施即程式碼佈建計算資源時,你通常會定義:

  • 計算資源的型別和大小(例如,VM執行個體型別、容器大小)
  • 作業系統或執行環境
  • 網路設定
  • 儲存設定
  • 安全設定
  • 中繼資料和標籤

以下是使用Terraform定義虛擬機器的範例:

resource "aws_instance" "web_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  
  vpc_security_group_ids = [aws_security_group.web.id]
  subnet_id              = aws_subnet.public.id
  
  tags = {
    Name = "web-server"
    Environment = "production"
  }
}

這段程式碼定義了具有特定AMI(Amazon機器映像)、執行個體型別、安全群組和子網路的AWS EC2執行個體。該執行個體被標記了名稱和環境。

儲存資源

儲存資源為應用程式提供永續性資料儲存。這些資源包括:

  • 區塊儲存
  • 物件儲存
  • 檔案儲存
  • 資料函式庫儲存

區塊儲存提供可以連線到計算資源的原始儲存卷。區塊儲存類別似於傳統硬碟,通常用於作業系統儲存、資料函式庫儲存和其他需要低延遲資料存取的應用程式。例如AWS EBS、Azure Disk Storage和Google Persistent Disk。

物件儲存為非結構化資料提供可擴充套件、持久的儲存。物件儲存透過API存取,非常適合儲存大量不經常變更的資料,如備份、媒體檔案和靜態網站內容。例如AWS S3、Azure Blob Storage和Google Cloud Storage。

檔案儲存提供可以被多個計算資源掛載的分享檔案系統。檔案儲存對於需要傳統檔案系統介面和分享檔案存取的應用程式很有用。例如AWS EFS、Azure Files和Google Filestore。

資料函式庫儲存提供用於儲存和檢索結構化資料的受管資料函式庫服務。這些服務處理資料函式函式倉管理任務,如備份、修補和擴充套件。例如AWS RDS、Azure SQL Database和Google Cloud SQL。

使用基礎設施即程式碼佈建儲存資源時,你通常會定義:

  • 儲存資源的型別和大小
  • 效能特性(例如IOPS、吞吐量)
  • 複製和備份設定
  • 存取控制
  • 加密設定
  • 生命週期策略

以下是使用Terraform定義S3儲存桶的範例:

resource "aws_s3_bucket" "data_bucket" {
  bucket = "my-data-bucket"
  acl    = "private"
  
  versioning {
    enabled = true
  }
  
  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm = "AES256"
      }
    }
  }
  
  lifecycle_rule {
    id      = "archive"
    enabled = true
    
    transition {
      days          = 30
      storage_class = "STANDARD_IA"
    }
    
    transition {
      days          = 90
      storage_class = "GLACIER"
    }
  }
}

這段程式碼定義了一個啟用了版本控制、伺服器端加密的S3儲存桶,以及一個根據物件年齡將物件轉移到不同儲存類別的生命週期規則。

網路資源

網路資源提供計算資源之間以及與外部網路的連線。這些資源包括:

  • 虛擬網路
  • 子網路
  • 路由表
  • 負載平衡器
  • 防火牆和安全群組
  • DNS服務
  • 虛擬私人網路和直接連線服務

虛擬網路為你的資源提供隔離的網路環境。虛擬網路類別似於傳統實體網路,但是在軟體中實作。例如AWS VPC、Azure Virtual Network和Google VPC。

子網路是虛擬網路的細分,讓你能夠組織和保護你的資源。子網路可以是公共的(直接存取網際網路)或私有的(沒有直接存取網際網路)。

路由表定義了網路流量如何在網路內部和網路之間傳遞。路由表包含根據目的地確定網路流量傳送到哪裡的規則。

負載平衡器將網路流量分散到多個計算資源,以提高用性和可擴充套件性。負載平衡器可以在網路堆積積疊的不同層次運作,如應用層負載平衡器(第7層)和網路負載平衡器(第4層)。

防火牆和安全群組控制入站和出站網路流量以保護你的資源。安全群組是在例項級別運作的有狀態防火牆,而網路ACL是在子網級別運作的無狀態防火牆。

DNS服務將網域名稱轉換為IP位址,使用者能夠使用友好的名稱存取你的應用程式。例如AWS Route 53、Azure DNS和Google Cloud DNS。

虛擬私人網路和直接連線服務提供你的內部網路與雲端環境之間的安全連線。這些服務啟用混合雲架構和對雲端資源的安全存取。

使用基礎設施即程式碼佈建網路資源時,你通常會定義:

  • 你的虛擬網路和子網路的結構
  • 路由規則
  • 安全控制
  • 負載平衡設定
  • DNS記錄
  • 與外部網路的連線

以下是使用Terraform定義VPC和相關網路資源的範例:

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  
  tags = {
    Name = "main-vpc"
  }
}

resource "aws_subnet" "public" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-west-2a"
  
  map_public_ip_on_launch = true
  
  tags = {
    Name = "public-subnet"
  }
}

resource "aws_subnet" "private" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-west-2a"
  
  tags = {
    Name = "private-subnet"
  }
}

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id
  
  tags = {
    Name = "main-igw"
  }
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }
  
  tags = {
    Name = "public-route-table"
  }
}

resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

resource "aws_security_group" "web" {
  name        = "web-sg"
  description = "允許網頁流量"
  vpc_id      = aws_vpc.main.id
  
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

這段程式碼定義了一個VPC,包含公共和私有子網路、網際網路閘道、路由表和一個用於網頁流量的安全群組。

基礎設施平台為現代雲端基礎設施提供了基礎。它們提供了各種資源,你可以用來建立應用程式執行環境,而應用程式執行環境則託管你的應用程式。

瞭解不同型別的基礎設施資源以及它們之間的關係,對於有效實施基礎設施即程式碼至關重要。透過將這些資源定義為程式碼,你可以建立可重複、一致與可管理的基礎設施。