YC
AWS CLOUD & DEVOPS LAB · CONTINUOUS INTEGRATION

Automated Container Image Pipeline: GitHub Actions to Amazon ECR

A continuous integration pipeline that automates Docker container image compilation, ephemeral health check validation, and versioned artifact delivery to Amazon Elastic Container Registry (ECR) in ap-south-1. Eliminates manual workstation builds while enforcing dual-tag release hygiene.

PIPELINE RUNNERGitHub Actionsubuntu-latest Host
TARGET REGISTRYAmazon ECR (ecr-test)ap-south-1 · Private Repo
IMAGE FOOTPRINT~28.8 MB (Alpine)nginx:alpine Base
TAGGING SCHEMEGit SHA + latestImmutable Traceability
01. CONTEXT & MOTIVATION

Why Automate Container Delivery? Overcoming Workstation Friction

When developers start working with Docker, the initial habit is to build and push images directly from a local workstation using terminal commands:

$ docker build -t my-app . && docker tag my-app 123456789.dkr.ecr... && docker push ...

While fine for rapid experimentation, manual publishing from developer laptops introduces systemic failure modes:

  • Architecture Discrepancies: Building on an Apple Silicon Mac (ARM64) produces containers that fail when pulled onto standard x86_64 cloud servers unless multi-arch flags are meticulously configured.
  • Uncommitted Drift: Images pushed from dirty local git trees contain uncommitted code, unstaged configuration files, or temporary secrets that do not exist in the canonical repository.
  • Untracked Releases: Tagging manually as v1 or latest severs the audit trail between the running container and the specific Git commit that produced it.
  • Secret Sprawl: Storing long-lived cloud credentials across multiple laptops increases the surface area for credential leaks.

This project codified an automated delivery pipeline: turning every Git push to the canonical repository into a reproducible build that verifies container health before publishing immutable, traceable container artifacts to Amazon ECR.

02. PIPELINE ARCHITECTURE & FLOW

End-to-End Delivery Flow: Code to Amazon ECR

The automated pipeline enforces a linear, five-stage execution graph inside an ephemeral Ubuntu runner:

// VERIFIED CI PIPELINE GRAPH (GitHub Actions → Amazon ECR)
+-------------------------------------------------------------+
|  Developer Workstation                                      |
|  - VS Code edit (index.html / Dockerfile)                   |
|  - git commit -m "feat: release UI v2.0 ..." (SHA: 31fb54b) |
|  - git push origin main                                     |
+-----------------------------+-------------------------------+
                              |
                              | 1. Webhook Event
                              v
+-------------------------------------------------------------+
|  GitHub Actions Workflow (.github/workflows/docker-ci.yml)  |
|  Runner: ubuntu-latest                                      |
|  Job: build-and-push                                        |
+-----------------------------+-------------------------------+
                              |
    +-------------------------+-------------------------+
    | 2. actions/checkout@v4                            |
    |    Clones repository into runner workspace        |
    +-------------------------+-------------------------+
                              |
    +-------------------------+-------------------------+
    | 3. aws-actions/configure-aws-credentials@v4       |
    |    Injects AWS_ACCESS_KEY_ID & SECRET_ACCESS_KEY  |
    |    Sets AWS_REGION to ap-south-1                  |
    +-------------------------+-------------------------+
                              |
    +-------------------------+-------------------------+
    | 4. aws-actions/amazon-ecr-login@v2                |
    |    Obtains short-lived Docker login authorization |
    |    Outputs ECR_REGISTRY URL                       |
    +-------------------------+-------------------------+
                              |
    +-------------------------+-------------------------+
    | 5. Pre-Push Validation Step                       |
    |    - docker build -t test-frontend:local .        |
    |    - docker run -d -p 8080:80 test-app            |
    |    - curl --fail http://localhost:8080 (Assert OK)|
    |    - docker stop && docker rm test-app            |
    +-------------------------+-------------------------+
                              |
    +-------------------------+-------------------------+
    | 6. Production Build & Dual-Tag Push               |
    |    - Tag 1: ${ECR_REGISTRY}/ecr-test:${github.sha}   |
    |    - Tag 2: ${ECR_REGISTRY}/ecr-test:latest      |
    |    - docker push (both tags)                      |
    +-------------------------+-------------------------+
                              |
                              v
