CD: from main to running tasks
After this you can answer: What happens, job by job, after a merge to main?
Picture it
Section titled “Picture it”flowchart TB CI["CI green on main"] --> P["publish<br/>build 3 ARM64 images :sha<br/>push to ECR"] P --> A{"approval<br/>(environment dev)"} A --> D["deploy<br/>guard → phase A → migrate → phase B"] D --> C["check revisions,<br/>smoke test, record commit"]How it works
Section titled “How it works”- Start.
workflow_runfires when CI completes on main. Both jobs check that CI succeeded and that it ran for a push. - publish checks out exactly the commit CI tested. The tag is its 7-character SHA. It logs in with the publish role, skips images that already exist (tags are immutable), and builds the rest for ARM64 on an ARM runner.
- deploy runs in GitHub environment
dev. A required reviewer configured there makes it wait for a person to click Approve. - deploy logs in with the deploy role, runs the deploy guard, checks the tag exists in all three repositories, and refuses committed image-tag overrides.
- Then the two phases (next chapters): infrastructure and migration first, the new app version second, then checks.
In MiniTickets
Section titled “In MiniTickets”Build once, promote: deploy never builds. It runs the exact bytes publish pushed, so what was scanned and tested is what runs.
Concurrency permits one publish per commit and one uncancelled deploy per environment. GitHub keeps at most one waiting run.
A manual run (“Run workflow”) has two inputs. With image_tag set, publish is skipped and that
existing image is deployed: a redeploy or an app rollback. With allow_older_infra, the guard lets
older infrastructure code through, on purpose.
The owner will restrict dev to main in GitHub. Prevent self-review stays OFF because there
is one reviewer. Teams use a second person to approve production deploys. OIDC’s environment
subject does not identify a branch.
| From → to | What happens | What allows it |
|---|---|---|
| CI workflow → CD publish job | CD starts after CI finished on main |
|
| CD publish job → CD deploy job | deploy runs after publish; waits for approval when environment dev has a required reviewer |
|
| CD publish job → GitHub publish role | swaps its GitHub OIDC token for 1-hour AWS credentials |
|
| CD publish job → ECR repositories | docker push api, web and worker :<git sha> |
|
See it in AWS
Section titled “See it in AWS”GitHub → Actions → CD → a run → job deploy → Review deployments. In AWS: ECR → the repositories → images tagged with the SHA.
gh run list --workflow CD --limit 5
Break it
Section titled “Break it”| Symptom | Cause | Where to look |
|---|---|---|
| “Not authorized to perform sts:AssumeRoleWithWebIdentity” | The token’s sub does not match the role’s trust policy | OIDC |
Publish: not authorized for ecr:BatchGetImage on a new repository | The role’s policy reaches AWS only with the next infrastructure apply | The publish role’s policy |
| Deploy stops at “Read the committed config” | An image-tag override is committed in Pulumi.dev.yaml | The step’s error line |
Say it in an interview
Section titled “Say it in an interview”Follow-ups
Section titled “Follow-ups”Why is publish not behind the approval too?
Publishing only stores images; it changes nothing that runs. Publishing before the approval means the deploy starts right after the click.
Why never cancel a running deploy?
A cancelled infrastructure apply or migration can leave AWS half changed. Waiting is safer, and the stack lock stops a second apply anyway.
What is the risk of a single approval click?
The reviewer sees a commit, not its age. That is how an old approved run once deleted newer resources; the deploy guard now refuses it (see rollback and the guard).
Advanced: Details: names and variables
Role ARNs, repository and function names come from GitHub variables, not from the workflow file,
so a new stack needs no edit there. A role ARN is an address, not a password, so it is a variable,
not a secret. The deploy job may run up to 110 minutes; its AWS credentials last 2 hours.
In GitHub → Settings → Environments → dev, choose Selected branches and tags, then add only
the Branch rule main. Keep Prevent self-review unchecked for this solo project. The owner
will make this change; this session did not inspect or apply the live settings. See
GitHub’s environment configuration.
Checkpoint
Section titled “Checkpoint”Answer these without scrolling up. If one feels hard, reread that section.
- What are the two CD jobs, and which one needs approval?
- What is the image tag?
- What does “build once, promote” mean here?
- What does a manual run with
image_tagdo? - Why is the deploy never cancelled by a newer run?
Redraw it from memory: CI green → publish (3 ARM64 images :sha → ECR) → approval → deploy (guard, phase A, migrate, phase B, checks)
Try this: on the map, play the deploy flow and stop at the approval step
Read this book online: https://book.theversehub.in/