Back to Blog
DevOps Docker GitHub Actions AWS

From 5 Days to 30 Minutes: Automating CI/CD with Docker and GitHub Actions

Before: The 5-Day Deployment

Early in the project, deploying a release meant: manually building the JAR, SSHing into the EC2 instance, stopping the service, uploading the file, restarting — and repeating for each environment. A single production deploy with testing took the better part of a week.

This is not sustainable.

The Setup

The automated pipeline I settled on has three stages:

1. Build and Test (on every push)

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 21
        uses: actions/setup-java@v3
        with:
          java-version: '21'
      - name: Build with Maven
        run: mvn clean package
      - name: Run tests
        run: mvn test

2. Docker Build and Push

On merge to main, the workflow builds a Docker image and pushes it to Amazon ECR:

  - name: Build Docker image
    run: docker build -t my-app:${{ github.sha }} .
  - name: Push to ECR
    run: |
      aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_URI
      docker push $ECR_URI/my-app:${{ github.sha }}

3. Deploy to EC2

The final step SSH's into EC2, pulls the new image, and does a zero-downtime swap using Docker Compose:

  - name: Deploy
    run: |
      ssh ec2-user@$EC2_HOST "
        docker pull $ECR_URI/my-app:${{ github.sha }} &&
        docker compose up -d --no-deps app
      "

Lessons Learned

  • Secrets management: Store all credentials in GitHub Actions secrets, never hardcode. Use AWS IAM roles with the minimum required permissions.
  • Health checks: Add a Docker health check so Compose won't route traffic to a container that hasn't finished starting.
  • Rollback: Tag images by commit SHA so you can roll back instantly by redeploying the previous tag.

Result

Total deploy time: under 30 minutes, fully automated, with tests as a gate. The mental overhead of deployments dropped to essentially zero.