기준: DVA-C02 시험 가이드오류 제보
빌드 도구, 테스트 도구, 배포 도구를 따로 만들었으면 그 다음 문제는 "이걸 어떻게 자동으로 이어 붙일까"다. 한 사람이 매번 손으로 "빌드 끝났으니 테스트 시작", "테스트 통과했으니 배포 시작"을 누르는 건 출시 직전 새벽 3시까지 누군가가 깨어 있어야 하는 비극을 만든다. CodePipeline은 그 비극을 끝내는 도구다. "소스 변경 감지 → 빌드 → 테스트 → 승인 → 배포"라는 흐름을 한 번 정의해두면, 그 다음부터는 코드를 push할 때마다 자동으로 production까지 흘러간다.
DVA-C02 시험에서는 CodePipeline 자체의 문법보다 *다른 Code 서비스들과 어떻게 조합되는지**, 수동 승인이 언제 필요한지, artifact가 어떻게 단계 간에 흐르는지, 그리고 2023년 등장한 V2 파이프라인의 변수와 트리거 필터링이 중요하다. 이번 글에서는 CodePipeline의 내부 동작 모델, 아티팩트 시스템의 본질, 그리고 크로스 계정/리전 패턴까지 짚는다.
CodePipeline은 build tool이 아니다. 빌드 자체는 CodeBuild가 하고, 배포는 CodeDeploy/CloudFormation/ECS가 한다. CodePipeline의 역할은 그것들을 순서대로, 조건부로, 병렬로 실행하는 워크플로우 엔진이다. AWS Step Functions가 일반 비즈니스 워크플로우용이라면, CodePipeline은 CI/CD 워크플로우에 특화된 형태다.
CodePipeline은 Stage(단계) → Action(액션) → Transition(전이)의 3층 구조이고, 각 Action은 외부 서비스 호출이다. GitHub Actions의 jobs → steps, GitLab CI의 stages → jobs, Jenkins의 stages → steps도 같은 추상화다.
CodePipeline의 데이터 모델:
Pipeline (전체 워크플로우)
└── Stage (논리적 단계: Source, Build, Deploy 등)
└── Action (구체적 작업: CodeBuild 실행, CodeDeploy 실행, 수동 승인)
├── Input Artifacts (이전 단계 산출물)
├── Output Artifacts (이 단계 산출물, 다음에 전달)
├── Configuration (액션별 파라미터)
└── Role ARN (이 액션이 사용할 IAM 역할)
한 Stage 안에 여러 Action을 두면 기본적으로 병렬 실행된다. 순차 실행을 강제하려면 runOrder 속성을 다르게 지정한다(runOrder 1 → 2 → 3). "한 stage에서 빌드와 보안 스캔을 동시에 돌리고 둘 다 통과해야 다음 stage" 같은 시나리오에서 정답이 되는 개념이다.
{
"name": "BuildAndScan",
"actions": [
{
"name": "Build",
"runOrder": 1,
"actionTypeId": { "category": "Build", "provider": "CodeBuild" }
},
{
"name": "SecurityScan",
"runOrder": 1, // 같은 runOrder = 병렬
"actionTypeId": { "category": "Test", "provider": "CodeBuild" }
},
{
"name": "UploadResult",
"runOrder": 2, // 위 두 개 완료 후
"actionTypeId": { "category": "Invoke", "provider": "Lambda" }
}
]
}CodePipeline은 액션을 6가지 카테고리로 분류한다. "다음 중 Source 카테고리에 속하지 않는 것은?"처럼 카테고리 분류를 직접 묻는 유형이 있다.
| 카테고리 | 역할 | 대표 Provider |
|---|---|---|
| Source | 코드/아티팩트 가져오기 | CodeCommit, GitHub, GitHub Enterprise, BitBucket, S3, ECR, Service Catalog |
| Build | 빌드 산출물 생성 | CodeBuild, Jenkins, TeamCity |
| Test | 테스트 실행 | CodeBuild, Device Farm, BlazeMeter, Ghost Inspector |
| Approval | 수동 승인 게이트 | Manual, ServiceNow Change |
| Deploy | 배포 실행 | CodeDeploy, CloudFormation, Elastic Beanstalk, ECS, S3, AppConfig, Service Catalog, AWS OpsWorks |
| Invoke | 임의 함수 호출 | Lambda, Step Functions |
"Invoke" 카테고리는 비교적 새로 추가됐는데(2018년 Lambda, 2022년 Step Functions), "임의 검증 로직을 파이프라인 중간에 넣고 싶다"는 시나리오의 정답은 Lambda Invoke다. 단순한 검증은 Manual Approval로 사람이 누르지만, "외부 API에서 컴플라이언스 체크 가져오기" 같은 자동화된 검증은 Lambda Invoke를 쓴다.
CodePipeline의 가장 중요한 개념 중 하나가 아티팩트다. Stage A의 출력이 Stage B의 입력이 되는 메커니즘이고, 이것이 S3 기반이라는 점이 시험에서 구분해야 할 포인트다.
[Source Stage]
Output Artifact: "SourceOutput"
│ (zip으로 압축돼 S3 artifact bucket에 저장)
▼
[Build Stage]
Input Artifact: "SourceOutput"
│ (S3에서 다운로드해 CodeBuild 작업 디렉토리에 풀림)
Output Artifact: "BuildOutput"
│ (artifacts: 섹션의 파일을 다시 zip해 S3에 저장)
▼
[Deploy Stage]
Input Artifact: "BuildOutput"
아티팩트는 계정·리전당 하나의 S3 bucket에 저장된다(이름: codepipeline-<region>-<random>). 파이프라인을 처음 만들 때 AWS가 자동 생성하지만, 명시적으로 다른 bucket을 지정할 수도 있다. 이 bucket의 access를 제대로 통제하지 않으면 빌드 산출물(소스 코드 zip, Docker 이미지 메타데이터)이 노출될 수 있다.
⚠️ 함정: 아티팩트 bucket은 반드시 파이프라인과 같은 리전에 있어야 한다. Cross-Region 배포를 하려면 각 리전마다 별도의 artifact bucket이 필요하고, CodePipeline이 자동으로 복제한다. 이를 모르고 "us-east-1 artifact를 ap-northeast-2 deploy에 직접 참조"하려고 하면 실패한다.
# Cross-Region 배포의 artifact bucket 설정 (CloudFormation 발췌)
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStores:
- Region: us-east-1
ArtifactStore:
Type: S3
Location: !Ref PrimaryArtifactBucket
- Region: ap-northeast-2
ArtifactStore:
Type: S3
Location: !Ref SeoulArtifactBucket # 서울 리전 별도 bucketCodePipeline이 어떻게 trigger되는지는 헷갈리기 쉬운 영역이다. 4가지 방식이 있는데, 권장도와 latency가 다르다.
| 방식 | Latency | 권장 사용처 | 시험 키워드 |
|---|---|---|---|
| EventBridge (default for AWS sources) | 수 초 | CodeCommit, ECR, S3 변경 | "즉각 자동 시작" |
| GitHub Webhook | 수 초 | GitHub push 시 | "GitHub 통합" |
| Polling | 최대 1분 | 레거시, 비권장 | "Polling은 비권장" |
| 수동/CLI | 즉시 | 디버깅, 핫픽스 | "수동 재시작" |
2019년 이전에는 CodePipeline이 기본적으로 polling 모델(매 분마다 S3/GitHub 변경 확인)을 썼다. AWS가 EventBridge 기반 push 모델로 전환한 이유는 ① latency 단축 ② API 호출 비용 절감 ③ GitHub rate limit 회피. Polling은 여전히 가능하지만 비권장으로 명시돼 있고, 시험에서 "가장 효율적인 트리거"가 보이면 EventBridge가 답.
2023년 10월 출시된 V2는 V1의 한계를 정면 해결했다. V1에서 가장 큰 불편이 ① 단계 간 동적 변수 전달 불가 ② 모든 push마다 파이프라인 실행 ③ 동시 실행 제어 부족이었는데, V2가 모두 풀었다.
# 파이프라인 시작 시 변수 정의
variables:
- name: Environment
defaultValue: dev
description: "Target environment"
- name: ImageTag
defaultValue: latest
# 사용
configuration:
ProjectName: my-build
EnvironmentVariables: |
[{"name":"ENV","value":"#{variables.Environment}","type":"PLAINTEXT"}]또 stage의 action variable을 다른 stage에서 참조 가능하다:
Source action output: #{SourceVariables.CommitId}
Build action output: #{BuildVariables.IMAGE_TAG} (CodeBuild의 exported-variables)
#{SourceVariables.CommitId}는 V1에서도 가능했지만 일부 source에서만 노출됐다. V2는 모든 액션이 일관된 변수 모델을 갖는다. 빌드의 exported-variables가 deploy 단계로 자동으로 흐르는 것이 대표적인 패턴이다. 빌드 시 결정된 image tag를 deploy의 ECS task definition에 동적으로 주입.
V1에서는 push만 일어나면 무조건 파이프라인이 실행됐다. V2는 브랜치·파일 패턴으로 필터 가능.
triggers:
- providerType: CodeStarSourceConnection
gitConfiguration:
sourceActionName: Source
push:
- branches:
includes: ["main", "release/**"]
excludes: ["release/experimental"]
filePaths:
includes: ["src/**", "package.json"]
excludes: ["docs/**", "**/*.md"]
- tags:
includes: ["v*.*.*"]⚠️ 함정: 트리거 필터는 V2 + CodeStar Source Connection(GitHub, BitBucket, GitLab)에서만 동작한다. CodeCommit source에는 적용되지 않는다. "CodeCommit + 특정 브랜치만 트리거" 시나리오의 정답은 파이프라인 트리거 필터가 아니라 EventBridge rule 필터링이다.
executionMode: SUPERSEDED # 기본. 새 실행이 들어오면 대기 중인 이전 실행 자동 취소
# 또는
executionMode: QUEUED # 들어온 순서대로 하나씩 실행
# 또는
executionMode: PARALLEL # 여러 실행 동시 진행PARALLEL 모드는 2024년 발표된 새 기능이다. 여러 PR을 동시에 검증해야 하는 monorepo 환경에서 유용. 단 deploy 단계가 같은 리소스(예: 동일 ECS service)를 만지면 race condition이 발생한다. 그래서 Source/Build/Test까지만 PARALLEL로 두고, Deploy는 SUPERSEDED나 QUEUED로 별도 파이프라인을 분리하는 것이 안전한 패턴이다.
자동화는 위대하지만, production 배포 직전에는 사람의 눈이 필요할 때가 있다. 컴플라이언스 요구사항이거나, 정책상 변경 관리 위원회 승인이 필요하거나, 단순히 비즈니스 시간에만 배포하고 싶거나.
- name: ProductionApproval
actions:
- name: Approve
actionTypeId:
category: Approval
owner: AWS
provider: Manual
configuration:
NotificationArn: arn:aws:sns:ap-northeast-2:111122223333:approvals
CustomData: "Please review staging environment at https://staging.example.com"
ExternalEntityLink: "https://staging.example.com"승인 메커니즘 디테일:
codepipeline:PutApprovalResult 권한 필요Manual Approval의 7일 timeout은 변경 불가능한 하드 리밋이다. 더 짧거나 길게 하고 싶으면 EventBridge로 "STARTED" 상태 모니터링 → Lambda로 N시간 후 자동 reject 호출하는 패턴을 쓴다. 또는 Approval action 대신 Lambda Invoke에서 외부 시스템(JIRA, ServiceNow)의 승인 상태를 polling하는 패턴.
Manual Approval에 권한이 있는 IAM 사용자가 본인이 만든 변경을 본인이 승인할 수 있는가? 기본적으로는 가능하지만, IAM Condition aws:userId로 "변경한 사람과 승인자가 달라야 한다"는 분리(separation of duties)를 강제하려면 추가 IAM 정책이 필요하다. 컴플라이언스가 중요한 환경에서는 별도 그룹(release manager)에만 승인 권한을 부여한다.
기업이 성장하면 보통 dev/staging/prod 계정을 분리하고, 각 계정의 권한을 분리한다. CodePipeline이 cross-account로 자원을 만지려면 권한 chain을 명시적으로 설정해야 한다.
[Source Account: 111111111111]
- CodePipeline 실행
- 아티팩트 bucket
- KMS CMK (cross-account 사용 허용)
[Target Account: 222222222222 (prod)]
- CrossAccountDeployRole (Source 계정을 신뢰하는 IAM role)
- CodeDeploy / CloudFormation으로 실제 배포
[Source 계정 Pipeline] →
Sts:AssumeRole (CrossAccountDeployRole) →
[Target 계정에서 배포 실행]
필요한 구성:
sts:AssumeRole for Target 계정 role 권한CodePipeline의 모든 상태 변경(시작, 단계 진행, 성공, 실패)은 EventBridge로 자동 발행된다. 알림·메트릭·자동화의 표준 hook.
{
"source": ["aws.codepipeline"],
"detail-type": [
"CodePipeline Pipeline Execution State Change",
"CodePipeline Stage Execution State Change",
"CodePipeline Action Execution State Change"
],
"detail": {
"state": ["FAILED"]
}
}이걸로 만들 수 있는 패턴:
CodeStar Notifications는 EventBridge 위에 더 친화적 UI를 얹은 것이다. "이메일/Slack/Chime으로 알림"이 목적이라면 CodeStar Notifications가 빠르고, "복잡한 자동화 분기"가 필요하면 EventBridge rule을 직접 쓰는 게 유연하다. 시험에서 "Slack 알림 + 최소 구성"이면 CodeStar Notifications, "조건부 자동 응답"이면 EventBridge.
파이프라인 자체도 코드로 관리하는 게 best practice다. 콘솔로 클릭해 만든 파이프라인은 다른 환경에 복제하기 어렵고, 변경 이력이 안 남는다.
# AWS CDK 예시 (Python)
from aws_cdk import (
Stack, aws_codepipeline as codepipeline,
aws_codepipeline_actions as actions,
aws_codebuild as codebuild,
)
class PipelineStack(Stack):
def __init__(self, scope, id, **kwargs):
super().__init__(scope, id, **kwargs)
source_output = codepipeline.Artifact()
build_output = codepipeline.Artifact()
pipeline = codepipeline.Pipeline(self, "MyPipeline",
pipeline_name="my-app",
stages=[
codepipeline.StageProps(
stage_name="Source",
actions=[actions.CodeCommitSourceAction(
action_name="Source",
repository=repo,
output=source_output,
branch="main",
)]
),
codepipeline.StageProps(
stage_name="Build",
actions=[actions.CodeBuildAction(
action_name="Build",
project=build_project,
input=source_output,
outputs=[build_output],
)]
),
codepipeline.StageProps(
stage_name="Deploy",
actions=[actions.CloudFormationCreateUpdateStackAction(
action_name="DeployInfra",
stack_name="my-app-infra",
template_path=build_output.at_path("template.yaml"),
admin_permissions=False,
)]
),
]
)CodePipeline은 빌드도 배포도 직접 하지 않는다. 그저 다른 도구들을 정해진 순서와 조건으로 호출하는 지휘자다. 그 단순한 역할이 중요한 이유는 "수동으로 하던 모든 release 절차를 한 번 정의해두면 그 다음부터는 사람 없이 동작한다"는 약속을 가능하게 하기 때문이다. CodePipeline V2의 변수와 트리거 필터링은 그 약속을 더 정교한 워크플로우까지 확장한다.
다음 글에서는 이 자동 파이프라인의 마지막 안전망 — CloudFormation의 변경 세트(Change Set)와 drift detection — 을 본다. 인프라가 코드와 일치하는지, 그리고 코드 변경이 production에 어떤 영향을 줄지를 어떻게 사전에 검증하는지를 짚는다.
선택지를 클릭하면 정답·해설이 펼쳐집니다.
문제 1
CodePipeline의 한 stage 안에 빌드 액션과 보안 스캔 액션을 두 개 만들었다. 두 액션이 병렬로 실행되게 하려면?
문제 2
CodePipeline의 stage 간 데이터(빌드 산출물) 전달은 어떻게 이뤄지는가?
문제 3
CodePipeline V2에서 추가된 트리거 필터링 기능에 대한 설명으로 옳은 것은?
문제 4
Production CodeDeploy 단계 직전에 사람의 승인을 반드시 받게 하려면?
문제 5
Source 계정의 CodePipeline이 다른 AWS 계정의 ECS 서비스에 배포하려고 한다. 필요한 구성이 아닌 것은?
문제 6
CodePipeline 파이프라인 실패 시 슬랙 채널에 알림을 보내려 한다. 가장 권장되는 구성은?
문제 7
CodePipeline V2의 execution mode 중 새 실행이 들어오면 대기 중이던 이전 실행을 자동 취소하는 모드는?