This starts a series of posts about devops where we’ll be leveraging AWS to solve some common situations that arise when running apps on the cloud. In this post we will go over a very simple set up: A web server hooked into a database for persistence. While very far from a real production situation this setup is a good starting place to learn about AWS fundamental tools. The concepts I’ll be going over today include:

  • Amazon Regions
  • EC2 instance
  • AMI
  • Security Groups
  • SSH
  • Manual Dependencies installation

The Plan

The simplest (but not necessarily most recommended) way to get a server running on amazon can be achieved with the following steps:

  • Choose an Amazon Region
  • Create an EC2 instance.
  • Ssh and install software (dependencies, database, etc)
  • Test the app

We’ll go through each of these steps and explain all the new terms along the way. Throughout this tutorial I’ll be using a very simple rails 5 blog app. We’ll be using this repo in subsequent steps so feel free to check it out.

Choose an Amazon Region.

Amazon has data-centers located on different parts of the world which are known as regions. Each region contains a certain number of availability zones (AZ) where ultimately the infrastructure lives. While each region is completely independent from each other, AZs from within the same region can communicate with each other through low latency links nevertheless, they are physically and resource-wise (power supply, etc) isolated from one another. This set up allows AWS to efficiently serve users across the globe while providing enough redundancy to protect against unfortunate events (e.g power outages, natural disasters, etc).

Choosing an AWS region is easy just go to the top right corner and choose one according to your location.

Selecting Regions

As a rule of thumb you should pick a region that it’s closest to where you’re users are located to minimize latency. In my particular case that would be US EAST.

Create an EC2 instance

EC2 stands for Elastic Cloud Computing. Despite recent development on serverless technology EC2 are still Amazon’s bread and butter. They consist on virtual servers of different capacities that developers can “rent” to run their applications on the cloud. When creating an EC2 instance AWS takes you through a wizard with a few different steps, we’ll be covering these next. To launch the wizard we just need to find the EC2 service and click the “Launch Instance” button.

EC2 Wizard

Step 1: Choose an AMI

We’re then faced with the first step of the process where we’ll be choosing an Amazon Machine Image (AMI). AMIs are basically templates with pre-installed software ready for developers to use. AMI can be free or paid and they can be provided by AWS or third parties. Also organization can decide to create their own images for private use when their needs become very specific.

For this exercise we’ll be using an Ubuntu server which can easily support our simple rails app. To find this specific AMI just paste “Ubuntu Server 16.04 LTS” on the AMI search bar and select the free-tier option.

Step 2: Choose an Instance Type

Instance types basically determine the specs and performance of your machine. AWS provides several “series” or tiers with specs suitable for different kind of tasks. You can find more info about these tiers in here. In general, T and M series are good all-purpose machines suitable for small-mid web applications. We’ll be choosing t2.micro as it’s free-tier eligible and will do for the purpose of this tutorial.

Step 3: Configure Instance Details

We can further tweak our instance configuration but for now we’ll leave this options unchanged.

Step 4: Add Storage

The default amount (8Gib) should be more than enough for our instance storage.

Step 5: Add Tags

Tagging allows to attach arbitrary meta-data to our AWS resources. We can then use them to easily manage our resources (e.g search, classify them, etc). Tags in general have not specific semantic meaning to AWS they are just interpreted as key-value string pairs used to label resources at the developers discretion. We do not need tagging since our setup is going to be very minimal.

Step 6: Configure Security Group

Security Groups They basically work as firewalls with specific rules to white-list the kind of request we’ll let into our server. We will create a new security group and give it any name and description we want, (e.g aws-security-group and Security group for AWS tutorial) then we can proceed to add rules. For our particular case we’ll require 2 types of interaction with the server, ssh and http.

  • SSH The ssh connection will allow us to login into our server and install the additional software required to run our app. There should be a SSH rule added by default, if no just click add rule and select SSH on the type drop-down. For the source we’ll be selecting “Custom” 0.0.0.0/0 will basically allows us to ssh into the server from anywhere in the world as long as we have the correct permission.
  • HTTP We then have to define a HTTP connection and open it to the world. For this we just simply select add a rule with: Type “Custom TCP Rule” Port Range: 3000 (since we will starting our server on that port) Source: Custom 0.0.0.0/0 (which means that our app should be reachable from anywhere in the world)

