A fully managed Source → Build → Test → Deploy toolchain that automates getting application changes from a repository into production, without you running Jenkins masters or writing your own deployment scripts. This module pairs deep "how it actually works" understanding with the exam-reasoning layer the Developer Associate exam tests — including a critical, explicit flag on two services AWS has deprecated for new customers.
Effective July 25, 2024, AWS CodeCommit stopped onboarding new customers — an AWS account that had never created a CodeCommit repository before that date cannot create one now. Existing customers with existing repositories are unaffected and can keep using them, but CodeCommit receives no new features. AWS CodeStar (the older "one-click project template" service that used to bundle CodeCommit + CodeBuild + CodeDeploy + CodePipeline together) was deprecated just days later — July 31, 2024 — and its console has been retired. Neither should be presented as the current best-practice answer for a brand-new project. The exam may still test legacy knowledge of both (how CodeCommit triggers a pipeline, what CodeStar used to bundle), but the real-world — and increasingly the exam's own — expected answer for "connect a Git source to CodePipeline" today is GitHub, Bitbucket, or GitLab via AWS CodeConnections (the current name for what was originally called CodeStar Connections — the connection mechanism itself is not deprecated, only the CodeStar project-template product is). This distinction — CodeStar (deprecated) vs CodeStar Connections/CodeConnections (current, actively used) — is a frequently-tested trap and is covered in depth in the Components and Best Practices tabs.
imagedefinitions.json) for the Deploy stage to consume.buildspec.yml, and discards the container afterward. There is no persistent build server to patch or scale.appspec.yml) and orchestrates rolling it onto EC2/On-Premises instances, an ECS service, or a Lambda function/alias, following a defined deployment configuration and set of lifecycle hooks.Nearly every CI/CD question on this exam tests one of three things: (1) can you match the right config file to the right service — buildspec.yml is CodeBuild, appspec.yml is CodeDeploy, and mixing them up is the single most common distractor pattern; (2) do you know which deployment type is valid for which compute platform — in-place only exists for EC2/On-Premises, while blue/green spans EC2/On-Premises, Lambda, and ECS but means something structurally different on each one; and (3) can you correctly identify that CodeCommit and CodeStar are legacy and steer a "new project, new Git repo" scenario toward GitHub/Bitbucket/GitLab via CodeConnections instead.
| Domain | Where CI/CD Shows Up |
|---|---|
| Domain 1 — Development with AWS Services (32%) | Writing buildspec.yml/appspec.yml, using the CodeBuild/CodeDeploy/CodePipeline SDKs and CLI, packaging Lambda/container artifacts for deployment |
| Domain 2 — Security (26%) | Service roles per stage, iam:PassRole, storing secrets referenced from buildspec in Secrets Manager/Parameter Store rather than hardcoding them |
| Domain 3 — Deployment (24%) | The centerpiece domain for this file — pipeline design, deployment strategies, deployment configurations, rollback behavior |
| Domain 4 — Troubleshooting & Optimization (18%) | Diagnosing a failed build from CodeBuild logs, diagnosing a stuck/failed CodeDeploy deployment via lifecycle event logs, tuning build performance with caching |
CI/CD is one of the highest-yield topic clusters on DVA-C02 — it is explicitly named in the exam guide's Deployment domain and recurs inside Domain 1 and Domain 2 questions too, so treat this file as core material, not a side topic.
Automatically build, test, and release application changes whenever code changes, without managing build servers or hand-writing deployment scripts
A continuous integration / continuous delivery pipeline, fully managed, triggered by a source-control event
AWS CodePipeline (orchestration) + AWS CodeBuild (build/test) + AWS CodeDeploy (deploy)
Define stages/actions in CodePipeline; buildspec.yml drives what CodeBuild does; appspec.yml + a deployment group drive what CodeDeploy does
CloudWatch Logs (build output), CloudWatch Alarms (rollback trigger source), CloudTrail (API activity), SNS (manual approval / notifications)
CodeDeploy automatic rollback on deployment failure and/or CloudWatch alarm breach; a manual approval action gates the production Deploy stage
buildspec.yml phases in fixed order: install → pre_build → build → post_buildappspec.yml = CodeDeploy; hook order differs per compute platformiam:PassRoleExam appearance probability: HIGH
The settings, file formats, and structural concepts inside each service that most commonly appear in exam scenarios.
buildspec.yml High exam relevanceBUILD_GENERAL1_SMALL/MEDIUM/LARGE/2XLARGE (plus GPU-enabled options)| buildspec.yml phase | What runs here |
|---|---|
install | Install runtime versions and dependencies (the runtime-versions block) |
pre_build | Commands before the main build — e.g. ECR login, restoring cached dependencies, linting |
build | The main compile/test/package commands — e.g. docker build, running the test suite |
post_build | Cleanup, pushing the built image to ECR, sending notifications, finalizing artifacts |
install → pre_build → build → post_build. An artifacts block (separate from the phases) defines which files become the stage's output artifact, and an optional cache block defines paths cached locally or in S3 between builds to speed up dependency installs.buildspec.yml — this is the expected pattern for credentials, never hardcoding secrets in the file itself.appspec.yml — what actually gets deployedappspec.yml & Lifecycle Hooks High-trap| Platform | appspec structure | Hook order |
|---|---|---|
| EC2 / On-Premises | version, os, files (source → destination copy mapping), hooks | ApplicationStop → DownloadBundle → BeforeInstall → Install → AfterInstall → ApplicationStart → ValidateService |
| Lambda | version, Resources (function name, alias, current/target version, timeout) | BeforeAllowTraffic → AfterAllowTraffic |
| ECS | version, Resources (task definition ARN, container name/port) | BeforeInstall → AfterInstall → AfterAllowTestTraffic → BeforeAllowTraffic → AfterAllowTraffic |
appspec.yml has a files section — Lambda and ECS revisions simply reference the new function version or task definition; there's no file-copy step because there's no server to copy files onto.hooks section maps to a script executed at that lifecycle point (EC2/On-Premises) or is used purely for validation/traffic control (Lambda/ECS — e.g. running smoke tests in BeforeAllowTraffic before traffic actually shifts).On EC2 it's a fleet swap behind a load balancer. On Lambda it's weighted alias traffic shifting between function versions. On ECS it's a task-set/target-group swap. The exam expects you to know which mechanism applies to which platform, not just the phrase "blue/green."
| Platform | Built-in configurations |
|---|---|
| EC2/On-Premises (in-place or blue/green) | CodeDeployDefault.OneAtATime, HalfAtATime, AllAtOnce, or a custom configuration specifying minimum healthy host percentage |
| Lambda / ECS (blue/green traffic shifting) | Canary10Percent5Minutes, Linear10PercentEvery1Minute, AllAtOnce (and similar named variants at different percentages/intervals) |
Higher batch sizes (AllAtOnce) deploy fastest but risk the largest blast radius on failure; OneAtATime/Linear/Canary trade deployment speed for safety and faster detection of a bad revision before it reaches 100% of traffic.
iam:PassRole to hand execution off to the roles used by the services it invokes.buildspec.yml.iam:PassRole is required whenever one service must hand off execution to another service's role (e.g., CodePipeline passing the CodeDeploy service role at deploy time) — a common "why did my pipeline fail with an access denied error despite the roles looking correct" root cause.Requirement → Keywords → Expected Answer → why every distractor fails.
AWS CodePipeline + AWS CodeBuild + AWS CodeDeploy
| Distractor | Why it's wrong |
|---|---|
| Self-hosted Jenkins on EC2 | You now own patching, scaling, and HA for the build server — the opposite of low operational overhead |
| AWS CodeStar | Deprecated/retired product — not a valid "set this up today" answer, even though it once bundled these same services |
| Custom Lambda + CLI scripting | You'd be building your own orchestration engine — far more operational overhead than using managed orchestration |
AWS CodeBuild
| Distractor | Why it's wrong |
|---|---|
| AWS CodeDeploy | Deploys already-built revisions — has no build/compile/test capability |
| AWS CodePipeline | Orchestrates the workflow; delegates the actual build work to CodeBuild |
| A dedicated EC2 build server | Requires you to manage patching/scaling — not the managed, ephemeral answer |
CodeDeploy blue/green deployment for ECS (e.g. CodeDeployDefault.ECSLinear10PercentEvery1Minutes, with a CloudWatch alarm configured for automatic rollback)
| Distractor | Why it's wrong |
|---|---|
| CodeDeploy in-place deployment | In-place is EC2/On-Premises only — CodeDeploy has no in-place option for ECS |
| Native ECS service rolling update (no CodeDeploy) | Works, but doesn't provide CodeDeploy's weighted traffic shifting, hooks, and alarm-based automatic rollback that "gradual" and "fast rollback" imply |
| Manually creating a second ECS service and swapping DNS | Reinvents what CodeDeploy blue/green already automates — much higher operational overhead |
CodeDeploy blue/green for Lambda using a Canary (e.g. Canary10Percent5Minutes) deployment configuration with a CloudWatch alarm attached to the deployment group
| Distractor | Why it's wrong |
|---|---|
| Manually adjusting alias weights over time | Works technically, but is manual, error-prone, and has no built-in automatic rollback on alarm breach |
| Publishing a new Lambda version with no alias | Without an alias and CodeDeploy, there's no traffic-shifting mechanism at all — every invocation hits whichever version is configured |
| A CodePipeline manual approval action only | Approval gates a human decision; it doesn't perform gradual, monitored traffic shifting |
Use AWS CodeConnections as the Source action provider for the GitHub repository (webhook-driven via EventBridge)
| Distractor | Why it's wrong |
|---|---|
| Migrate the repo to CodeCommit first | Unnecessary — CodeConnections integrates directly with GitHub; also CodeCommit can't onboard new customers |
| Leave CodePipeline on its default periodic polling behavior | Polling checks on an interval — it does not deliver near-real-time triggering |
| Use an S3 bucket as the Source and manually upload zips | Reintroduces a manual step the scenario is explicitly trying to automate away |
They cannot provision a new CodeCommit repository — recommend GitHub, GitLab, or Bitbucket connected via AWS CodeConnections instead
| Distractor | Why it's wrong |
|---|---|
| AWS CodeCommit | The obvious-looking answer is the trap — AWS stopped onboarding new CodeCommit customers on July 25, 2024 |
| AWS CodeStar | Also deprecated; was never itself a Git hosting service anyway (it scaffolded projects, often on top of CodeCommit) |
| Self-hosted GitLab on EC2 | Introduces server management overhead the managed alternatives avoid |
AWS CodeBuild — buildspec.yml
| Distractor | Why it's wrong |
|---|---|
appspec.yml | Drives CodeDeploy's deployment lifecycle, not build commands |
| A Dockerfile alone | Defines the container image, not the CI orchestration (install/test/package) around it — buildspec still typically invokes it |
template.yaml | A SAM/CloudFormation template — infrastructure definition, unrelated to build phase commands |
Configure CodeDeploy automatic rollback on the deployment group (on deployment failure and/or CloudWatch alarm threshold breach)
| Distractor | Why it's wrong |
|---|---|
| Manually redeploy the previous revision | Works, but requires human action — the requirement is explicitly automatic |
| Rely on CloudFormation stack rollback | CloudFormation rolls back infrastructure stack changes, not an application revision deployed via CodeDeploy |
| Auto Scaling health check instance replacement | Replaces an unhealthy instance with a fresh one running the SAME (bad) revision — doesn't restore the previous app version |
Configure the CodeBuild project with a VPC configuration (VPC, private subnets, security group) so build containers launch inside the VPC
| Distractor | Why it's wrong |
|---|---|
| Make the RDS instance publicly accessible | Security anti-pattern — exposes the database unnecessarily |
| Switch the build to run inside a Lambda function | Doesn't solve networking and abandons CodeBuild's build tooling for no reason |
| "VPN into" the CodeBuild service | Not a real CodeBuild capability — VPC configuration is the actual mechanism |
Grant the CodePipeline service role iam:PassRole permission scoped to the CodeDeploy service role's ARN
| Distractor | Why it's wrong |
|---|---|
| Attach an AdministratorAccess policy to the pipeline role | Solves the symptom by violating least privilege — not the correct fix |
| Create a cross-account trust policy | Unnecessary when both roles are in the same account, which is the default/common case |
| Add a resource-based policy to the CodeDeploy application | CodeDeploy applications don't use resource-based policies for this hand-off — iam:PassRole on the role itself is the mechanism |
| Mechanism | How it works | When it applies |
|---|---|---|
| EventBridge (push) | A source-provider change event — a CodeCommit "Repository State Change" event, or a webhook from GitHub/Bitbucket/GitLab forwarded through CodeConnections — triggers a pipeline execution within seconds | Default/recommended when the pipeline source is created via the console for CodeCommit or a CodeConnections-based provider |
| Polling (pull) | CodePipeline periodically checks the source location for changes on a fixed interval | Legacy behavior, or a fallback when an EventBridge rule isn't configured — higher latency and unnecessary API calls compared to push-based triggering |
"Trigger the pipeline immediately/near real-time when code changes" is a strong signal the expected answer involves EventBridge, not polling. Polling is the thing to move away from, not the thing to configure for a "fast" requirement.
imagedefinitions.json referencing the ECR image URI for the ECS deploy actioniam:PassRole hand-offs between thembuildspec.yml's env block for credentials/configAWS::Serverless::Function resource can declare AutoPublishAlias + a DeploymentPreference to get CodeDeploy-style Lambda traffic shifting declared entirely as codebuildspec.yml — install pulls build tooling, pre_build logs in to ECR, build runs docker build and the unit test suite, post_build tags and pushes the image to ECR and writes an imagedefinitions.json output artifact referencing the new image URI.appspec.yml, registers a new task set behind the ALB's test target group, validates it, then shifts production traffic according to CodeDeployDefault.ECSLinear10PercentEvery1Minutes.See also: 08 — Cross-Service Architectures for this pattern drawn out end to end alongside four other realistic architectures.
buildspec.yml — never hardcode themAutoPublishAlias + DeploymentPreference instead of configuring CodeDeploy separatelysam deploy or a direct console update can be the lower-overhead answer| Aspect | CodeBuild | CodeDeploy |
|---|---|---|
| Purpose | Compiles source, runs tests, produces an artifact | Rolls an already-built revision onto target compute |
| Config file | buildspec.yml | appspec.yml |
| Typical pipeline stage | Build / Test | Deploy |
| Where it executes | Ephemeral managed build container | The target compute itself — EC2/On-Premises, Lambda, or ECS |
| Failure behavior | Build/test failure fails the pipeline stage — nothing is deployed | Deployment failure can trigger automatic rollback if configured |
| Aspect | CodePipeline | CodeDeploy |
|---|---|---|
| Purpose | Orchestrates the entire release workflow across stages/services | Executes the specific deployment step onto compute |
| Scope | End-to-end: Source → Build → Test → Deploy → Approval | Just the deploy action — one stage's worth of work |
| Can operate standalone? | Not meaningfully — a pipeline with no actions does nothing | Yes — can be invoked directly via console/CLI/API without CodePipeline |
| Deployment type | Supported targets | Mechanism | Rollback speed |
|---|---|---|---|
| In-place | EC2/On-Premises only | Same instances: app stopped → new revision installed → app restarted → validated | Slower — the previous revision must be redeployed through the same process |
| Blue/Green | EC2/On-Premises (replacement ASG/fleet), Lambda (alias traffic weighting), ECS (task set + target group swap) | New environment/version stood up alongside the old one; traffic shifted gradually or all at once; old one retained briefly then removed | Fast — simply route traffic back to the still-running original environment |
| Misconception | Reality |
|---|---|
| "CodeCommit is the standard Git source for a new pipeline" | Deprecated for new customers since July 25, 2024 — use GitHub/Bitbucket/GitLab via CodeConnections |
| "CodeStar is a current AWS best-practice service" | Deprecated and retired — legacy exam trivia only, never the "set this up today" answer |
| "CodeStar Connections/CodeConnections is also deprecated because it has 'CodeStar' in its old name" | The connection mechanism is current and actively recommended — only the CodeStar project-template product is deprecated |
"buildspec.yml belongs to CodeDeploy" | buildspec.yml = CodeBuild; appspec.yml = CodeDeploy |
| "All CodeDeploy deployments support blue/green" | Only EC2/On-Premises, Lambda, and ECS; in-place is EC2/On-Premises only, and blue/green means a different mechanism on each platform |
| "CodePipeline triggers instantly by default no matter the source" | The modern push/EventBridge trigger is the recommended setup, but polling is still a legacy fallback mode with real latency |
| "CodeDeploy needs an agent for every compute platform" | The CodeDeploy agent is required only for EC2/On-Premises — not for Lambda or ECS deployments |
| "A failed deployment rolls back automatically by default" | Automatic rollback must be explicitly enabled on the deployment group (on failure and/or alarm) |
| Service | What it actually answers |
|---|---|
| CodePipeline vs CodeBuild | CodePipeline = orchestrates the whole release workflow. CodeBuild = does the actual compiling/testing inside one stage |
| CodePipeline vs CodeDeploy | CodePipeline = the workflow container. CodeDeploy = the deploy action's execution engine, and can run independently of CodePipeline entirely |
| CodeCommit vs CodeConnections | CodeCommit = AWS-hosted Git repo (deprecated for new customers). CodeConnections = the integration bridge to an externally-hosted Git provider (current, active) |
| CodeDeploy vs CloudFormation deploy actions | CodeDeploy = rolls an app revision onto existing compute with lifecycle hooks and traffic shifting. CloudFormation deploy action = creates/updates infrastructure (the stack itself) as part of a pipeline |
| CodePipeline vs Elastic Beanstalk's built-in deployment | Elastic Beanstalk can deploy new application versions on its own (rolling/immutable/blue-green via environment swap) without CodePipeline at all — CodePipeline is used to automate triggering and orchestrating that from source control |
| CodeStar (product) vs AWS CodeCatalyst | CodeCatalyst is AWS's newer, actively developed unified software-delivery service — a more current analogue to what CodeStar once tried to be. Not in scope for DVA-C02, but useful context for why CodeStar was retired |
Two guided, self-contained exercises run with the AWS CLI v2 against resources in eu-west-1. Both use a fictional theodore-dva-lab naming convention and assume an ECS cluster, service, task definition, and an Application Load Balancer with two target groups (blue/green) already exist — see 01 — Containers if you need to stand those up first. The point isn't the ECS plumbing — it's wiring CodePipeline/CodeBuild/CodeDeploy together correctly, and then deliberately breaking that wiring the exact way the exam loves to test. Source is GitHub via AWS CodeConnections throughout — never CodeCommit, consistent with the rest of this guide.
Build a complete pipeline: a GitHub push, authenticated via AWS CodeConnections, triggers a CodeBuild image build, and CodeDeploy rolls the result onto an ECS service using a blue/green traffic shift.
aws codeconnections create-connection \ --provider-type GitHub \ --connection-name theodore-dva-lab-gh \ --region eu-west-1Returns a ConnectionArn with ConnectionStatus "PENDING".
aws codeconnections get-connection --connection-arn <arn> --region eu-west-1.
aws ecr create-repository \ --repository-name theodore-dva-lab \ --image-scanning-configuration scanOnPush=true \ --region eu-west-1
repositoryUri returned, e.g. 111122223333.dkr.ecr.eu-west-1.amazonaws.com/theodore-dva-lab.
buildspec.yml at the repo root — install/pre_build/build/post_build only, no deploy logic.
version: 0.2
phases:
install:
runtime-versions:
nodejs: 18
pre_build:
commands:
- echo Logging in to ECR...
- aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin $ECR_REPO_URI
- IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c1-7)
build:
commands:
- echo Building image...
- docker build -t $ECR_REPO_URI:$IMAGE_TAG .
post_build:
commands:
- echo Pushing image...
- docker push $ECR_REPO_URI:$IMAGE_TAG
- printf '[{"name":"theodore-dva-lab-container","imageUri":"%s"}]' "$ECR_REPO_URI:$IMAGE_TAG" > imagedefinitions.json
artifacts:
files:
- imagedefinitions.json
- appspec.yaml
- taskdef.json
A buildspec.yml exists that only installs, builds, and packages — it produces artifacts but never touches ECS directly.
appspec.yaml at the repo root — this is CodeDeploy's file, not CodeBuild's, and it is never referenced by anything inside the build container.
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: <TASK_DEFINITION_ARN>
LoadBalancerInfo:
ContainerName: "theodore-dva-lab-container"
ContainerPort: 80
appspec.yaml committed alongside buildspec.yml, but conceptually owned by a completely different service.
aws codebuild create-project \ --name theodore-dva-lab-build \ --source type=CODEPIPELINE,buildspec=buildspec.yml \ --artifacts type=CODEPIPELINE \ --environment type=LINUX_CONTAINER,image=aws/codebuild/amazonlinux2-x86_64-standard:5.0,computeType=BUILD_GENERAL1_SMALL,privilegedMode=true \ --service-role arn:aws:iam::111122223333:role/theodore-dva-lab-codebuild-role \ --region eu-west-1Project ARN returned;
privilegedMode=true is required because the build runs docker build/docker push.
aws deploy create-application \
--application-name theodore-dva-lab-app \
--compute-platform ECS \
--region eu-west-1
aws deploy create-deployment-group \
--application-name theodore-dva-lab-app \
--deployment-group-name theodore-dva-lab-dg \
--deployment-config-name CodeDeployDefault.ECSLinear10PercentEvery1Minutes \
--service-role-arn arn:aws:iam::111122223333:role/theodore-dva-lab-codedeploy-role \
--ecs-services serviceName=theodore-dva-lab-svc,clusterName=theodore-dva-lab-cluster \
--load-balancer-info targetGroupPairInfoList="[{targetGroups=[{name=theodore-dva-lab-tg-blue},{name=theodore-dva-lab-tg-green}],prodTrafficRoute={listenerArns=[arn:aws:elasticloadbalancing:eu-west-1:111122223333:listener/app/theodore-dva-lab-alb/1234567890abcdef/abcdef1234567890]}}]" \
--auto-rollback-configuration enabled=true,events=DEPLOYMENT_FAILURE \
--region eu-west-1
Deployment group created with a blue/green deployment type implied by the ECS + load-balancer-info combination, and automatic rollback enabled on deployment failure.
pipeline.json, then create it.
{
"pipeline": {
"name": "theodore-dva-lab-pipeline",
"roleArn": "arn:aws:iam::111122223333:role/theodore-dva-lab-codepipeline-role",
"artifactStore": { "type": "S3", "location": "theodore-dva-lab-artifacts-eu-west-1" },
"stages": [
{ "name": "Source", "actions": [{
"name": "GitHub_Source",
"actionTypeId": { "category": "Source", "owner": "AWS", "provider": "CodeStarSourceConnection", "version": "1" },
"configuration": {
"ConnectionArn": "arn:aws:codeconnections:eu-west-1:111122223333:connection/CONNECTION_ID",
"FullRepositoryId": "your-org/theodore-dva-lab",
"BranchName": "main"
},
"outputArtifacts": [{ "name": "SourceOutput" }]
}]},
{ "name": "Build", "actions": [{
"name": "CodeBuild_Build",
"actionTypeId": { "category": "Build", "owner": "AWS", "provider": "CodeBuild", "version": "1" },
"configuration": { "ProjectName": "theodore-dva-lab-build" },
"inputArtifacts": [{ "name": "SourceOutput" }],
"outputArtifacts": [{ "name": "BuildOutput" }]
}]},
{ "name": "Deploy", "actions": [{
"name": "CodeDeploy_ECS",
"actionTypeId": { "category": "Deploy", "owner": "AWS", "provider": "CodeDeployToECS", "version": "1" },
"configuration": {
"ApplicationName": "theodore-dva-lab-app",
"DeploymentGroupName": "theodore-dva-lab-dg",
"TaskDefinitionTemplateArtifact": "BuildOutput",
"AppSpecTemplateArtifact": "BuildOutput",
"Image1ArtifactName": "BuildOutput",
"Image1ContainerName": "IMAGE1_NAME"
},
"inputArtifacts": [{ "name": "BuildOutput" }]
}]}
]
}
}
aws codepipeline create-pipeline --cli-input-json file://pipeline.json --region eu-west-1Pipeline created; its first execution starts automatically, pulling the current GitHub branch HEAD as the Source artifact.
aws codepipeline get-pipeline-state --name theodore-dva-lab-pipeline --region eu-west-1Source, Build, and Deploy stages all report
latestExecution.status = "Succeeded"; the ECS console briefly shows two task sets (blue and green) before settling on green at 100% traffic.
buildspec.yml never mentions ECS, the load balancer, or traffic shifting — it only installs, builds, and packages, then hands off an imagedefinitions.json/appspec.yaml/taskdef.json bundle as its output artifact. Everything about how the new revision reaches production — the blue/green shift, the target-group swap, the rollback trigger — lives in appspec.yaml and the CodeDeploy deployment group, not in the build. The exam repeatedly tests this exact boundary: which file, and which service, owns which responsibility.
Reproduce the classic trap this guide warns about elsewhere: deploy logic accidentally living inside buildspec.yml's post_build phase instead of being handled by CodeDeploy. This is one of the most common real-world — and exam — misconfigurations.
buildspec.yml: add a direct ECS update to post_build, and stop producing the artifacts CodeDeploy needs.
post_build:
commands:
- echo Pushing image...
- docker push $ECR_REPO_URI:$IMAGE_TAG
- echo Deploying directly from the build...
- aws ecs update-service \
--cluster theodore-dva-lab-cluster \
--service theodore-dva-lab-svc \
--force-new-deployment \
--region eu-west-1
artifacts:
files:
- imagedefinitions.json
buildspec.yml now performs a deployment itself and no longer packages appspec.yaml/taskdef.json as output artifacts.
git add buildspec.yml git commit -m "break: deploy from buildspec post_build" git push aws codepipeline get-pipeline-state --name theodore-dva-lab-pipeline --region eu-west-1The Build stage reports "Succeeded" — the ECS service actually starts a plain rolling update triggered from inside CodeBuild — but the Deploy stage (the
CodeDeployToECS action) fails.
aws codepipeline get-pipeline-state --name theodore-dva-lab-pipeline --region eu-west-1 \ --query "stageStates[?stageName=='Deploy']" aws deploy list-deployments \ --application-name theodore-dva-lab-app \ --deployment-group-name theodore-dva-lab-dg \ --region eu-west-1 aws deploy get-deployment --deployment-id <id-from-above> --region eu-west-1The Deploy action fails because CodeDeploy can't find the
appspec.yaml/taskdef.json it expects in the build's output artifact — and separately, ECS shows the service was already force-updated by CodeBuild, bypassing blue/green entirely, so that release never had a controlled traffic shift or an alarm-based rollback safety net.
buildspec.yml to only build/package (drop the aws ecs update-service call, restore appspec.yaml/taskdef.json to the artifacts list), then re-run the pipeline.
git revert HEAD git push aws codepipeline start-pipeline-execution --name theodore-dva-lab-pipeline --region eu-west-1The Deploy stage now succeeds via
CodeDeployToECS, performing a proper blue/green shift with alarm-backed automatic rollback available — confirm with aws deploy get-deployment --deployment-id <new-id> --region eu-west-1 showing status: "Succeeded" and deploymentType: "BLUE_GREEN".
Putting deploy logic in post_build "works" in the sense that the ECS service does update — which is exactly what makes it a dangerous, exam-favorite distractor. It silently discards everything CodeDeploy was providing: gradual blue/green traffic shifting, lifecycle hooks like AfterAllowTestTraffic, and alarm-based automatic rollback. A question describing "the deployment updates the service but there's no gradual traffic shift and no automatic rollback" is almost always describing this exact misconfiguration — deploy logic that belongs in appspec.yaml/CodeDeploy was instead written into buildspec.yml/CodeBuild.
Click card to flip. Mark right or wrong to track score.
DVA-C02 scenario style, Easy → Specialty. Select an answer to reveal the explanation.