Building and storing images in ECR
Before you can deploy a container to EKS or ECS, the image must live somewhere the cluster can pull it from — a container registry. On AWS that is ECR (Elastic Container Registry). This lesson is building images in the pipeline and storing them in ECR properly: tagging, scanning, lifecycle policies, and the multi-arch builds that let you run on cheaper Graviton. It builds on the containers module (Dockerfiles, image tags) and the pipeline-design lesson.
ECR: your private image registry
Amazon ECR is a private container registry integrated with AWS. Your pipeline builds an image and pushes it to an ECR repository; your EKS nodes or ECS tasks pull it from there to run it. An image's full name in ECR looks like:
123456789012.dkr.ecr.eu-west-1.amazonaws.com/greetings:a1b2c3d
└── account ──┘ └─ region ─┘ └ repo ┘ └ tag ┘
Two AWS-specific points:
- Access is via IAM. Pushing and pulling from ECR is controlled by IAM permissions (the IAM lesson) — the pipeline's deploy role can push; the EKS node role or pod (via IRSA) can pull. No registry password to manage; it is all IAM and temporary credentials (the keyless pattern).
- Authentication is a token. To push, the pipeline authenticates to ECR with a short-lived token, obtained from its assumed role:
- uses: aws-actions/amazon-ecr-login@v2 # gets a short-lived ECR auth token via the assumed role
- run: |
docker build -t $ECR/greetings:${{ github.sha }} .
docker push $ECR/greetings:${{ github.sha }}
So building and pushing is: build the image (the containers module's Dockerfile), authenticate to ECR with the role's token, and push the commit-tagged image. The cluster then pulls that exact image to deploy it.
Tag by commit, never rely on latest
The tagging discipline from the containers module matters even more in a pipeline: tag each image with the
commit SHA (or a version), not latest.
- A commit-SHA tag (
greetings:a1b2c3d) is immutable and traceable — you know exactly which code is in it, you deploy that exact version, and rollback means redeploying a specific known-good SHA (the rollback lesson). latestis ambiguous — it moves with every build, so you can never be sure which code a runninglatestcontains, and rollback becomes guesswork. Deployinglatestto production is a classic mistake.
Enforce immutable tags on the ECR repository (a setting that prevents overwriting an existing tag), so a given SHA tag always refers to the exact image that was built for that commit — nobody can push a different image over it. Immutable, commit-tagged images are the basis of traceable, reversible deployments.
Image scanning: catch vulnerabilities
ECR can scan images for vulnerabilities — checking the OS packages and libraries in your image against known CVE databases. This is a security practice worth building into the pipeline:
- Enable scan-on-push so every image is scanned as it arrives in ECR, and you learn about vulnerable dependencies before deploying.
- Act on the findings — a critical vulnerability in a base image or dependency is a signal to update (rebuild on a patched base — the containers module's small, current base images help here). You can gate the pipeline on scan results for critical issues.
- This complements the small-image discipline (the containers module): a smaller image has fewer packages, so fewer vulnerabilities to scan and patch. Minimal base images and scanning together keep your deployed images secure.
Scanning turns "we hope our image is not vulnerable" into "we check every image and act on what we find" — a basic supply-chain security practice.
Lifecycle policies: don't let images pile up (and cost)
Every build pushes a new image, so an ECR repository accumulates images fast — and stored images cost money (the cost concern this course keeps front of mind). Lifecycle policies automatically clean up old images:
- A policy like "keep the last 20 images, expire older untagged images" removes images you no longer need (old commits' builds), keeping the repository — and its cost — bounded.
- Keep enough history to roll back to recent versions (you need old images to roll back to them — the rollback lesson), but not every image ever built.
Without a lifecycle policy, an ECR repository grows without limit, storing thousands of images from every build, quietly costing money — the same "deployment storage piles up" problem in registry form. A lifecycle policy is the standard, cheap fix: set it once and old images are pruned automatically.
Multi-arch images for Graviton
One build detail that connects to the cost module: to run on Graviton (ARM) instances for their ~20%
saving (the cost-of-compute lesson), your image must be built for ARM64. In the pipeline you build a
multi-arch image (both amd64 and arm64) with Docker Buildx, or build specifically for arm64 if all
your nodes are Graviton:
- uses: docker/setup-buildx-action@v3
- run: docker buildx build --platform linux/amd64,linux/arm64 -t $ECR/greetings:${{ github.sha }} --push .
A multi-arch image runs on both x86 and Graviton nodes, so you can adopt Graviton (and its saving) without maintaining separate images. Building multi-arch (or ARM) images in the pipeline is what makes the compute module's Graviton advice practical.
Check your work
ECR = private AWS registry; pipeline pushes, cluster pulls. Image name =
account.dkr.ecr.region.amazonaws.com/repo:tag. Access via IAM (deploy role pushes; node/IRSA pulls — no
registry password); auth is a short-lived token (amazon-ecr-login via the assumed role).
Tag by commit, not latest: SHA tags are immutable/traceable (know the code, deploy exact, roll back to a
SHA); latest is ambiguous (rollback = guesswork). Enable immutable tags so a SHA always means that exact
image.
Scanning: enable scan-on-push (checks packages against CVEs), act on findings (rebuild on a patched base; gate on critical), complemented by small base images (fewer packages/vulns). Check every image.
Lifecycle policies: builds accumulate images (storage cost); a policy ("keep last N, expire old untagged") prunes automatically — keep enough to roll back, not everything. Without one, the repo grows unbounded (registry version of the deployment-storage problem).
Multi-arch for Graviton: build amd64,arm64 (Buildx) so the image runs on Graviton (~20% cheaper) as well
as x86 — makes the compute module's Graviton advice practical.
Practice
- Explain what ECR is, how the pipeline authenticates to it, and how the cluster pulls from it.
- Explain why you tag images by commit SHA and enable immutable tags, versus using
latest. - Explain scan-on-push and how it, plus small base images, keeps deployed images secure.
- Explain what an ECR lifecycle policy does and why it is needed, relating it to cost.
- Explain why a multi-arch (or ARM) image build is needed to run on Graviton, and how it enables the saving.
- Write the pipeline steps to authenticate to ECR, build a commit-tagged image, and push it.
Official documentation
- AWS — Amazon ECR user guide — Private registries, push/pull and IAM access.
- AWS — ECR image scanning — Scanning images for vulnerabilities.
- AWS — ECR lifecycle policies — Pruning old images automatically.
Next: deploying to EKS from CI.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship