Session 3 | Rails Elastic Beanstalk Workshop

Rails logo

Rails Elastic Beanstalk Workshop

In this workshop, you'll deploy a pre-built, database-backed Rails application using Elastic Beanstalk and CodePipeline.

Before you start, make sure that you are in the same region where you created your EC2 instances since this is where you have created previous key pairs.

You'll want to download this Rails app. Unzip it and put it in a directory you want to work with on the command line. We're specifically not using git to share the code so that you can set it up with your own git repository later on, and this exercise will mimic the same steps you'll take for a brand new Rails project.

A few quick notes about this Rails app:

  • This app uses ruby 2.6.6 and rails 5.2.3.
  • Because of Beanstalk's defaults, we are using bundler 1.17.3. There is a way to use v2 of Bundler with Elastic Beanstalk, but custom platform hooks are beyond the scope of this exercise. To bundle using this specific version of Bundler, you will need to type bundle _1.17.3_ from your command line instead of bundle.
  • This app has one resource (tasks), and the functionality was built out with rails generate scaffold. The app does not have tests. Yolo.

Although it's not necessary, if you'd like to test out the app locally before you deploy to Elastic Beanstalk, you can do that with these commands:

  1. First, if you aren't already using ruby 2.6.6, install that version. With rbenv, first upgrade your rbenv packages with brew upgrade rbenv ruby-build, then install 2.6.6 with rbenv install 2.6.6, then set it locally with rbenv local 2.6.6.
  2. bundle _1.17.3_
  3. rake db:create db:migrate
  4. rails s
  5. Navigate to localhost:3000 in your browser

AWS RDS Logo

Setting up the RDS Database

First, we'll want to set up our RDS database so that we have the endpoint, DB name + password, and port to use when setting up our Elastic Beanstalk environment.

  • In your AWS Management Console, open RDS.
  • Click the orange Create Database button.
  • Don't click the "Easy Create" slider, as there are two custom configurations that we want for our database that this option takes away from us.
  • Select a Postgres database for Engine Type.
  • Screen shot for selecting RDS engine
  • Scroll down and select Free Tier for Template.
  • In the input fields for DB instance identifier, master username, and master password, type "taskmanager". This is (obviously) not best practice for a production database, but for now, this will make it easier for you to remember the inputs since we'll keep all of them the same.
  • Screen shot for setting up RDS security
  • Scroll down to Storage and uncheck Enable storage autoscaling. We won't need that anyway, but we also dn't want to get charged if for some reason we do go over that limit.
  • Scroll to Connectivity and click Additional connectivity configuration. Make sure that NO is checked off in the Publicly Accessible section (it should be, but just double check).
  • In that same section, find VPC Security Groups and select the box that says "Create New".
  • For New VPC security group name, enter "rds-taskmanager". This is an arbitrary name, but it will help us identify it later.
  • Screen shot for connecting RDS
  • Scroll down to Additional Configuration and open up the options.
  • In Initial database name, type taskmanager.
  • Screen shot for naming RDS database
  • Uncheck Enable automatic backups. This would be good to have on if we were creating a real app, but to save on S3 storage, we'll skip backups.
  • Scroll down to the bottom and click the orange Create database button at the bottom.

Your database is being created. In the meantime, open up the rails app that you downloaded and change the database.yml file (it lives in the config folder) by making the production section look like this:

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

This sets the database name, username, password, host, and port to be environment variables that we'll set in our EB environment.


AWS Elastic Beanstalk Logo

Preparing an Elastic Beanstalk App and Environment

For this exercise, we'll just create a development environment; however, it is possible to have many (ie. dev, prod).

  • Open the Elastic Beanstalk console in a new tab. Keep your RDS dashboard open because we'll need to reference values from here later.
  • Click the orange Create Application button.
  • For application name, type "taskmanager".
  • For platform, choose Ruby, and for platform branch, choose "Puma with Ruby 2.6 running on 64bit Amazon Linux"
  • For Application Code, keep "Sample application" selected. We won't use the sample app, but we also don't want to upload our code through a zip file or S3. Eventually, we'll set up a pipeline to push our code from Github to EB, but that comes later.
  • Don't click the blue button! Instead, click the grey Configure more options button. This is what your screen should look like:
  • EB create app screenshot

