CodePipeline: Nối Source, Build, Deploy Thành Dây Chuyền

K
Kai··5 min read

Bốn Part đầu xây từng mảnh: code trên CodeCommit, build bằng CodeBuild, deploy bằng CodeDeploy. Nhưng mỗi mảnh ta vẫn kích hoạt bằng tay — gõ start-build, gõ create-deployment. Đó chưa phải CI/CD; đó là các bước rời. CodePipeline là nhạc trưởng nối chúng thành một dây chuyền tự động: có commit mới là cả chuỗi Source → Build → Deploy tự chạy. Bài này dựng pipeline đầu tiên.

💰 Chi phí

Pipeline deploy lên một EC2 t3.micro (target in-place). CodePipeline tính theo pipeline hoạt động (có một mức free-tier). Giữ pipeline + target cho bài 13–14, dọn ở cuối Part V.

Mục tiêu

Hiểu cấu trúc CodePipeline (stage, action, artifact), dựng pipeline ghép ba dịch vụ đã học, và thấy artifact chảy giữa các stage ra sao.

Stage, action, artifact

CodePipeline mô hình hóa quy trình thành các stage chạy tuần tự, mỗi stage chứa các action. Mỗi action sinh ra output artifact (gói file) cất ở một artifact store (bucket S3), và stage sau nhận input artifact là output của stage trước. Đó là cách dữ liệu chảy: Source cho ra mã nguồn, Build nhận mã nguồn và cho ra gói đã build, Deploy nhận gói đã build và đưa lên server.

Ta dùng pipeline type V2 — bản hiện hành, hỗ trợ biến, trigger lọc, và tính theo lần chạy.

Service role và artifact store

Pipeline cần service role (trust codepipeline.amazonaws.com) với quyền: đọc/ghi bucket artifact, lấy code từ CodeCommit, gọi CodeBuild, gọi CodeDeploy. Đây là role điều phối — nó gọi các dịch vụ, còn mỗi dịch vụ vẫn chạy dưới role riêng của nó (CodeBuild dưới role bài 2, CodeDeploy dưới role bài 8). Artifact store là bucket S3 đã tạo ở bài 2 (đã bật versioning — chính vì pipeline).

Định nghĩa pipeline

Pipeline khai bằng JSON, ba stage nối nhau:

{
  "pipeline": {
    "name": "awscicd-pipeline",
    "roleArn": "arn:aws:iam::111122223333:role/awscicd-codepipeline-role",
    "artifactStore": {"type": "S3", "location": "awscicd-artifacts-111122223333-ap-southeast-1"},
    "pipelineType": "V2",
    "stages": [
      {"name": "Source", "actions": [{
        "name": "Source",
        "actionTypeId": {"category": "Source", "owner": "AWS", "provider": "CodeCommit", "version": "1"},
        "configuration": {"RepositoryName": "awscicd-demo-app", "BranchName": "main"},
        "outputArtifacts": [{"name": "SourceOutput"}]
      }]},
      {"name": "Build", "actions": [{
        "name": "Build",
        "actionTypeId": {"category": "Build", "owner": "AWS", "provider": "CodeBuild", "version": "1"},
        "configuration": {"ProjectName": "awscicd-demo-build"},
        "inputArtifacts": [{"name": "SourceOutput"}],
        "outputArtifacts": [{"name": "BuildOutput"}]
      }]},
      {"name": "Deploy", "actions": [{
        "name": "Deploy",
        "actionTypeId": {"category": "Deploy", "owner": "AWS", "provider": "CodeDeploy", "version": "1"},
        "configuration": {"ApplicationName": "awscicd-demo", "DeploymentGroupName": "awscicd-demo-dg"},
        "inputArtifacts": [{"name": "BuildOutput"}]
      }]}
    ]
  }
}

Để ý dây nối: Source outputArtifacts: SourceOutput → Build inputArtifacts: SourceOutput, rồi Build outputArtifacts: BuildOutput → Deploy inputArtifacts: BuildOutput. Tên artifact chính là cách các stage nối với nhau.

$ aws codepipeline create-pipeline --cli-input-json file://pipeline.json \
    --query 'pipeline.[name,pipelineType]' --output text
awscicd-pipeline    V2

Pipeline tự chạy

