How to Deploy a Rails Application to AWS with Docker - Part 3 
Tags: ruby, docker, aws, rails
Published: 2020-02-29 15:09:02


## Creating a load balancer

Load balancers are like the waiters & waitresses of the web server world. Whenever a user wants to look at a web page, some software must respond to that request. If we only have one container instance running, then that instance will be the only one available to take orders and process them.

Having only one container running your application is kind of like going to a food truck with only one person making the food. Many businesses start with such a simple model, but need to expand when they get more customers. In those cases, we cannot the same person taking orders as the one making them. Similarly the server that takes the requests for web pages should not be the same as the one making them.

This is where load balancers come in. Load balancers act like waitress. A waitress who does not know about making the food, just about describing what the customer wants, forwarding that request to a cook, and then getting the food back to the customer's table. Similarly, load balancers do not know about HTML, CSS, or JavaScript. They know HTTP, which is the language of web requests. It can forward requests for web pages to different containers. If one container is too busy to respond to a request, it can send the request to one that is not busy. Hence they balance the workload amongst the containers.

For this part of the tutorial, we're going to use AWS EC2. Search for "ec2" in the service search menu:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3vm9n0drg7kx8dsqi4fx.png)

The EC2 console is sophisticated and has many options, and is under constant improvement.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1nnbixummvx7qhoenl6x.png)

The load balancing options are in the sidebar, if you scroll down enough.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ak924danexs05fw4jkvc.png)

Click on "Load Balancers" and then click the blue button "Create Load Balancer".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kguycjk5w3268i8ozwna.png)

You'll want to choose on the "Application Load Balancer" option, so click the "Create" button there.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/m5915xc4k9k8y8pyhuhd.png)

Here we are brought to the load balancer configuration. We'll give it a name using our 'the-greatest' naming convention: "the-greatest-rails-lb-ever"

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/h9jqu9ekqlv5ijm24qm2.png)

For the Availability Zones, you'll want to enable both subnets.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pzzcnb2x2eog71lfe9ki.png)

The next panel is to "Configure Security Settings", but we can skip that for now and move on to "Configure Security Groups".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/npxcg1syu62u4cs236q1.png)

For this step, we DO NOT want to select an existing security group. When switching to "Create a new security group", we're asked the name and description of the new group. We're sticking to the same naming style, and going with "the-greatest-rails-security-group-ever".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/s8eoyhoyl7p458k9m3h6.png)

In step 4, we configure the load balancer around what group it will delegate work to. I've gone with the name "the-greatest-target-group-ever".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/z4xeq6zmlltx850jhhzm.png)

From here you can skip to step 6, review.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/91k8h4o4r7itqicrkta4.png)

Click the blue button "Create" and you should see, after a brief loading period, a success screen:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3k7xm8iy7nj4t19npzsg.png)

## Creating the ECS cluster

We have containers but we don't have any machine instances to run them on. Towards this end, we need to create an ECS cluster. The next section will do that for us. Towards this end, we'll first need a key pair from EC2 to run ECS.

### Creating an EC2 key pair

Search for "ec2" in the AWS console.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/upq1gjbyqhaenpbw6o2k.png)

Scroll down the side menu until you find "Key Pairs".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qgzf7w5u836dj78n4hsi.png)

Next we'll create a new key pair by clicking the orange button "Create key pair".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rkwe34v63i51v876dstb.png)

We're going to create "the-greatest-rails-key-pair-ever"

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6spu4etcb7fssknkpdkf.png)

Click on "Create key pair" and you'll get a success screen. It should also download a `.pem` file that you will need soon.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/977tpq1r8w7fkb2nfl0y.png)

### Creating the ECS cluster

Search for "ecs" in the AWS console and let's create a cluster.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wfp3txfijkpdcwia31ks.png)

Once there, click the "Clusters" option from the side menu.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rkg69g7brbv4tnr44tj2.png)