This configuration dashboard shows you what Elastic Beanstalk is about to be setup for you. You can customize anything that needs to be added or changed. For now, we'll do the following:

  • Under the Software box, click "Edit".
  • Screen shot for modifying software config
  • Scroll to the bottom where you'll see inputs for Environment properties. In here, you'll need to add six keys, five of which are the database environment variables we referenced in our database.yml file earlier plus one more variable:
    • You'll first need to set SECRET_KEY_BASE: you can get this by typing $ rake secret in your terminal while you're in the Rails app. The output is what you'll paste in for the value.
    • RDS_PORT: use 5432 (this is the Postgres port, which you can also find on your RDS dashboard)
    • RDS_DB_NAME: use taskmanager
    • RDS_USERNAME: use taskmanager
    • RDS_PASSWORD: use taskmanager
    • RDS_HOSTNAME: go back to your RDS dashboard and find the value for endpoint which should be on the Connectivity & security tab. It should look like a URL. Copy that and paste it as the hostname value in your Elastic Beanstalk configuration window. If it's blank, that just means AWS hasn't finished provisioning the database. Just keep refreshing.
    • RDS endpoint screenshot
  • This is what your environment properties should look like (with your own values). The order does not matter.
  • EB environment properties screenshot
  • If everything looks right, click Save which will bring you back to the main configuration screen.

Next, click "Modify" under the Security configurations box. Choose a keypair from the dropdown (make sure this is a keypair that you have access to!), then save. You do not need to put anything for service role or IAM instance profile -- AWS will generate a role for you.

Screen shot for modifying ssh key

The rest of the settings are beyond the scope of this exercise. It may be tempting to click on the Database setting, but we'll skip this for now, as we want our database to be separated from our Beanstalk environment. This is best practice so that your data is preserved even if you delete your app's environment.

Click on the blue Create app button at the bottom.

Compared to Heroku, AWS Elastic Beanstalk takes a surprisingly long time to provision and configure your resources. This process will probably take about 5-10 minutes.


Coffee and Donuts

Take a Break

Whew. Before we create the CodePipeline (which will deploy our app), we need to fix one security group issue, but we can't do that until our security group is provisioned from Beanstalk. Take a short break and come back when your Beanstalk dashboard looks like this:

Successful Elastic Beanstalk dashboard

AWS Security Group Logo

Fixing Security Group Issues

