DEV Community

Raphael Jambalos
Raphael Jambalos

Posted on • Updated on

Deploy Rails in Amazon ECS: Part 2 - Push an image to ECR

This is the second 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.

2 | Setting up an IAM User

The first step in deploying your Dockerized application in the cloud is being able to upload the images you’ve built to an image repository. For this tutorial, we will use AWS Elastic Container Registry (ECR).

You will need an AWS account. You can set up one here. In this section, we will create an IAM policy with all the permissions we need to access ECR. Then, we will attach that policy to a new user we will use later on.

(2.1) When you're done with your AWS account setup, let's create an IAM policy. On the Services tab, search for IAM and click it. Then, click the "Policies" tab on the left-side menu. After that, click "Create Policy".

(2.2) On the next page, choose Elastic Container Registry as the service, All Elastic Container Registry Actions as the actions, and All Resources as the resources. This permission grants our user ability to do anything inside the ECR service (such as push docker images to ECR, etc)

(2.3) On the next page, add ecr-admin-access as the name, and Give admin access to ECR as the description. Then, click Create Policy.

(2.4) Now, go to the Users tab on the left-side menu. Then, click Create User.

(2.5) In the next page, add ecr-fetch-user as the username and enable Programmatic access. There are two main ways to access AWS: through the Management Console (which you are now using) or through the CLI. Enabling Programmatic access will enable us to access AWS via CLI only. Then, click "Next: Permissions".

(2.6) On the next page, search for the policy we created in 2.1: ecr-admin-access. Then, tick the checkbox on the left and click "Next: Tags"

(2.7) Skip the next pages by clicking next. Then, review your IAM user. When you've reviewed it, click "Create user".

(2.8) The next page will show the Access Key ID (AKID) and Secret. You will use these credentials to get access to AWS in a later step. Make sure to download the CSV as this will be the last time you will be able to see these credentials.

(2.9) Setup your AWS CLI using the official install guide. Click on the OS you are using on the left-hand side.

At the step where you type aws configure, put in the AKID and secret you downloaded from 2.8. For the region, choose "ap-southeast-1".

3 | Create an ECR Repository

With an AWS CLI setup, let's dive in!

(3.0) In a production setup, you must choose the AWS region closest to you. For simplicity, choose the Singapore region ("ap-southeast-1") on the upper-right side.

(3.1) On the services tab, search for ECR and click it. On the page's right-hand side, click "Create Repository".

(3.2) On the next page, use sample-docker-rails-app as the repository name. Then, click "Create Repository".

You will see the repository URI. Take note of this, we will use it in step 5.2. We have create an image repository. With the URI of the repository provided, we can push as many versions of the same image as we like.

4 | Preparing our Rails 5 app for ECS

(4.1) First, cd into the project's root directory of the project we did on the last post. If you decided to skip that blog post, clone it from here.

Add this snippet to your config/database.yml file.

staging:
  adapter: postgresql
  encoding: unicode
  host: <%= ENV['POSTGRESQL_HOST'] %>
  username: <%= ENV['POSTGRESQL_USER_NAME'] %>
  password: <%= ENV['POSTGRESQL_PASSWORD'] %>
  pool: 5
  database: <%= ENV['POSTGRESQL_DB'] %>

This allows our database credentials to be supplied via an environment variable (instead of hardcoding them here).

(4.2) Then, create a copy of your config/environments/development.rb file by using the command:

cp config/environments/development.rb config/environments/staging.rb

In step 4.1 and step 4.2, we created a new Rails environment called staging. This is so we can distinguish between the development environment on our local and our staging environment on our containers.

(4.3) After that, commit your progress:

git add .
git commit -m "Add staging environment"
git push origin master

(4.4) For us to run our rails server on our containers, create a new file called config/docker_puma.rb and paste the snippet from below. We are going to use the default application server for Rails, Puma.

# Change to match your CPU core count
workers 1

# Min and Max threads per worker
threads 1, 6

app_dir = File.expand_path("../..", __FILE__)
shared_dir = "#{app_dir}/shared"

# Default to production
rails_env = ENV['RAILS_ENV'] || "production"
environment rails_env

# Set up socket location
bind "unix://#{shared_dir}/sockets/puma.sock"

# Logging
# - Commened out this line so logs would pour into awslogs cloudwatch
# stdout_redirect "#{app_dir}/log/puma.stdout.log", "#{app_dir}/log/puma.stderr.log", true

# Set master PID and state locations
pidfile "#{shared_dir}/pids/puma.pid"
state_path "#{shared_dir}/pids/puma.state"
activate_control_app

