Setting up a Rails Build on AWS CodeBuild
With Continuous Delivery, you want to ensure all automated tests pass prior to deploying the code to a Dev or Test environment. If your code is already deploying to AWS, e.g. EC2 or Elastic Beanstalk, then a great option is to keep everything in-house and build your code with AWS CodeBuild.
This post will walk you through setting up a Ruby on Rails CodeBuild project which runs a suite of RSpec tests.
1) Create a Docker Image for the Build Environment
You want to ensure that the build environment matches the environment where the code is deployed to. CodeBuild provides images for various Ruby environments:
But most likely these will not match your environment completely. For example, you might be using Ruby 2.4.0. We can customize one of these images– changing the ruby version to match our environment and installing PostgreSQL– by cloning the AWS Github repo where the image definitions, i.e. Dockerfiles, are stored:
git clone https://github.com/aws/aws-codebuild-docker-images.git
Then updating one of the Ruby image definitions to match the build environment. I choose to update
ubuntu/ruby/2.5.1/Dockerfile, changing the Ruby version to 2.4.0 and installing Postgres:
ENV RUBY_MAJOR="2.4" \ RUBY_VERSION="2.4.0" \ RUBY_DOWNLOAD_SHA256="152fd0bd15a90b4a18213448f485d4b53e9f7662e1508190aa5b702446b29e3d" \ RUBYGEMS_VERSION="2.7.2" \ BUNDLER_VERSION="1.16.1" \ GEM_HOME="/usr/local/bundle" # Download and install Postgres RUN set -ex \ && sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' \ && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - \ && apt-get update -qq && apt-get install -y postgresql-9.4
You can then build your modified AWS CodeBuild Docker Image locally by running:
# cd into dir if not already there cd aws-codebuild-docker-images/ubuntu/ruby/2.5.1 docker build -t my-codebuild-image .
Here is the complete customized image described above.
2) Deploy the Custom Image to AWS ECR
AWS ECR is the place to store your custom built image on AWS. Assuming the AWS CLI is installed you can run the following commands:
# create ECR repo, which will return repositoryUri aws ecr create-repository --repository-name codebuild-images # tag docker image with the repository URI docker tag my-codebuild-imag aws_account_id.dkr.ecr.us-east-1.amazonaws.com/codebuild-images # login to ECR aws ecr get-login --no-include-email # push image to ECR docker push aws_account_id.dkr.ecr.us-east-1.amazonaws.com/codebuild-images
This Docker Basics for Amazon ECR Guide is a great resource for this step.
3) Set up CodeBuild Using the Custom Image
After uploading the custom image to ECR, when creating a new CodeBuild project, your custom image will be selectable under the Environment section:
4) Add buildspec.yml to the Code Source
The buildspec.yml file describes how CodeBuild should perform the build. For a Ruby on Rails app using a Postgres data source and RSpec, it should look something like:
version: 0.1 phases: install: commands: - echo Starting postgresql... - service postgresql restart - echo Installing Bundler... - gem install bundler - bundle install --with test pre_build: commands: - echo Preparing database to run tests... - cp config/database.yml.example config/database.yml - RAILS_ENV=test bundle exec rake db:setup - RAILS_ENV=test bundle exec rake db:migrate build: commands: - echo Running rspec tests... - bundle exec rspec spec/
Commit it to your source repository on the branch that is being built.
5) Verify the build succeeds!
After adding buildspec.yml and saving the CodeDeploy project settings with the custom image, you should be able to run a build which checks out the source and verifies all the RSpec tests pass:
A Tip for Debugging buildspec.yml
If you are debugging your buildspec.yml or test setup, it can be faster and easier to run the image locally, mounting the source code volume (instead of constantly pushing an update to the source repository and running a build within CodeBuild). To do this, you can use commands like:
# run the image locally, making the source repo available within the running image docker run -v /Users/jonbake/Code/git/my-code-repo:/home/my-code-repo -it --entrypoint sh my-codebuild-image -c bash # within image cd into mounted directory and run build spec steps to verify they succeed cd /home/my-code-repo service postgresql restart # ...