CloudFormation 作為基礎設施即程式碼的實踐工具,需要完善的釋出管理策略以確保穩定性和可靠性。選擇合適的分支模型,例如 dev/test/master,配合 CI/CD 系統在不同分支執行對應的測試和佈署流程,是確保程式碼品質的關鍵。程式碼審查和完整的測試覆寫率,包括語法檢查、範本驗證和自定義 linter 規則,能有效減少錯誤。使用 CloudFormation IAM 角色則能提升安全性,避免直接使用管理員許可權。此外,佈署前的煙霧測試能及早發現潛在問題。構建 CI/CD 管道時,選擇合適的工具如 CodePipeline 和 CodeBuild,並持續改進流程,是保持效率和品質的關鍵。

使用CloudFormation進行釋出管理最佳實務

選擇適當的分支模型

在大多數軟體專案中,master分支被視為生產分支。明智地選擇分支模型至關重要,這樣才能將原始碼與CI/CD系統整合。可以將工作流程分為dev/test/master分支,使CI/CD系統在特定分支上執行特定階段。並非每次提交都需要佈署到生產堆積疊,因此對於dev分支,通常只進行驗證和語法檢查。

如果使用像Jira這樣的專案管理工具,請確保在提交訊息中加入問題鍵:

git commit -m "PROJ-1234 add extra subnets for databases"

清晰的註解和包含專案或問題鍵有助於保持程式碼函式庫的整潔和開發過程的透明度。

進行程式碼審查

不要允許直接推播到主分支,而是使用提取請求(Pull Request)來控制即將發生的變更。即使linter檢查透過且所有測試都成功,仍有可能錯誤組態進入生產堆積疊。即使CloudFormation能夠回復,透過審查每次變更總是明智的做法。

完整的測試覆寫率

在佈署變更到堆積疊之前,必須始終執行語法檢查和範本驗證。雖然無法對CloudFormation範本執行單元測試,但仍需要確保盡可能減少錯誤到達CloudFormation的數量。重點開發自定義的cfn-lint規則,以實施組織的最佳實踐。

使用CloudFormation IAM角色

當佈署堆積疊時,我們使用自己的IAM許可權,這意味著我們必須至少在AWS上具有管理員存取策略,這並不安全。此外,由於我們希望更多人協作基礎設施,因此需要使用CloudFormation IAM角色,這樣就不必為每個範本開發人員提供對AWS的管理員存取許可權。

執行煙霧測試

如果我們管理關鍵基礎設施,則需要確保每次變更不會導致故障或組態錯誤。在單獨的環境(甚至是單獨的AWS帳戶)中使用最新的變更佈署臨時堆積疊,並對我們的堆積疊執行煙霧測試,結合適當的語法檢查和驗證,是避免錯誤的最佳實踐。

持續整合與佈署

使用正確的CI/CD工具

堆積疊操作(驗證、語法檢查和佈署)是基本命令。然而,我們需要確保CI/CD系統能夠執行這些操作。我們需要明智地選擇功能和成本。此外,我們需要考慮安全性,因為我們正在提供對AWS帳戶的存取許可權。如果我們有嚴格的安全要求,我們可能會希望在我們的AWS環境中組態CI/CD系統(如GitLab或Jenkins),或使用AWS管理的服務,如CodeBuild或CodePipeline。

持續改進

實踐和方法正在不斷演進,工具也是如此。我們希望重新審視執行CD的方式,並檢視是否有改進的空間。簡而言之,總是有改進的空間。

使用CloudFormation和CodePipeline建立CI/CD管道

在開始建立管道之前,讓我們回顧一下CI/CD管道實際上是什麼。任何CI/CD管道(就軟體開發而言)都由多個階段組成。這些階段通常如下(我們稍後將實踐所有這些步驟):

  1. 預建構:從原始碼管理中提取程式碼並安裝依賴項。
  2. 建構:執行建構並檢索成品。
  3. 測試:對建構執行測試套件。
  4. 封裝:將建構成品儲存在成品儲存中。
  5. 佈署:在環境中佈署新版本。

如果這些步驟中的任何一個失敗,建構系統將觸發錯誤。