Click "Create Cluster". We'll be using the "EC2 Linux + Networking" option.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jngxkdh8xj80mxmzbj6c.png)

Click the "Next Step" button at the bottom and now we can pick a cluster name. I went with "the-greatest-rails-cluster-ever".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nqx5e6o94j065em72zwi.png)

Scroll down and you should see Instance configuration. I changed the EC2 Instance type to "t2.micro" because it is a part of the free tier. Large applications will likely want "m3.medium" or larger.

We also specify the Key pair ("the-greatest-rails-key-pair-ever"), which we created earlier.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/73msqvk9wpz11hr8joll.png)

For the networking portion of this configuration, you'll be using the same VPC and subnets we configured earlier, when we configured the Availability Zones for the load balancer.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4oexm0qphzhlymsb00ji.png)

One last configuration is allowing CloudWatch to provide Container Insights.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fuck4czpkytf6ub8x8mq.png)

When you're done, hit "Create". It will kick off the cluster. Give it a minute and it should be ready when all three steps are green.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/b89i2ad7cb5vda0vwh4k.png)

When it's ready, click the "View Cluster" button, where we will create the ECS service.

## Creating an ECS service

To create an ECS service on our new cluster, click on the "Create" button in the cluster detail view.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/owmli5b98pfzadg62aig.png)

Much of the initial service configuration is filled in for us. When I did this, I needed to specify the launch type as "EC2", and the service name as "the-greatest-rails-service-ever". The number of tasks can be set to 1.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6nailrnja8e7bqbccsin.png)

Go to the "Next Step" to configure the network.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/i1zubrvd1xo9buc2tqjm.png)

In this part, we need to choose "Application Load Balancer", which is what we created earlier. The IAM role can be changed to "AWSServiceRoleForEC2". The load balancer name should be picked for you, since it's the only one available. When you're done here, you can click "Add to load balancer".

After you've clicked that, it should pop up with configurations on "Container to load balance". At this point, I picked "the-greatest-target-group-ever" as the target group name.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0cudkbkfjyehcfrjtgav.png)

Make sure that the "Enable service discovery integration" is unchecked. Then click "Next Step".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jv9qjmslg86sn4a4rem5.png)

Leave this configuration as is.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zx0y09a91nkwxro08aq4.png)

This is what my review page looked like.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/83eemobvvpo314mlh9hh.png)

When ready, hit "Create Service" and you'll see a success screen.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ejbdths5rnptgxso1828.png)

## Creating AWS Security Groups

AWS Security Groups are like virtual firewalls, and are absolutely necessary to create a secure cluster. We're going to create a security group around our EC2 instances and our RDS database. This is to ensure that the traffic between the two instances is protected from the outside world.

### Adding the cluster to the security group

Search for "ecs" in the AWS console.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wfp3txfijkpdcwia31ks.png)

We're going to go back to the cluster we just created.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/67f4kjskumhion117gv6.png)

Click on the name ("the-greatest-rails-cluster-ever") and it should bring you to the detail view.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3a9ez0cf51616y4naqsp.png)

Click on the "EC2 Instances" tab below and you should see at least one instance available.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6w294fnipk9j1zthhkea.png)

Click on the "EC2 Instance" link, which in my case, starts with "i-089132...". This should bring you the detail view for the EC2 instance.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pk5zx1lsx3qhcm13pn1p.png)

If you scroll down a bit in the lower panel, you should find a section called "Security groups" under the "Description" tag. In my case, the link starts with "EC2ContainerService-the-greatest-...".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/hh3ou2lr7h3ernogba97.png)

Clicking on that link should bring you a list with only one security group.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mo26qmmeucjkmh54ntx8.png)

Click on the "Inbound" tab in the bottom panel.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/yu0v4jwqnr7uf3ygsr9k.png)

