Introduction
Building a reliable CI CD pipeline for a Rails application on AWS does not require exotic tools. In this article I walk through a straightforward setup that uses GitHub Actions, Docker, and Elastic Beanstalk. The goal is to ship code quickly while keeping the production environment stable.
Choosing the right build environment
Start with a GitHub Actions workflow that runs on the latest Ubuntu runner. Install Ruby, Node, and the required system libraries. A typical step looks like this:
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
- name: Install dependencies
run: |
gem install bundler
bundle install --jobs 4 --retry 3
npm ci
- name: Run tests
run: bundle exec rspec
The workflow installs the exact Ruby version used in production and caches the bundle and node modules to speed up subsequent runs.
Containerizing the application
Docker provides a consistent runtime across development, CI, and production. Create a Dockerfile that mirrors the Elastic Beanstalk platform configuration:
FROM ruby:3.2-slim
RUN apt-get update && apt-get install -y nodejs
WORKDIR /app
COPY Gemfile*./
RUN bundle install --without development test
COPY..
EXPOSE 3000
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
Build the image in the CI workflow and push it to Amazon ECR:
- name: Build Docker image
run: |
docker build -t ${{ secrets.ECR_REPO }}:${{ github.sha }}.
aws ecr get-login-password | docker login --username AWS --password-stdin ${{ secrets.ECR_REGISTRY }}
docker push ${{ secrets.ECR_REPO }}:${{ github.sha }}
Deploying to Elastic Beanstalk
Elastic Beanstalk can pull the image directly from ECR. Define an environment configuration file that sets the image tag based on the Git SHA. The deployment step in the workflow triggers a new application version:
- name: Deploy to Elastic Beanstalk
run: |
aws elasticbeanstalk create-application-version \
--application-name developerz-app \
--version-label ${{ github.sha }} \
--source-bundle S3Bucket=${{ secrets.S3_BUCKET }},S3Key=app.zip
aws elasticbeanstalk update-environment \
--environment-name developerz-prod \
--version-label ${{ github.sha }}
Because the version label is the commit SHA, each deployment is uniquely identifiable.
Monitoring and rollback
Add a health check script that runs after deployment. If the health endpoint returns an error, trigger a rollback to the previous version using the Elastic Beanstalk CLI. This safety net prevents a bad commit from staying live.
- name: Health check
run: |
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://myapp.example.com/health)
if [ $STATUS -ne 200 ]; then
aws elasticbeanstalk update-environment --environment-name developerz-prod --version-label ${{ github.event.before }}
fi
Lessons learned
- Keep the CI environment as close as possible to production. Docker images eliminate “works on my machine” surprises.
- Use the commit SHA as the version identifier. It makes tracing a problem back to a change trivial.
- Automate health checks and rollbacks. A small script can save hours of manual debugging.
Conclusion
A minimal CI CD pipeline built with GitHub Actions, Docker, and Elastic Beanstalk provides fast feedback and reliable deployments for Rails apps on AWS. The setup is inexpensive, scales with traffic, and requires only a few YAML files to maintain. Feel free to adapt the snippets to your own workflow.
Author: senior engineer at developerz.ai
Top comments (0)