Tạo xong, pipeline tự khởi chạy ngay lần đầu. Poll trạng thái từng stage:

$ aws codepipeline get-pipeline-state --name awscicd-pipeline \
    --query 'stageStates[].[stageName,latestExecution.status]' --output text
Source:InProgress  Build:None        Deploy:None
Source:Succeeded   Build:InProgress  Deploy:None
Source:Succeeded   Build:Succeeded   Deploy:InProgress
Source:Succeeded   Build:Succeeded   Deploy:Succeeded

Cả ba stage chạy lần lượt và Succeeded. Toàn bộ chuỗi — kéo code, build, test, deploy lên EC2 — chạy mà không gõ một lệnh nào sau khi tạo pipeline. Kiểm chứng app lên server:

$ curl http://<ec2-public-ip>/
... awscicd demo app — v2 ...

Artifact chảy giữa các stage

Đây là cơ chế đáng mổ. Mỗi stage không tự lấy lại code từ đầu — nó nhận output của stage trước qua artifact store. Cụ thể:

  • Source kéo code từ CodeCommit, đóng thành SourceOutput (zip), đẩy lên bucket artifact.
  • Build lấy SourceOutput làm input (không tự clone CodeCommit nữa — CodeBuild trong pipeline dùng artifact đầu vào thay cho source khai trong project), chạy buildspec.yml, cho ra BuildOutput chứa index.html + appspec.yml + scripts/.
  • Deploy lấy BuildOutput làm revision; vì gói này có appspec.yml ở gốc, CodeDeploy biết cách triển khai.
   commit → CodeCommit (main)
        │  trigger
   ┌──────────────── CodePipeline awscicd-pipeline (V2) ────────────────┐
   │  Source              Build                Deploy                    │
   │  CodeCommit  ──────▶ CodeBuild  ────────▶ CodeDeploy                │
   │  out:SourceOutput    in:SourceOutput      in:BuildOutput            │
   │                      out:BuildOutput      (in-place EC2)            │
   └──────┬──────────────────┬──────────────────────┬───────────────────┘
          └── artifact store S3 (mỗi stage đọc output stage trước) ──┘
                                                     ▼
                                       curl http://<ec2>/ → v2

Điểm mấu chốt: artifact là hợp đồng giữa các stage. Build không cần biết Source lấy code từ đâu, Deploy không cần biết Build làm gì — mỗi stage chỉ nhận một gói, làm việc của mình, đưa ra một gói. Nhờ vậy thay từng mảnh được: đổi nguồn từ CodeCommit sang khác chỉ sửa stage Source, phần còn lại không đụng.

Trigger: chạy khi có commit

Lần chạy đầu là do tạo pipeline. Từ đó về sau, pipeline tự chạy mỗi khi nhánh main của CodeCommit có commit mới — CodePipeline dựng sẵn một quy tắc EventBridge để bắt sự kiện đó (trigger type hiện là PollForSourceChanges hoặc qua EventBridge tùy cấu hình). Nghĩa là từ giờ, lập trình viên chỉ cần git push, và dây chuyền lo phần còn lại tới khi code chạy trên server.

🧹 Dọn dẹp

Pipeline và EC2 target dùng tiếp ở bài 13–14, nên giữ tới hết Part V. Khi dọn:

$ aws codepipeline delete-pipeline --name awscicd-pipeline
$ aws ec2 terminate-instances --instance-ids <target-iid>

Tổng kết

CodePipeline nối các chặng thành dây chuyền: stage chạy tuần tự, mỗi action sinh artifact, stage sau nhận artifact của stage trước qua artifact store S3. Ta dựng pipeline V2 ba stage — Source (CodeCommit) → Build (CodeBuild) → Deploy (CodeDeploy) — chạy dưới một service role điều phối, và nó tự chạy end-to-end ngay khi tạo, đưa app lên EC2 không cần thao tác tay. Artifact là hợp đồng giữa các stage (SourceOutputBuildOutput), nên mỗi mảnh thay được độc lập. Từ đây, git push là đủ để kích hoạt cả chuỗi.

Bài tới làm pipeline thực dụng hơn cho production: thêm cổng phê duyệt thủ công trước khi deploy, chạy nhiều action song song, và lọc trigger theo nhánh — những thứ biến một pipeline "chạy được" thành một pipeline "dùng được ở công ty".