In that tab, click "Edit". We are editing the inbound rules for this security group. We already have one for HTTP. We also want to allow SSH-ing into this group, so we add another row for SSH, and set the source to "Anywhere". We add one more rule for All TCP. Set the source to the security group we created earlier. In my case, I started typing "the-great" and I added the one that begins with "sg-02f94...".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/r85cr60jhf4jzeybn06s.png)

Hit "Save" and and the new rules will show up in the bottom panel.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0oriniu9j6dmcxi4fjlc.png)

We've added the security group to the ECS instance. Now we need to add it to our RDS database.

### Adding the database to the security group

Search for "rds" in the AWS console.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/an6ozfz5yzwdv6lxb1vw.png)

Find your database in the list of database, then click it's name. In my example, it is "the-greatest-rails-app-ever-db-1".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wtjpv9ha0it669bdk5se.png)

We're going to edit the security group for the database as well. In the detail view of database, we can edit it's security group. Click on it's name, which in my case it is "default (sg-7d493718)".

This view should look familiar, since we were just editing the group for the container instances. Look for the "Inbound" tab at the bottom.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pqr07g4h7vpfuga4o0a3.png)

Clicking on that tab should give you an edit button. From there we can add a new rule for MySQL/Aurora, belonging to the same security group we used before.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nfgx3dn2wbztiyqzug3n.png)

### Test the SSH connection

Go back into your EC2 panel and click on "Instances"" in the side menu.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qx0offx85cdktko03lt5.png)

Clicking "Connect" will bring up instructions on how to connect to this instance. Yours will be different from mine. Run the instructions to be sure you can connect to your instance, with one exception: Instead of `root`, you should use `ec2-user`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/arklhjtu95th0i80xcws.png)

Here's what I got when running it:

```shell
$ ssh -i "the-greatest-rails-key-pair-ever.pem" ec2-user@ec2-54-85-141-101.compute-1.amazonaws.com
Last login: Fri Feb 28 21:24:36 2020 from 104.218.140.180

   __|  __|  __|
   _|  (   \__ \   Amazon Linux 2 (ECS Optimized)
 ____|\___|____/

For documentation, visit http://aws.amazon.com/documentation/ecs
No packages needed for security; 1 packages available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-172-16-0-12 ~]$
```

Check the running Docker containers:

```shell
[ec2-user@ip-172-16-0-12 ~]$ docker ps
CONTAINER ID        IMAGE                                                                      COMMAND              CREATED             STATUS                   PORTS                     NAMES
e3fbc2eda44f        035513743183.dkr.ecr.us-east-1.amazonaws.com/the-greatest-rails-app-ever   "sh entrypoint.sh"   50 seconds ago      Up 48 seconds            0.0.0.0:32769->8080/tcp   ecs-the-greatest-rails-docker-app-ever-30-web-a2e082efd5f689d71500
9be25ec937fa        amazon/amazon-ecs-agent:latest
```

## Final Testing of Our Rails application

Since our container is running, we should be able to access our Rails application. The EC2 instance should have a publicly accessible domain name.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/meysujyjblyqjhq7hc71.png)

We're going to plug in that URL and add `/blog_posts` at the end, since that endpoint will allow us to test the database as well.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/73zflr5ywysbykkebzqn.png)

Clicking on the 'New Blog Post' link should bring up a form to create a new blog post.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/q8xm5mmkhbjrkrqg3g08.png)

Once we've created the blog post, we will be redirected to this screen:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/to6snowlrd2vkfvjb0n6.png)

A little anti-climatic, but we have shown that our application does work in AWS!

## Wrapping up

What have we learned so far?

* How to dockerize our Rails application.
* How to create an IAM role and ECR repository for a Docker image.
* How to create an ECS cluster and Task Definition based on that image.
* How to test the EC2 instance that is running the container.

With AWS, there is plenty to learn and explore. I will continue to post about new topics as I learn them! If you have any questions, suggestions or other comments, please feel to them down below.

Thanks everyone! :)