Skip to content

Instantly share code, notes, and snippets.

@iEv0lv3
Last active July 30, 2020 19:57
Show Gist options
  • Save iEv0lv3/0d3979312791f6a64440b3d320c0bea8 to your computer and use it in GitHub Desktop.
Save iEv0lv3/0d3979312791f6a64440b3d320c0bea8 to your computer and use it in GitHub Desktop.
CircleCI setup for Rails, PostgreSQL, and Docker app

CircleCI :: Rails

This guide is intended for a Rails application that uses PostgreSQL and is tested, developed, and deployed using Docker. The following link is a setup guide for a Rails + PostgreSQL application using Docker:

https://gist.github.com/iEv0lv3/17e33bc8d3ad4132d317ba5a1cf62d9b

The guide assumes the above Docker + Rails setup is complete. The approach in this guide creates a new Rails environment: staging, and the only responsibility of the staging environment is to be used with CircleCI for CI/CD testing. The environment name can be whatever you'd like, ci, cd, or circleci would all work as environment names as well. Why I prefer this approach is because it allows the use of standard CircleCI environments for the build and test jobs that utilize native CircleCI images for Ruby and PostgreSQL. It also allows for a high degree of customization for CircleCI without affecting Docker test, development, and production deployments.

Completing the entire guide is required to ensure all functionality works as expected, but the primary factor that makes this build work is overwriting the default host: db in config/database.yml

...
# config/database.yml
staging:
  <<: *default
  database: my_app_staging
  host: 127.0.0.1
  

Updating the config/database.yml file with the above code enables CircleCI to use the standard PostgreSQL image: circleci/postgres:12.3, and run it locally on 127.0.0.1. This guide requires Rails 6 in order to use credentials.

There is an alternative approach that creates a Linux environment in the .circleci/config.yml setup using an Ubuntu image, and then adds all necessary dependencies to run Docker and Docker Compose within that environment. The alternative approach allows for the use of docker-compose build to build a test environment in CircleCI, which creates containers based on the project's Dockerfile. The images built from the Dockerfile are used in place of standard images from CircleCI. A standard image configuartion for CircleCI and a Rails app generally includes:

# .circleci/config.yml

docker:
  - image: cimg/ruby:2.7.1-node
  - image: circleci/postgres:12.3

With my current level of Docker knowledge I find the alternative approach to be more cumbersome and prone to errors, but it is a valid solution to use with CircleCI.

Step 1 - Add the rspec_junit_formatter Gem

  • Open Gemfile
    • Add gem ‘rspec_junit_formatter’
  • Result
    • Solves a test formatting error when running RSpec tests

Step 2 - Rails Environment - Add Staging

The following steps create the staging environment in Rails

Create new Rails Environment
  • Add staging.rb to config/environments
  • Copy contents of config/environments/test.rb into config/environments/staging.rb

Here is a resource to help understand creating new Rails environments

Update Rails app to use new Environment
  • Open Gemfile
    • Add :staging environment to Gem group that also includes :test and :development
  • Open database.yml and add
...

staging:
  <<: *default
  database: my_app_staging
  host: 127.0.0.1

...
  • Open webpacker.yml and add
...

staging:
  <<: *default
  compile: true

  # Compile test packs to a separate directory
  public_output_path: packs-test
  
...
Add credentials for new Environment
  • Run rails c
    • Rails.application.credentials.config
    • Copy secret_key_base and it’s value
    • Close rails c
  • Edit staging environment credentials in terminal
    • EDITOR=“code --wait” bin/rails credentials:edit --environment staging
      • In the above command replace code with your IDE of choice
    • A file will open that can be edited
    • Add secret_key_base: <paste value> to file
    • Close file and it will save and encrypt

Here are some resources to help understand Rails credentials

Update .gitignore to ignore new environment key
  • Open .gitignore
    • Add /config/credentials/staging.key

Step 3 - CircleCI - Use the staging environment

  • Open .circleci/config.yml and ensure these environment variables are set correctly
jobs:
  test:
    docker:
      - image: circleci/postgres:12.3
          environment:
	    POSTGRES_DB: my_app_staging
    environment:
      RAILS_ENV: staging
      PGHOST: 127.0.0.1
  • Open project on CircleCI.com
    • Open project options
    • Add Environment Variable
      • RAILS_MASTER_KEY: <staging.key value>
.circleci/config.yml - This is my working CircleCI config
version: 2.1 # Use 2.1 to enable using orbs and other features.

# Declare the orbs that we'll use in our config.
orbs:
  ruby: circleci/[email protected]
  node: circleci/[email protected]

jobs:
  build: # our first job, named "build"
    docker:
      - image: cimg/ruby:2.7.1-node # use a tailored CircleCI docker image.
    steps:
      - checkout # pull down our git code.
      - ruby/install-deps # use the ruby orb to install dependencies
      # use the node orb to install our packages
      # specifying that we use `yarn` and to cache dependencies with `yarn.lock`
      # learn more: https://circleci.com/docs/2.0/caching/
      - node/install-packages: 
          pkg-manager: yarn
          
  test:  # our next job, called "test"
    # we run "parallel job containers" to enable speeding up our tests;
    # this splits our tests across multiple containers.
    parallelism: 3 
    # here we set TWO docker images.
    docker:
      - image: cimg/ruby:2.7.1-node # this is our primary docker image, where step commands run.
      - image: circleci/postgres:12.3
        environment: # add POSTGRES environment variables.
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: password
          POSTGRES_DB: my_app_staging
    # environment variables specific to Ruby/Rails, applied to the primary container.
    environment:
      BUNDLE_JOBS: "3"
      BUNDLE_RETRY: "3"
      PGHOST: 127.0.0.1
      PGUSER: postgres
      PGPASSWORD: password
      RAILS_ENV: staging
    # A series of steps to run, some are similar to those in "build".
    steps:
      - checkout 
      - ruby/install-deps 
      - node/install-packages:
          pkg-manager: yarn
      # Here we make sure that the secondary container boots 
      # up before we run operations on the database.
      - run:
          name: Wait for DB
          command: dockerize -wait tcp://localhost:5432 -timeout 1m
      - run:
          name: Database setup
          command: bundle exec rails db:schema:load --trace
      # Run rspec in parallel
      - ruby/rspec-test

# We use workflows to orchestrate the jobs that we declared above.
workflows:
  version: 2
  build_and_test:     # The name of our workflow is "build_and_test"
    jobs:             # The list of jobs we run as part of this workflow.
      - build         # Run build first.
      - test:         # Then run test,
          requires:   # Test requires that build passes for it to run.
            - build
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment