Skip to content

AWS EB: Best Practices for Rails app using AWS Elastic Beanstalk

E. Lynette Rayle edited this page Mar 6, 2022 · 2 revisions

Prerequisite: Relies on a multi-server deployment environment being set up. See Multi-Server Deployment Strategy.


App Configs

secrets.rb

Edit /config/secrets.rb and set/change the following to match...

integration:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

staging:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

/config/environments

/config/environments should include an environment file for each deployment

  • integration.rb should be very close to production.rb and possibly identical
  • staging.rb == production.rb

/config/database.yml

Update database names to use the following convention for integration, staging, and production, respectively.

database: <%= "#{ENV['DATABASE_NAME_PREFIX']}_integration
database: <%= "#{ENV['DATABASE_NAME_PREFIX']}_staging
database: <%= "#{ENV['DATABASE_NAME_PREFIX']}

EB Extensions

The configs in the app's .ebextensions directory can be used to perform actions on the AWS machine. The actions you can take include...

  • run a command immediately (ex. .ebextensions/01_fits_download.config)
  • create script files on the AWS machine in directory /opt/elasticbeanstalk/hooks/appdeploy/pre which to run BEFORE the deploy (ex. .ebextensions/02_db_seed_task.config)
  • create script files on the AWS machine in directory /opt/elasticbeanstalk/hooks/appdeploy/post which to run AFTER the deploy (ex. .ebextensions/solr_reindex.config)
  • run a yum package (ex. .ebextensions/git.config)

Configs that all rails apps on AWS will need include...

| filename | purpose | examples | git.config | can be used to run bundler such that gems are installed in app's /vendor/bundle directory instead of the default shared location for the machine | .ebextensions/git.config | | nginx.config | runs service nginx reload so that changes to nginx (like the https rule below) are actually applied | .ebextensions/nginx.config | | nginx-redirect-to-https.config | Applies https rewrite rules so that https is not only enabled, but requests are forced onto https. Must be combined with a load balancer (nginx), a load balancer listener on port 443, and a certificate in ACM to enable the listener. | .ebextensions/nginx-redirect-to-https.config |

Jenkins & Elasticbeanstalk (EB) Deployment

3 deployment processes are setup to go to 3 EB machines

  • integration - tied to dev branch to verify latest code works on AWS
  • staging - tied to main to verify code targeted for production will work on AWS
  • production - the live production app

Jenkins Setup

integration staging production
project name project_name_int project_name_stg project_name_prod
deploy trigger auto-deploy when dev branch changes auto-deploy when main changes manually deploy from main
parameters Name: sha Name: sha
Type: String Type: String
Default: dev Default: main
Description: The branch or commit sha to deploy from github. Description: The branch or commit sha to deploy from github.

Elastic Beanstalk Setup

integration staging production Description/Comments
application name project_name_int project_name_stg project_name_prod

Machine Setup

integration staging production
typical initial machine size t2.large t2.large t2.medium
database name DATABASE_NAME_PREFIX + '_' + RACK_ENV e.g. exhibits_integration DATABASE_NAME_PREFIX + '_' + RACK_ENV e.g. exhibits_staging DATABASE_NAME_PREFIX e.g. exhibits

Standard Rails Related Configs

Sysops staff can change the configuration parameters through the UI on tab Configurations -> Software -> Modify. For developers, you can change the configuraitons through the UI, but will get a permissions error when you save. But developers can do this using the EB CLI.

integration staging production Description/Comments
BUNDLE_DISABLE_SHARED_GEMS 1 1 1 "bundle install" will always install the gems into a local directory instead of using system-wide installed gems
BUNDLE_PATH vendor/bundle vendor/bundle vendor/bundle where gems will be installed
BUNDLE_WITHOUT test test:development:integration test:development:integration gem groups to ignore
RACK_ENV integration staging production the rails environment to use
RAILS_SERVE_STATIC_FILES true true true allow access to files in public directory when true (default=false)
RAILS_SKIP_ASSET_COMPILATION false false false w/o this the assets will not compile
RAILS_SKIP_MIGRATIONS false false false typically set to false to run migrations with every deploy
SECRET_KEY_BASE Copy results of SecureRandom.hex(64) as the value. Copy results of SecureRandom.hex(64) as the value. Copy results of SecureRandom.hex(64) as the value.
$ irb
>> require 'securerandom' 
=> true
>> SecureRandom.hex(64)
=> "A_LONG_RANDOM_KEY"
>> exit

Standard Database Related Configs

integration staging production Description/Comments
DATABASE_HOST set by sysopts based on databases location
DATABASE_NAME_PREFIX your_app_name your_app_name your_app_name
DATABASE_RAILS_USER your_app_db_user your_app_db_user your_app_db_user
DATABASE_RAILS_USER_PW your_app_db_user_pw your_app_db_user_pw your_app_db_user_pw
command example description
eb use EB_APP_NAME eb use myproj-int connect to a specific EB machine MUST DO BEFORE USING OTHER COMMANDS
eb printenv eb printenv lists EB configurations
eb setenv NAME=VALUE eb setenv RACK_ENV=integration set an environment variable

##Setting up s3 data

###Rails app

  • install carrierwave gem
  • install carrierwave-aws gem
  • add config/initializers/carrierwave.rb
if ENV['S3_KEY_ID'].present?
  CarrierWave.configure do |config|
    config.storage = :aws
    config.aws_bucket = ENV['S3_BUCKET']
    config.aws_acl = 'bucket-owner-full-control'

    config.aws_credentials = {
      access_key_id:      ENV['S3_KEY_ID'],
      secret_access_key:  ENV['S3_SECRET_KEY'],
      region:             ENV['S3_BUCKET_REGION']
    }
  end
end

AWS changes

  • setup s3 buckets and enable web site hosting for each one, in the us-east-1 region
  • create an IAM user with permissions to access the three buckets, and restrict access to the buckets only to that user; generate a credential set to insert into configs
  • add the following configurations to the AWS project (int, stg, and prod)
integration staging production Description/Comments
S3_BUCKET PROJECT-NAME-data-int PROJECT-NAME-data-stg PROJECT-NAME-data-prod
S3_BUCKET_DOMAIN http://_PROJECT_NAME-data-int.s3-website-us-east-1.amazonaws.com http://_PROJECT_NAME-data-stg.s3-website-us-east-1.amazonaws.com http://_PROJECT_NAME-data-prod.s3-website-us-east-1.amazonaws.com
S3_BUCKET_REGION us-east-1 us-east-1 us-east-1
S3_KEY_ID IAM user access key ID IAM user access key ID IAM user access key ID
S3_SECRET_KEY IAM user secret access key IAM user secret access key IAM user secret access key