那麼,我們如何將相同的步驟應用於CloudFormation?通常,這取決於持續整合(CI)系統。在我們的案例中,這些階段將執行以下操作:

  1. 預建構:將程式碼(例如範本)儲存在AWS CodeCommit中,並使用AWS CodeBuild作為建構系統。我們還將從CodeCommit中提取程式碼並安裝必要的依賴套件,包括以下內容:

    • cfn-lint
    • awscli
    • boto3和botocore(AWS SDK for Python)

    內容解密:

    在預建構階段,我們使用AWS CodeCommit儲存範本,並使用CodeBuild執行建構。我們需要安裝cfn-lint來進行範本驗證,使用awscli與AWS服務互動,以及boto3botocore來與AWS API互動。這些工具確保我們的範本正確無誤,並與AWS服務正確整合。

  2. 建構:此階段將被跳過。為什麼?因為CloudFormation範本不像任何軟體原始碼。例如,我們不需要編譯它們。相反,我們可以執行驗證檢查:

    aws cloudformation validate-template --template-body ...
    

    在此階段,這就足夠了。我們不在測試階段執行驗證檢查的原因是,驗證是一種簡單的語法檢查,類別似於CloudFormation背景下的程式碼編譯。

    內容解密:

    由於CloudFormation範本不需要編譯,因此建構階段被跳過。我們使用aws cloudformation validate-template命令來驗證範本的語法是否正確。這確保了範本在佈署前是有效的。

  3. 測試:在此步驟中,我們將對範本執行cfn-lint檢查。如果linter檢查未失敗,我們將把新範本佈署到測試環境,執行煙霧測試,然後終止它。

    內容解密:

    在測試階段,我們使用cfn-lint檢查範本的正確性。如果檢查透過,我們將範本佈署到測試環境,並執行煙霧測試以確保一切正常運作。測試完成後,我們將終止測試堆積疊,以避免不必要的成本。

  4. 封裝:在此步驟中,我們希望將成品(在我們的案例中,是範本檔案)儲存在成品儲存中。由於作為服務,AWS CloudFormation使用來自S3(特定儲存桶)的範本,因此S3將成為我們的成品儲存。

    一旦測試階段完成,我們將變更後的(或新的)範本上傳到S3儲存桶。

    內容解密:

    我們使用S3作為成品儲存,將經過測試的範本上傳到S3儲存桶。這確保了我們的範本被妥善儲存,並可供稍後的佈署階段使用。

  5. 佈署:在此步驟中,我們將使用儲存在S3上的範本執行生產佈署。

    內容解密:

    在佈署階段,我們使用儲存在S3上的範本來更新生產堆積疊。這確保了生產環境與我們的範本定義保持一致。

場景 - 核心堆積疊

我們決定將核心堆積疊作為AWS環境中的獨立實體儲存。對於核心堆積疊,我們的工作流程將如下所示: 圖表翻譯: 此圖示展示了核心堆積疊的CI/CD工作流程。首先,程式碼被儲存在CodeCommit中。然後,CodeBuild執行建構和驗證。如果驗證成功,變更將被佈署到測試環境,並執行煙霧測試。測試完成後,測試堆積疊被終止,範本被上傳到S3。最後,變更被佈署到生產環境。如果任何步驟失敗,將觸發錯誤處理和通知。

為了執行此任務,我們將使用CodeCommit(原始碼管理)、CodeBuild(建構系統)和CodePipeline(實際的CI/CD聯結器系統)。我們需要組態檔案。第一個是buildspec.yaml——包含指令和建構階段的建構規格檔案(類別似於Jenkins中的Jenkinsfile)。第二個是CloudFormation範本,其中包含管道的所有建構模組:原始碼儲存函式庫、建構專案和管道。

讓我們從buildspec.yml開始。以下是我們的案例中的內容: // buildspec.yml

version: 0.2
phases:
  install:
    commands:
      - pip install cfn-lint
  pre_build:
    commands:
      - aws cloudformation validate-template --template-body file://template.yaml
  build:
    commands:
      - cfn-lint -t template.yaml
  post_build:
    commands:
      - aws cloudformation package --template-file template.yaml --s3-bucket my-bucket --output-template-file packaged.yaml
artifacts:
  files:
    - packaged.yaml

內容解密:

buildspec.yml檔案中,我們定義了建構過程中的不同階段。在install階段,我們安裝了cfn-lint工具。在pre_build階段,我們使用aws cloudformation validate-template命令驗證範本的語法。在build階段,我們執行cfn-lint檢查以確保範本符合最佳實踐。在post_build階段,我們使用aws cloudformation package命令將範本封裝並上傳到S3。最後,我們將封裝好的範本檔案packaged.yaml作為成品輸出。

透過這種方式,我們建立了一個完整的CI/CD管道,用於管理CloudFormation堆積疊的釋出。這個管道確保了範本的正確性、安全性和一致性,並且可以在不同的環境中重複使用。

使用CloudFormation和CodePipeline建立CI/CD Pipeline

概述

本文將詳細介紹如何利用AWS的CloudFormation和CodePipeline服務建立一個完整的CI/CD(持續整合/持續佈署)流程。該流程涵蓋了從原始碼管理到自動化佈署的全過程,有效提升了軟體開發的效率和品質。

CI/CD Pipeline的架構

我們的CI/CD Pipeline主要由以下幾個元件組成:

  1. 原始碼管理:使用AWS CodeCommit作為原始碼倉函式庫。
  2. 建置專案:利用AWS CodeBuild進行建置、驗證和測試。
  3. 構件儲存:使用S3儲存桶儲存建置後的構件。
  4. Pipeline管理:透過AWS CodePipeline管理整個CI/CD流程。
  5. IAM角色:為各個服務組態適當的IAM角色以確保安全性和正確的許可許可權。

詳細步驟

1. 定義CI/CD範本

首先,我們需要定義一個CloudFormation範本(cicd.yaml),該範本包含了CI/CD Pipeline所需的所有資源。

// cicd.yaml
Repository:
  Type: "AWS::CodeCommit::Repository"
  Properties:
    RepositoryName: "core"