on_worker_boot do
  require "active_record"
  ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
  ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env])
end

(4.5) Then, create folders needed by puma.

mkdir shared
mkdir shared/sockets
mkdir shared/pids

(4.6) After that, commit your progress:

git add .
git commit -m "Add special docker puma config. Add folders for puma"
git push origin master

5 | Pushing an Image to ECR

In this section, we will push an image to ECR.

(5.1) Let's build a Docker image with this command: docker build . -t my-rails-app. This may take a while.

(5.2) When the build is done, let's tag the image we just built. Get the URI of the repository you took note of in step 3.2 and run: docker tag my-rails-app:latest <uri-from-3.2>:v1.0.0

(5.3) Then, let's authenticate by typing aws ecr get-login --no-include-email --region=ap-southeast-1. The command will output a string starting in docker login -u AWS -p. This string will be used for us to log in with the ECR private image repository we created in section 3. Copy-paste the entire string back into the terminal.

For those using AWS CLI 2.0, you can use the command: aws ecr get-login-password | docker login --username AWS --password-stdin.

(5.4) Let's now push our image to ECR by: docker push <uri-from-3.2>:v1.0.0. Your local machine is now pushing the image to ECR, layer by layer. It should look something like this:

(5.5) Go back to the AWS Management Console. On the services tab, search for ECR and click it. Then, click the repository you created in step 3.2

You should be able to see the image you just uploaded, with the tag "v1.0.0"

What's next?

You pushed your first image into ECR. In the next post, you will build the required AWS resources to set up your Rails app in ECS.

Special thanks to Allen, my editor, for helping this post become more coherent. Another special thanks to Richard Hessler for the tip on AWS CLI 2.0

I'm happy to take your comments/feedback on this post. Just comment below, or message me!

Top comments (12)

Collapse
 
kavitajadhav profile image
Kavita Jadhav

Thank you Raphael for such detailed tutorial.

I face one issue at point (5.3). Below command didn't work for me.
*aws ecr get-login-password | docker login --username AWS --password-stdin *

To make it work I had to provide registry url in the end of docker login command

Collapse
 
sunpochin profile image
Sun Pochin • Edited

for example, on my terminal I have to enter:

aws ecr get-login-password | docker login --username AWS --password-stdin 789819000571.dkr.ecr.ap-southeast-1.amazonaws.com/sample-docker-rails-app:v1.0.0
Enter fullscreen mode Exit fullscreen mode

readers you need to replace

789819000571.dkr.ecr.ap-southeast-1.amazonaws.com/sample-docker-rails-app:v1.0.0
Enter fullscreen mode Exit fullscreen mode

with your own repository URI created from section (3.2).

and the terminal will return:

Login Succeeded
Enter fullscreen mode Exit fullscreen mode
Collapse
 
raphael_jambalos profile image
Raphael Jambalos

Hi Kavita, thank you for taking the time to read the article. I hope it was helpful. I'm so sorry I wasn't able to get back to you sooner. Can you give me a sample of the docker login command (redact the url if you have to)? This is so I can apply the relevant changes to the article

Collapse
 
cataherrera profile image
Catalina Herrera • Edited
Collapse
 
elbartostrikesagain profile image
Calvin • Edited

There are issues with the base image version and the gem versions. I would confirm docker-compose build works first. I update the image to the most recent Ruby 2.5.x and updated Bundler to the last version to support this Ruby version (2.3.26), and updated Rails to 5.2.8.1.

Collapse
 
rpascar1 profile image
Rpascar1

in the aws cli setup what would the output be? default is json but there is also yaml text and table does this not matter

Collapse
 
richessler profile image
Richard Hessler

it doesn't really matter, whatever your preference is.

Collapse
 
rpascar1 profile image
Rpascar1

What would cause your preference of one over the other?

Collapse
 
richessler profile image
Richard Hessler

One thing to note is that with AWS CLI Version 2 the aws ecr get-login command is replaced with

aws ecr get-login-password | docker login --username AWS --password-stdin

Collapse
 
raphael_jambalos profile image
Raphael Jambalos

Thanks for this Richard, I have edited the article to reflect this. Have a good one! :D

Collapse
 
abigoroth profile image
Ahmad Ya'kob Ubaidullah

Hi Raph,
Please share about your shared_dir Would love to learn how to set it up on fargate.

Collapse
 
jisuanjixue profile image
wangxiaobo

thank you , i will learn how to deplay a ruby on rails application production to ECS, i am in china ,so ,i want to use aliyun ecs