+-------------------------------------------------------------+
|  Amazon Elastic Container Registry (ECR)                    |
|  Region: ap-south-1 | Repository: ecr-test                  |
|  Registry ID: 205639151266                                  |
|  - Artifact: 28.79 MB Nginx Alpine Container Image         |
|  - Tags: 31fb54b978d... + latest (sha256 digest verified)  |
+-------------------------------------------------------------+
03. TECHNICAL IMPLEMENTATION & SOURCE ARTIFACTS

Source Code, Workflow Definition & Infrastructure as Code

The entire pipeline is open-source and defined across three files in the public repository chaudharyo7/Devops-Demo↗:

WORKFLOW CONFIGURATION: .github/workflows/docker-ci.ymlGitHub Actions YAML
name: Deploy to Amazon ECR

on:
  push:
    branches: [ "main" ]
  workflow_dispatch:

env:
  AWS_REGION: ap-south-1
  ECR_REPOSITORY: ecr-test

jobs:
  build-and-push:
    runs-on: ubuntu-latest

    steps:
      - name: Check out repository
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Log in to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      # Pre-push validation: verifies container boots and serves HTTP 200
      - name: Test Docker build and health check
        run: |
          docker build -t test-frontend:local .
          docker run -d -p 8080:80 --name test-app test-frontend:local
          sleep 3
          curl --fail http://localhost:8080 || exit 1
          echo "Health check passed!"
          docker stop test-app && docker rm test-app

      # Build and push with dual tagging
      - name: Build, tag, and push image to Amazon ECR
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -t $ECR_REGISTRY/$ECR_REPOSITORY:latest .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
CONTAINER SPECIFICATION: Dockerfile
FROM nginx:alpine

COPY index.html /usr/share/nginx/html/index.html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

Lightweight Alpine base produces a minimal ~28.8 MB image, reducing registry storage costs and network push/pull latency.

REGISTRY PROVISIONING: Terraform/ECR/main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

provider "aws" {
  region = "ap-south-1"
}

resource "aws_ecr_repository" "tf-ecr" {
  name = "ecr-test"
}

Declaratively provisions the private repository ecr-test in AWS region ap-south-1 using the AWS Terraform provider.

04. RECORDING EVIDENCE & DEMONSTRATION

Authentic Screen Recording: Pipeline Execution to ECR Registry

The video below demonstrates the complete pipeline lifecycle, recorded from the local code commit through the GitHub Actions runner execution to the AWS ECR registry console:

0:00 / 0:00
Near-Viewport Autoplay

Authentic recording: VS Code Git commit (31fb54b), push to GitHub, automated workflow trigger in GitHub Actions, container test build & curl validation, layer push to ECR, and AWS ECR console verification with dual tags.

RECORDING BREAKDOWN BY TIMESTAMP:
  • 00:00 – 00:10 (Local Commit & Push): In VS Code, edits to index.html (releasing UI v2.0) and Dockerfile are staged. A terminal commit is executed: git commit -m "feat: release UI v2.0 and trigger automated ECR pipeline" producing commit SHA 31fb54b, which is pushed to remote main.
  • 00:10 – 00:25 (GitHub Actions Trigger): Navigates to the GitHub web interface for repository chaudharyo7/Devops-Demo. The Actions tab immediately detects the push and starts workflow run #2 on the main branch.
  • 00:25 – 00:35 (Build, Health Check & Layer Push): The runner steps through checking out code, configuring AWS credentials, and logging into ECR. It executes the local test container, passes the HTTP health check assertion, builds the production tags, and pushes layers to 205639151266.dkr.ecr.ap-south-1.amazonaws.com/ecr-test.
  • 00:35 – 00:42 (AWS ECR Console Verification): Switches to the AWS Management Console in ap-south-1. Opens private repository ecr-test. The newly published image is visible with dual tags (31fb54b... and latest), verified image size of 28.79 MB, and matching SHA256 digest.