Step 7: Key Pairs

On the final step of wizard we’re taken to the review page where we can just go and hit “Launch”. We’re then be prompted with a modal to select a key pair. Select “Create a new pair” and give a name such as ‘aws-tutorial-key-pair’ and click “Download Key Pair”. It’s important that you keep this key secure and at easy accessible directory on you computer as we’ll be needing it very shortly to ssh into our servers. Finally, just click on “Launch Instances”.

Ssh and install software

After launching our instance we can access our instance panel by searching for EC2 on the services tab and going to our running instances. From there we can pull up the connect instructions for our instance.

Ssh

The modal present 2 sets of instructions. The first consist to authorize your key so navigate to the directory where you stored the previously downloaded SSH key and execute:

chmod 400 aws-tutorial-key-pair.pem

then on that same directory we can just run the ssh command as shown in the instructions modal which should look like something like this

ssh -i "aws-tutorial-key-pair.pem" ubuntu@<YOUR_INSTANCE_PUBLIC_DNS>

Please for the rest of the article and if you’re following along feel free to replace the by your instance DNS which you can find as shown below:

Public DNS

Now that we’ve ssh into our instance we then proceed to install all the software required to have our application running.

# Installing OS required dependencies
sudo apt update
sudo apt install -y curl libssl-dev libreadline-dev zlib1g-dev autoconf bison build-essential libyaml-dev libreadline-dev libncurses5-dev libffi-dev libgdbm-dev

# Installing the ruby version manager rbenv 
curl -sL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash -

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc

# Installing ruby
rbenv install 2.5.1
rbenv global 2.5.1

# Installing Postgres
sudo apt install -y postgresql postgresql-contrib
sudo apt-get -y install postgresql-server-dev-9.5
sudo -u postgres createuser ubuntu
sudo -u postgres createdb aws_blog_production

# cloning and running our project
git clone --branch post1 https://github.com/eduardopoleo/aws_blog.git
cd aws_blog
gem install bundler -v '< 2.0'
gem install rails -v 5.2.1

bundle install
RAILS_ENV=production rake db:migrate

Finally, we run the server with

RAILS_ENV=production rails server -d 

The -d options allows you to run your server on a detached state freeing the console for you to run other commands. If you need to see the server logs (e.g to verify that the requests are coming through) you can always tail the production logs with tail -f log/production.log. Finally, if you want to kill the server you can find the process id running on port 3000 lsof -i:3000 and then kill it kill -9 <PID>

You can test everything is working properly by attempting to create a post with:

curl -d '{"title":"Post Title", "body":"Post Body"}'\
-H "Content-Type: application/json"\
-X POST http://<YOUR_INSTANCE_PUBLIC_DNS>:3000/posts -v
#=> You should get 201 status code if everything went well

This concludes the first post on this AWS series, we managed to get a simple rails app up and running and learned lots of AWS concepts along the way. That being said, this set up is less than ideal to run production apps for many reasons:

  • <YOUR_INSTANCE_PUBLIC_DNS>:3000 is not really an enticing url for your service
  • Our setup server set up is very tedious and error prone, specifically the part where we install dependencies
  • We are not leveraging amazon managed solution like RDS to handle our database persistence
  • Our server won’t scale if many requests required to be processed
  • Our “deployment” process is less than ideal having to ssh and git pull to a public repo.

On the next post we’ll be going into how to hook up our app to Amazons RDS and how to improve performance using ElasticCache.

Thanks for reading