We created a new security group, rds-taskmanager, for our RDS database, but right now it will not accept any incoming traffic from our Elastic Beanstalk app. Let's fix that:

  • In a new tab, open up the EC2 dashboard.
  • On the left-hand side, click Security Groups under "Network & Security".
  • Screen shot for security group location
  • Find the security group that says rds-taskmanager under Group Name and select it.
  • Click on the tab that says Inbound. You should see that it has a rule for inbound PostgreSQL, but the source is YOUR personal IP address (check this by Googling "what is my IP address" and comparing the two), not the IP of the EC2 instance that will need to access it.
  • Click the Edit button.
  • Delete the current source (which is your computer's IP address), and start typing "sg". You should see all of your security groups pop up. Select the one that has "awseb" in its name -- this is the security group that AWS Elastic Beanstalk made for us, which is the one that our EC2 instance will be in. We want to accept PG traffic from that instance, so we'll reference its security group.
  • Screenshot selecting correct security group
  • Click the orange Save rules button.

AWS CodePipeline Logo

Setting up a Pipeline

CodePipline can integrate build and test tools in addition to deploy, but for now, we'll create a pipeline that just watches for a new version of code to be pushed to GitHub, then deploys that code automatically to our Beanstalk environment.

First, we'll need to initialize our Rails project as a git project and create a repository on GitHub for the code.

  • From the command line, do git init, git add ., and git commit -m 'Initial commit'.
  • In your GitHub account, create a new repository and push your code to it.

Next, from your AWS Management console, open up CodePipeline in a separate tab and follow these steps:

  • Click the orange Create Pipeline button.
  • For pipeline name, enter "taskmanagerdevpipeline" (or something to that effect).
  • Screen shot for code pipeline settings
  • Leave everything else as is, and click Next.
  • For source provider, choose GitHub and connect your account.
  • In Repository, select the repository you created earlier. If nothing appears in repository, wait a bit, then re-click in the box. Your repos will appear eventually.
  • Select your master branch, and use GitHub Webhooks.
  • Screen shot for code pipeline source settings
  • Click Next.
  • We will skip the build stage, so select the grey button on bottom that says Skip build stage.
  • Don't worry about the scary-sounding message about not skipping the deploy stage. For this stage, select AWS Elastic Beanstalk in the dropdown.
  • Choose your taskmanager application with your environment.
  • Screen shot for code pipeline deploy stage
  • Click Next and review all of your settings. If these are correct, click Create pipeline.

Take a Break

Again, this process will probably take a while to deploy your code. If you go to your Elastic Beanstalk dashboard, you'll know the deployment is done and successful when you see the large green checkmark.



Trying Your App!

Once your deployment is done and has succeeded, you can check out your live app. To see your app in action on AWS, click on the url at the top of the page:

Screen shot of url from elastic beanstalk

Take a minute to try out everything in your app. Can you create new tasks? Edit them? Delete them?


Mop and bucket

Cleanup

There are a lot of resources that we created during this workshop, and they need to be stopped/deleted in a very specific order. DO NOT TRY TO DELETE YOUR EC2 INSTANCE MANUALLY. Follow the instructions below and Elastic Beanstalk will delete everything it provisioned for you.

CodePipeline

In the CodePipeline landing page, select your pipeline, then click "Delete Pipeline". Confirm the deletion.

Screen shot for deleting code pipeline

EC2

In your EC2 panel, click on Security Groups. Find the security group for your RDS database. It should be called "rds-taskmanager". Click on "Edit inbound rules", then delete the inbound rule that links it to the Beanstalk security group, then click "Save rules".

Screen shot for deleting RDS security group source

Elastic Beanstalk

Go to your Elastic Beanstalk dashboard and select "Delete application" from the "Actions" dropdown. This will take a while.

Screen shot for deleting Elastic Beanstalk application

RDS

Go to your RDS dashboard and click on "Databases" on the left-hand side. Select your taskmanager database, then choose "Delete" from the "Actions" dropdown. Uncheck "Create final snapshot?" since you don't need one (and they cost money!)

Screen shot for deleting RDS database

Click on "Snapshots" on the left-hand side and delete any snapshots. It is possible that you may not have any snapshots.

Screen shot for deleting RDS snapshots

Back to EC2 for Security Groups

Now that your RDS database is gone, you can remove your RDS security group. Click on "Security Groups" from the left-hand side, select the "rds-taskmanager" group, and select "Delete Security Group" from the "Actions" dropdown.

If you get an error about a network interface, just wait a moment, as that means your Elastic Beanstalk application has not finished being deleted.

Screen shot for deleting RDS security group

S3 Artifacts

CodePipeline and Elastic Beanstalk both create S3 buckets to store artifacts related to your application versions.

In the S3 dashboard, select the CodePipeline bucket and delete it. You'll need to click the "empty bucket configuration" link in order for AWS to allow you to do this. Then, go back to the dashboard, select the same bucket, and you should be able to delete it this time.

Screen shot for deleting RDS security group

Next, click into the Elastic Beanstalk bucket. This one has a bucket policy attached to it that does not allow you to delete it. So first, we'll need to delete that bucket policy (see below):

Screen shot for deleting RDS security group

Then, repeat the same steps that you did above with the CodePipeline bucket.