Technology Musings

July 14, 2018

Platforms / Deploying a Rails Application to Elastic Beanstalk

JB

I'm not a big AWS fan because it is a lot of work.  However, sometimes a client requires it.  In any case, if you are wanting to deploy to AWS Elastic Beanstalk using a Rails app, here are your step-by-step instructions!

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px 'Helvetica Neue'; color: #454545} p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px 'Helvetica Neue'; color: #454545; min-height: 14.0px} li.li1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px 'Helvetica Neue'; color: #454545} span.s1 {color: #e4af0a} ol.ol1 {list-style-type: decimal}

Preparing a Rails app for EB deployment:

 

  1. Install the elastic beanstalk tools:
    From Python: sudo pip install awscli awsebcli --upgrade
    From homebrew: brew install aws-elasticbeanstalk
  2. AWS Config
    Set ~/.aws/config as follows:

    [default]
    region = us-east-1

    [profile eb-cli]
    aws_access_key_id = YOUR_ACCESS_KEY_ID
    aws_secret_access_key = YOUR_SECRET

    The name of the profile "eb-cli" will need to match future steps.
  3. Create an AWS EB application in the EB GUI:
    1. Create the application and give it a name
    2. Create an environment (select "web server environment") and name it whatever you want
    3. Select "Ruby" for the preconfigured platform
    4. Leave the application as "sample application"
    5. Hit "Create Environment" and wait for it to finish (this takes forever)
  4. Enable load balancing so that you have more control (optional, but required for HTTPS I think):
    1. Go to "configuration" then "Capacity"
    2. Change "Single Instance" to "Load Balanced"
    3. Reduce "max" to "1" to prevent additional instances from launching
    4. Hit "apply" and "confirm" and then wait (this takes forever)
  5. Change the instance type to "t2.small" at the lowest.  If it is smaller than this, you will get strange errors when deploying because it is running out of RAM to do the deployment.
    1. "Configuration" -> "Instances" -> "Modify" -> "Instance Type".  Set to t2.small.
  6. Add a data tier
    1. "Configuration" -> "Database" -> "Modify"
    2. Options:
      Engine: postgres
      Engine version: 9.6.8
      Username/password: set them and write them down, but you don't really need them
  7. Configure Environment Variables
    1. "Configuration" -> "Software" -> "Modify"
    2. BUNDLE_WITHOUT: test:development
    3. RACK_ENV: production
    4. RAILS_SKIP_ASSET_COMPILATION: false
    5. RAILS_SKIP_MIGRATIONS: false
    6. RAILS_SERVE_STATIC_FILES: 1
    7. SECRET_KEY_BASE: use "rake secret" to generate one (note that leaving this out can lead to some weird errors that seem senseless)
    8. Any other configuration (check your .env file if you have one)
  8. Modify your app to use your data tier.  In config/database.yml, make sure that the adapter is postgresql for "default", then set production to be like the following:

    production:
      <<: *default
      database: <%= ENV['RDS_DB_NAME'] %>
      username: <%= ENV['RDS_USERNAME'] %>
      password: <%= ENV['RDS_PASSWORD'] %>
      host: <%= ENV['RDS_HOSTNAME'] %>
      port: <%= ENV['RDS_PORT'] %>

  9. In your app, Create a .elasticbeanstalk/config.yml file in your project's home directory
    1. File contents:

      global:
        application_name: your-app-name
        default_region: us-east-1
        profile: eb-cli
      branch-defaults:
        master:
          environment: your-staging-environment

    2. The region should probably match the region of the application (though I am not certain), the profile should match the one in ~/.aws/config, and the application_name should match the actual name of the application in elastic beanstalk.
    3. "branch-defaults" allows you to set some parameters per-branch (based on the git branch).  Here, we are saying that when using the master git branch, the environment we should push to is "your-staging-environment".
  10. Create a file in your app .ebextensions/010_packages.config (loads packages we will probably need - may need others based on requirements):

    packages:
      yum:
        git: []
        gcc: []
        libxml2-devel: []
        libxslt-devel: []
        patch: []
        sqlite-devel: []
        libffi-devel: []
        postgresql96-devel: []

  11. Make sure that everything in your repository is committed and ready to go.  Then, run

    eb deploy

    and everything should work.
  12. Add a CNAME for your environment in your DNS manager, whatever that is.  It should CNAME to the name listed in your environment (i.e., my-environment-name.us-east-1.elasticbeanstalk.com) (optional - you can also just leave it with the generated name, but then you won't be able to add SSL).
  13. Turn on SSL (optional)
    1. Go to AWS Certificate Manager
    2. Click "Request a Certificate" -> "Request a Public Certificate" 
    3. Enter in your domain name (the CNAME you created)
    4. Choose "DNS Validation"
    5. When it says "Pending Validation", open up the "domain" area and create the requested CNAME in your DNS in order to validate your domain.  When complete, click "Continue"
    6. Go to your EB environment page
    7. Go to "Configuration" -> "Load Balancer" -> "Modify"
    8. Click "Add Listener":
      Listener Port: 443
      Listener Protocol: HTTPS
      Instance Port: 80
      Instance Protocol: HTTP
      SSL Certificate: select the certificate previously generated
    9. Note that after adding the listener, there is an "apply" button buried on the webpage.
    10. You can now access the site using SSL on the CNAME you created.