TemplateBucket:
  Type: "AWS::S3::Bucket"

Build:
  Type: "AWS::CodeBuild::Project"
  Properties:
    Artifacts:
      Type: "CODEPIPELINE"
    ServiceRole: !GetAtt BuildRole.Arn
    Name: "Core"
    Source:
      Type: "CODEPIPELINE"
    Environment:
      Type: "LINUX_CONTAINER"
      ComputeType: "BUILD_GENERAL1_SMALL"
      Image: "aws/codebuild/amazonlinux2-x86_64-standard:2.0"

2. 組態CodeBuild

buildspec.yml檔案中,我們定義了CodeBuild的建置規格,包括安裝依賴、建置、測試和佈署等步驟。

// buildspec.yml
install:
  runtime-versions:
    python: 3.8
  commands:
    - pip install awscli cfn-lint

build:
  commands:
    - aws cloudformation validate-template --template-body file://core.yaml
    - cfn-lint core.yaml

post_build:
  commands:
    - aws cloudformation deploy --template-file core.yaml --stack-name core-tmp --capabilities CAPABILITY_NAMED_IAM --role-arn $CFN_ROLE
    - python tests/core_subnets.py core-tmp
  finally:
    - aws cloudformation delete-stack --stack-name core-tmp --role-arn $CFN_ROLE

artifacts:
  files:
    - core.yaml

#### 內容解密:

此段落定義了CodeBuild的建置流程。首先,在install階段安裝必要的依賴,如awsclicfn-lint。接著,在build階段驗證CloudFormation範本並進行lint檢查。在post_build階段,佈署一個暫時的CloudFormation堆積疊,執行測試,並最終刪除該堆積疊。最後,將產生的core.yaml檔案儲存為構件。

3. 定義CodePipeline

cicd.yaml中,我們還定義了CodePipeline的組態,包括原始碼取得、建置和佈署三個階段。

// cicd.yaml (Pipeline組態)
- Name: "Clone"
  Actions:
    - ActionTypeId:
        Category: "Source"
        Owner: "AWS"
        Provider: "CodeCommit"
        Version: "1"
      Name: "Clone"
      OutputArtifacts:
        - Name: "CloneOutput"
      Configuration:
        BranchName: "main"
        RepositoryName: !GetAtt Repository.Name
      RunOrder: 1

- Name: "Build"
  Actions:
    - Name: "Build"
      InputArtifacts:
        - Name: "CloneOutput"
      ActionTypeId:
        Category: "Build"
        Owner: "AWS"
        Version: "1"
        Provider: "CodeBuild"
      OutputArtifacts:
        - Name: "BuildOutput"
      Configuration:
        ProjectName: !Ref Build
      RunOrder: 1

- Name: "Deploy"
  Actions:
    - Name: "Deploy"
      InputArtifacts:
        - Name: "BuildOutput"
      ActionTypeId:
        Category: "Deploy"
        Owner: "AWS"
        Version: "1"
        Provider: "CloudFormation"
      OutputArtifacts:
        - Name: "DeployOutput"
      Configuration:
        ActionMode: "CREATE_UPDATE"
        RoleArn: !GetAtt CfnRole.Arn
        Capabilities: "CAPABILITY_NAMED_IAM"
        StackName: "Core"
        TemplatePath: "BuildOutput::core.yaml"
      RunOrder: 1

#### 內容解密:

此段落定義了CodePipeline的三個階段。首先,在Clone階段從CodeCommit倉函式庫取得原始碼並儲存到S3。接著,在Build階段使用CodeBuild進行建置。最後,在Deploy階段使用CloudFormation佈署或更新堆積疊。

佈署CI/CD堆積疊

使用以下命令佈署CI/CD堆積疊:

aws cloudformation deploy \
  --stack-name cicd \
  --template-file cicd.yaml \
  --capabilities CAPABILITY_IAM

上傳必要檔案到CodeCommit

手動或使用Git命令將必要的檔案(如core.yamlbuildspec.yml等)上傳到CodeCommit倉函式庫。

檢視CodePipeline執行結果

在AWS管理主控台中檢視CodePipeline的執行結果,確保Pipeline能夠正確執行並完成佈署。

@startuml
skinparam backgroundColor #FEFEFE

title CloudFormation 釋出管理與 CI/CD 最佳實務

|開發者|
start
:提交程式碼;
:推送到 Git;

|CI 系統|
:觸發建置;
:執行單元測試;
:程式碼品質檢查;

if (測試通過?) then (是)
    :建置容器映像;
    :推送到 Registry;
else (否)
    :通知開發者;
    stop
endif

|CD 系統|
:部署到測試環境;
:執行整合測試;

if (驗證通過?) then (是)
    :部署到生產環境;
    :健康檢查;
    :完成部署;
else (否)
    :回滾變更;
endif

stop

@enduml

圖表翻譯:

此圖表展示了CI/CD流程的主要步驟。首先,從CodeCommit取得原始碼。接著,透過CodePipeline執行Clone、Build和Deploy階段。最終,顯示CodePipeline的執行結果。