05. ARCHITECTURAL BOUNDARY & HONEST DISTINCTION

Image Delivery is Not Application Deployment

CRITICAL ENGINEERING DISTINCTION

In modern cloud architecture, continuous delivery of container artifacts (CI) and runtime deployment orchestration (CD) are two distinct stages with different failure boundaries.

WHAT THIS PIPELINE ACCOMPLISHES:
  • Validates that the Docker image builds cleanly.
  • Executes an ephemeral container health check.
  • Publishes immutable commit-tagged images to ECR.
  • Maintains a verified artifact catalog in ap-south-1.
WHAT DOES NOT HAPPEN AUTOMATICALLY:
  • Does NOT deploy the container to EC2, ECS, or EKS.
  • Does NOT execute zero-downtime rolling updates.
  • Does NOT manage runtime ingress, DNS, or TLS certificates.
  • Does NOT trigger automated canary rollbacks.

By contrast, my Cloud Expense Tracker project takes the next step: using GitHub Actions and AWS Systems Manager (SSM) agent run commands to pull from ECR onto private EC2 instances and execute container restarts without open SSH ports.

06. CHALLENGES & ENGINEERING DECISIONS

Key Decisions & Real-World Trade-Offs

1. Dual Tagging: Git SHA Immutability vs. 'latest' Convenience

Relying exclusively on the mutable latest tag is an anti-pattern in container operations because downstream orchestrators cannot distinguish between consecutive releases or perform rollbacks. Conversely, requiring engineers to manually look up full 40-character commit hashes creates operational friction. Dual tagging publishes both: the Git SHA tag provides strict immutability and auditability, while latest points to the most recent validated build.

2. Ephemeral Health Check Assertion

Simply verifying that docker build exits with code 0 is insufficient. A container can build successfully yet crash loop upon execution due to misconfigured Nginx configs, missing files, or bad runtime syntax. Adding step 4—booting the container locally in the runner, sleeping 3 seconds, and executing curl --fail http://localhost:8080—ensures broken containers fail the pipeline before pushing damaged images to the cloud registry.

3. Credential Management: Secrets vs. OIDC Federation

In this lab pipeline, AWS authentication is established via repository secrets (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) using an IAM user. While functional and common in initial setups, static keys present rotation overhead and leakage risks compared to GitHub Actions OpenID Connect (OIDC) identity federation, which issues short-lived temporary STS credentials.

07. IMPLEMENTATION STATUS & BOUNDARIES

Implementation Status & Honest Technical Boundaries

IMPLEMENTATION STATUS MATRIX
  • Verified & Implemented: Repository Devops-Demo on GitHub; workflow file .github/workflows/docker-ci.yml; Dockerfile packaging Nginx Alpine; pre-push curl health check on port 8080; dual-tagging with commit SHA and latest; private Amazon ECR repository ecr-test in ap-south-1 provisioned via Terraform; verified image delivery (28.79 MB) displayed in the AWS ECR console.
  • Not Implemented / Explicit Scope Boundaries: Authentication relies on IAM user access keys rather than OIDC role assumption; automated image vulnerability scanning (such as Amazon Inspector or Trivy) is not enabled on push; automated downstream container deployment to EC2/ECS/EKS is out of scope.
08. KEY TAKEAWAYS & NEXT STEPS

What Building This Taught Me & Future Improvements

PRACTICAL NEXT STEPS FOR PRODUCTION HARDENING:
  • Migrate to GitHub Actions OIDC: Replace static IAM user access keys with an AWS IAM Role configured with a trust policy for token.actions.githubusercontent.com, eliminating static secrets entirely.
  • Automated Vulnerability Scanning: Integrate Trivy or enable ECR Enhanced Scanning on image push to block promotion when critical CVEs are detected.
  • Multi-Architecture Builds: Use Docker Buildx with QEMU to cross-compile images for both linux/amd64 and linux/arm64 architectures.
  • Downstream GitOps Deployment: Connect successful ECR publications to an AWS ECS service update or an ArgoCD GitOps repository commit to automate deployment without manual intervention.