loading...

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

raphael_jambalos profile image Raphael Jambalos Updated on ・6 min read

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!

Posted on by:

raphael_jambalos profile

Raphael Jambalos

@raphael_jambalos

Avid Reader, Curious Learner. AWS Certified ☁️

Discussion

pic
Editor guide
 

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

 

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

 
 

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

 

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

 

What would cause your preference of one over the other?

 

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

 

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