前言 在現代軟體開發中,手動部署已經成為過去式。自動化部署不僅能減少人為錯誤,還能加快交付速度,讓開發團隊專注於功能開發而非維運瑣事。
AWS 提供了一套完整的 DevOps 工具鏈,從程式碼託管、建置、測試到部署,以及基礎設施即程式碼(IaC)服務。本篇將深入探討:
AWS Code 系列服務:CodeCommit, CodeBuild, CodeDeploy, CodePipeline
CloudFormation:AWS 的 IaC 基石
AWS CDK:用程式語言定義基礎設施
實戰:構建一個完整的 CI/CD 流水線
AWS Code 系列服務全景 graph LR
subgraph "Source"
A[CodeCommit] -->|Git Push| B[CodePipeline]
G[GitHub] -->|Webhook| B
end
subgraph "Build"
B -->|Source Artifact| C[CodeBuild]
end
subgraph "Deploy"
C -->|Build Artifact| D[CodeDeploy]
end
subgraph "Target"
D --> E[EC2 / On-Premises]
D --> F[Lambda / ECS]
end
服務
功能
對應工具
CodeCommit
Git 儲存庫託管
GitHub, GitLab
CodeBuild
編譯、測試、打包
Jenkins, GitHub Actions
CodeDeploy
自動化部署到運算資源
Octopus Deploy
CodePipeline
協調發布流程
Jenkins Pipeline
CodeArtifact
套件管理
Nexus, Artifactory
CodePipeline:自動化流水線 CodePipeline 是整個 CI/CD 的指揮官,負責串聯各個階段。
流水線階段設計 一個標準的生產環境流水線通常包含以下階段:
Source :監聽 Git 分支變更
Build :編譯程式碼、執行單元測試、建置 Docker Image
Test (Staging) :部署到測試環境、執行整合測試
Approval :人工審核(生產環境部署前)
Deploy (Prod) :部署到生產環境
CodeBuild 配置 (buildspec.yml) CodeBuild 使用 buildspec.yml 定義建置步驟。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 version: 0.2 phases: install: runtime-versions: golang: 1.21 commands: - echo Installing dependencies... - go mod download pre_build: commands: - echo Logging in to Amazon ECR... - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com build: commands: - echo Build started on `date` - echo Building the Docker image... - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG . - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG post_build: commands: - echo Build completed on `date` - echo Pushing the Docker image... - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG - printf '[{"name":"my-app","imageUri":"%s"}]' $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG > imagedefinitions.json artifacts: files: imagedefinitions.json
CloudFormation 是 AWS 原生的 IaC 服務,使用 JSON 或 YAML 描述資源。
核心概念
Template :描述資源的 JSON/YAML 檔案
Stack :根據 Template 建立的一組資源集合
Change Set :預覽 Stack 更新會造成的影響
Template 結構範例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 AWSTemplateFormatVersion: '2010-09-09' Description: A simple S3 bucket and DynamoDB table Parameters: EnvironmentName: Type: String Default: dev AllowedValues: [dev , staging , prod ] Resources: MyBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub "${EnvironmentName}-my-app-assets" AccessControl: Private MyTable: Type: AWS::DynamoDB::Table Properties: TableName: !Sub "${EnvironmentName}-Orders" BillingMode: PAY_PER_REQUEST AttributeDefinitions: - AttributeName: PK AttributeType: S KeySchema: - AttributeName: PK KeyType: HASH Outputs: BucketName: Value: !Ref MyBucket Export: Name: !Sub "${EnvironmentName}-BucketName"
AWS CDK:用程式碼定義基礎設施 雖然 CloudFormation 很強大,但 YAML 寫起來冗長且缺乏邏輯能力。AWS CDK (Cloud Development Kit) 允許你使用熟悉的程式語言(TypeScript, Python, Go, Java)來定義基礎設施。
為什麼選擇 CDK?
真正的程式語言 :可以使用迴圈、條件判斷、繼承等特性。
高階抽象 (Constructs) :L2/L3 Construct 封裝了最佳實踐,幾行程式碼就能建立複雜架構(如 VPC + ALB + Fargate)。
型別安全 :IDE 自動補全與編譯時檢查。
CDK 實戰:Go 語言範例 假設我們要建立一個包含 VPC、ECS Fargate Service 和 ALB 的架構。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package mainimport ( "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/aws-cdk-go/awscdk/v2/awsec2" "github.com/aws/aws-cdk-go/awscdk/v2/awsecs" "github.com/aws/aws-cdk-go/awscdk/v2/awsecspatterns" "github.com/aws/constructs-go/constructs/v10" "github.com/aws/jsii-runtime-go" ) type MyStackProps struct { awscdk.StackProps } func NewMyStack (scope constructs.Construct, id string , props *MyStackProps) awscdk.Stack { var sprops awscdk.StackProps if props != nil { sprops = props.StackProps } stack := awscdk.NewStack(scope, &id, &sprops) vpc := awsec2.NewVpc(stack, jsii.String("MyVpc" ), &awsec2.VpcProps{ MaxAzs: jsii.Number(2 ), }) cluster := awsecs.NewCluster(stack, jsii.String("MyCluster" ), &awsecs.ClusterProps{ Vpc: vpc, }) awsecspatterns.NewApplicationLoadBalancedFargateService(stack, jsii.String("MyService" ), &awsecspatterns.ApplicationLoadBalancedFargateServiceProps{ Cluster: cluster, Cpu: jsii.Number(256 ), MemoryLimitMiB: jsii.Number(512 ), DesiredCount: jsii.Number(2 ), TaskImageOptions: &awsecspatterns.ApplicationLoadBalancedTaskImageOptions{ Image: awsecs.ContainerImage_FromRegistry(jsii.String("amazon/amazon-ecs-sample" )), }, PublicLoadBalancer: jsii.Bool(true ), }) return stack } func main () { app := awscdk.NewApp(nil ) NewMyStack(app, "MyStack" , &MyStackProps{ awscdk.StackProps{ Env: env(), }, }) app.Synth(nil ) } func env () *awscdk.Environment { return nil }
這段不到 50 行的 Go 程式碼,如果轉成 CloudFormation YAML,可能需要超過 500 行!
CDK 常用指令
cdk init app --language go:初始化專案
cdk synth:生成 CloudFormation Template
cdk diff:比較目前程式碼與已部署資源的差異
cdk deploy:部署 Stack
cdk destroy:刪除 Stack
實戰:構建完整的 CI/CD 流水線 我們將使用 CDK 來定義一個自我更新的 CI/CD 流水線(Pipeline that updates itself)。
架構設計 graph TD
Git[GitHub Repo] -->|Webhook| Pipeline[CodePipeline]
subgraph "Pipeline Stages"
Source[Source Stage] --> Build[Build Stage]
Build --> Update[Self-Mutate]
Update --> DeployDev[Deploy Dev]
DeployDev --> Approval[Manual Approval]
Approval --> DeployProd[Deploy Prod]
end
Update -->|更新 Pipeline 定義| Pipeline
CDK Pipelines 實作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 func NewPipelineStack (scope constructs.Construct, id string , props *awscdk.StackProps) awscdk.Stack { stack := awscdk.NewStack(scope, &id, props) source := pipelines.CodePipelineSource_Connection( jsii.String("my-org/my-repo" ), jsii.String("main" ), &pipelines.ConnectionSourceOptions{ ConnectionArn: jsii.String("arn:aws:codestar-connections:..." ), }, ) pipeline := pipelines.NewCodePipeline(stack, jsii.String("Pipeline" ), &pipelines.CodePipelineProps{ Synth: pipelines.NewShellStep(jsii.String("Synth" ), &pipelines.ShellStepProps{ Input: source, Commands: jsii.Strings( "go mod download" , "cdk synth" , ), }), }) pipeline.AddStage(NewAppStage(stack, "Dev" , &awscdk.StageProps{ Env: &awscdk.Environment{Account: jsii.String("111111111111" ), Region: jsii.String("ap-northeast-1" )}, }), nil ) prodStage := pipeline.AddStage(NewAppStage(stack, "Prod" , &awscdk.StageProps{ Env: &awscdk.Environment{Account: jsii.String("222222222222" ), Region: jsii.String("ap-northeast-1" )}, }), &pipelines.AddStageOpts{ Pre: []pipelines.Step{ pipelines.NewManualApprovalStep(jsii.String("PromoteToProd" ), nil ), }, }) return stack }
DevOps 最佳實踐
基礎設施即程式碼 (IaC)
所有基礎設施變更都必須透過程式碼(CDK/CloudFormation)進行,禁止手動在 Console 修改。
這樣可以確保環境的一致性與可複製性。
不可變基礎設施 (Immutable Infrastructure)
不要 SSH 進去伺服器修補。
每次部署都建立新的 AMI 或 Container Image,替換舊的資源。
小步快跑
頻繁的小規模部署優於偶爾的大規模部署。
配合 Feature Flags 控制功能開關。
環境隔離
Dev, Staging, Prod 應該在不同的 AWS 帳號中,避免資源誤用或權限過大。
本章重點回顧 關鍵要點
CodePipeline
串聯 Source, Build, Deploy 的自動化工具
支援跨帳號、跨 Region 部署
CloudFormation
AWS 的 IaC 基礎
使用 Stack 管理資源生命週期
AWS CDK
推薦使用的 IaC 工具
使用程式語言定義架構,具備高階抽象能力
cdk diff 是部署前的好幫手
CI/CD 策略
建立自我更新的 Pipeline
實施人工審核機制保護生產環境
嚴格遵守 IaC 原則
下一篇預告 在系列的第七篇文章中,我們將探討 監控與可觀測性 :
CloudWatch Metrics 與 Alarms
CloudWatch Logs Insights 查詢技巧
X-Ray 分散式追蹤
構建全方位的監控儀表板
系列文章導覽
參考資源