This is the fourth part of the Deploy Rails in Amazon ECS post. It's part of a broader series called More than 'hello world' in Docker. The series will help you ready your app: from setting it up locally to deploying it as a production-grade workload in AWS.
- Build Rails + Sidekiq web apps in Docker
Deploy Rails in Amazon ECS
- Push an image to ECR
- Create the RDS database, Task Definition, and Load Balancer
- Create the ECS Cluster and connect it all together - we are here
- Configure Sidekiq
- Automate Deploys with AWS CodeDeploy
An ECS cluster is a collection of tasks and services. When using ECS-EC2 services, a cluster is also a collection of EC2 instances. Your containers run on these EC2 instances. Check out this post for a more thorough explanation.
(9.0) On the services tab, search for EC2 and click it. Then, click Key Pairs on the left-hand side menu. Click on create key-pair and add the name "rails-docker". This will download a
rails-docker.pem file to your local. We are creating a key pair because we want to be able to access the EC2 instances that our clusters will create later on. Without a key pair, those EC2 instances won't be accessible via SSH
(9.1) On the services tab, search for ECS and click it. Then, click "Create Clusters". On the next page, click EC2 Linux + Networking.
(9.2) On the next page, add my-simple-ruby-app as the cluster name.
Change the EC2 instance type to
m3.medium, and set the key-pair to
rails-docker.pem (or whatever you set in step 9.0). Do note that using m3.medium would incur fees on your AWS account. If you are following along the tutorial and made your own simple Rails app from scratch, a t2.micro EC2 instance type would suffice. The t2.micro instance is the only instance that is under the free tier. However, if you are deploying an app with more features and gems, I suggest you try m3.medium first, before experimenting with t2.micro.
(9.3) Scroll down the page. In the network section, make sure you are using the same VPC as the one you used in 6.2. In the subnets field, add all the subnets inside the VPC.
(9.4) Scroll further down. Tick Enable Container Insights so ECS will collect CPU and memory utilization data from your containers. Then, click "Create". You should see something like this:
When everything is checked, click on "View Cluster"
An ECS service is responsible for keeping a set number of tasks up and running at all times. A task is a collection of containers that must run together. To learn more about services, click here.
(10.1) On the services tab, click "Create"
(10.2) Then, choose the EC2 launch type. Choose the Task Definition Family of docker-rails-app, and its latest revision (which should be 1 if you're doing this for the first time).
(10.3) On the Configure Network section, tick "Application Load Balancer". Then, choose the load balancer we created in section 8. Then, add the
Untick Enable service discovery integration and click next. On the next page, click Do not adjust the service’s desired count, then, click next.
(10.5) Review your ECS Service. It should look something like this.
Then click, "Create Service". You should see something like this:
We have created all the components necessary for our ECS setup. The problem is they currently exist in isolation. There is currently no way for them to communicate with one another. This is because the security groups of each of our components aren't set for them to communicate with one another. Security groups are a set of rules for incoming and outgoing traffic. They specify which resources can communicate with a specific set of resources. For instance. the security group for the ECS cluster specifies which resources can communicate with it.
We have to set up the security group of our ECS cluster to be able to accept SSH traffic (so we can connect to the container via SSH) and accept traffic from all ports from the load balancer (to enable dynamic port mapping). We also have to set up the security group of the database we created in Section 6 to be able to accept traffic from the ECS cluster.
(11.1) On the services tab, search for ECS and click it. Then, click "Clusters", and then find the cluster we just created in Section 9. Then, click on the "ECS Instances" tab. This should list the EC2 instances that have been created for the cluster. Click the EC2 instance.
(11.2) This should direct you to the EC2 page. Click on the instance and on the details pane below, find the security group, and click on it. Take note of this security group. This security group defines which resources can communicate with our ECS cluster.
(11.3) This should direct you to the EC2 Security Group page. Click the "inbound" tab, and then, click "Edit". Add a rule allowing SSH traffic from anywhere.
Add another rule allowing all TCP traffic from the security group we created for the ALB. The security group's name is
rails-docker-alb-sg. Alternatively, put the security group name you entered in Step 8.3.
(11.4) On the services tab, search for RDS and click it. On the left-hand side menu, click "Databases". Then, find and click the database you created in Step 6.
(11.5) On the Connectivity & Security tab, click the security group on the VPC Security Groups. This security group defines which resources can communicate with the database.
(11.6) This should redirect you to the EC2 Security Group page for this particular security group. Click on the "Inbound" tab and click "Edit". Add a rule to allow "PostgreSQL" traffic (port 5432) on the security group you took note of in step 11.2
(11.7) Next, we repeat step 11.1 to go to the EC2 instance created for the cluster. Then, we click "Connect". This should tell us specific instructions on how to connect to our instance.
On our local terminal, go to the folder where the
pem file was downloaded in step 9.0. Then, execute
chmod 400 rails-docker.pem to secure the pem file. The command restricts the permissions of the file to only be accessible by the current user. Then, run the ssh command on the pane but change
For me, the command looks something like this:
ssh -i "rails-docker.pem" firstname.lastname@example.org
(11.8) Once you're inside the instance, do a
docker ps to list the containers that are currently running. Find the container with the
sample-docker-rails-app:v1.0.0 in its name. Take note of the container_id of that container.
Then enter the container via this command
docker exec -it <<container_id>> /bin/bash. Replace
<<container_id>> with the container_id above.
(11.9) Execute the following commands inside. You may be kicked out several times from the container. Repeat from step 11.8 until you have successfully executed the commands below.
rake db:create && rake db:migrate && rake db:seed
(12.1) On the services tab, search for EC2 and click it. Find the load balancer we created in Section 8 and click it. Then, copy paste the DNS name to another tab in your browser.
(12.2) You should be able to see the working app!
(12.3) Click on the "like" button though, we see we have an error. That's because we haven't set up Redis and Sidekiq.
In the next post, we will fix the Sidekiq issue by setting up Redis and a Sidekiq service. It's still in the works, though. It'll be up in a few days. In the meantime, you can follow me here to be updated.
Or, as a challenge, figure out how to make the like button work. The hint is the Redis service is set up as a separate EC2 instance
Special thanks to Allen, my editor, for helping this post become more coherent. Also, special thanks to tanmmz for pointing out that only the t2.micro instance type is under the EC2 free tier.
I'm happy to take your comments/feedback on this post. Just comment below, or message me!