This will be the first in a series of posts where I go through the steps of creating a highly available minimum viable architecture.
To see the results of the step by step guide in video form click here
High availability is becoming more and more important. The Internet gives people the opportunity to shop/work and communicate with more flexibility than any other time in human history. Software is expected to work, and it’s expected to work 100% of the time. Businesses can not afford to have the negative exposure which a service not being available brings.
I’m using this series of blog posts to increase my knowledge of Amazon Web Services and my Linux administration skills. Although I’ve had exposure to solving this style of project before, I want to learn and increase my skill set further, whilst sharing knowledge gained with a wider community.
All and any feedback would be greatly appreciated.
For these blog posts I’m going to create the minimum viable architecture using the following stack.
I’ll be using Amazon web services to handle the hardware management, and using many of their software products to achieve the highly available architecture.
The rest of the software stack will use Ubuntu, Node.js, Postgresql and Git. I’m using these technologies as they’re very popular in the web development world, simple to install and have been designed to work at scale.
Before delving into building the application I took a while to think about the minimum viable architecture needed to produce highly available software stack. I also wanted to design the application in a scalable fashion, taking on advice from other developers and using my own personal experiences.
The stack will be split into two sections, a dumb side will take care of rendering and displaying the data to user, and a clever side which will take of performing complex data manipulation.
My first attempt at designing the architecture is as follows:
This diagram is subject to change and I’d love to get feedback on improvements or other suggestions.
Amazon Cloudfront and Route 53 are used to speed up delivery of the website, and manage DNS redundancy, which from personal experience can be tricky to get to grips with. I’m more than happy to pass this responsibility off to the team at Amazon.
The next level down will consist of two extremely dumb web servers. These web servers will handle incoming requests, communicate with web services and render the data returned.
One step further down and we’re into the clever parts of the application, these consist of a collection of web services. These can either be stand alone instances or several combined applications running on one instance, the important part is that during deployment the web services are kept in synchronization across zones.
The final part of the application are the database servers which will be split across zones and keep in synchronization via Postgresqls built in replication.
Putting the dumb part together
- Sign up for amazon web services http://aws.amazon.com/console/
- Login to aws
- Click on EC2
- Click on Launch instance
- Keep Classic Wizard selected and click Continue
- Click select next to Ubuntu server 12.04.1 LTS
- Keep the default options for number of instances and instance type and click Continue.
- Keep the advanced options the same and click Continue
- Keep the storage device configuration the same and click Continue
- Ignore setting any tags and click Continue
- Enter a name for your key pair, download and save to your ~/.ssh/ directory
- Give your security group a name and enter 80 in Port range, keep source as 0.0.0.0/0
- Confirm all the details and click launch
- Select a new region and repeat steps 4- 13
Step 2: SSH to one of the machine
On your desktop machine run the following commands
sudo chmod 600 ~/.ssh/ec2-keypairname.pem ssh-add ec2-keypairname.pem ssh -v ubuntu@[PublicDNSOfInstance1]
Step 3: Create a simple node.js application
sudo locale-gen en_GB.UTF-8 sudo apt-get update sudo apt-get install git sudo apt-get install nodejs sudo apt-get install npm sudo mkdir -p /var/www/frontend/ sudo chown -R ubuntu:ubuntu /var/www/frontend/ cd /var/www/frontend/ npm install express ./node_modules/express/bin/express //Press y to destination is not empty, continue? npm install //Unable to open port 80 directly, use iptables to redirect port 80 traffic to port 3000 sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to 3000 node app &
At this point you should be able to navigate to the public DNS entry in browser and see your node app running.
Step 4: Create an upstart script for the application
mkdir /var/www/frontend/log/ sudo vi /etc/init/nodefrontendapp.conf
Paste the following
start on startup
stop on shutdown
# We found $HOME is needed. Without it, we ran into problems
exec /usr/bin/node /var/www/frontend/app.js 2>&1 >> /var/www/frontend/log/node.log
Save and exit vi and run the following commands
sudo chmod u+x /etc/init/nodefrontendapp.conf sudo start nodefrontendapp
*If you get an unknown job error here check the ” have been pasted correctly.
Step 5: Set up a cloned server
git init . git add . git commit -m "Inital Commit" ssh-keygen -t dsa //use default directory cd ~/.ssh/ cat id_dsa.pub >> authorized_keys //keep default options exit
On your desktop machine copy the ssh key to the other instance via ssh
scp ubuntu@[PublicDNSOfInstance1:/home/ubuntu/.ssh/id_dsa . scp id_dsa ubuntu@[PublicDNSOfInstance2]:/home/ubuntu/.ssh/id_dsa
Now we’ll clone our basic application onto the second web server
ssh ubuntu@[PublicDNSOfInstance2] sudo locale-gen en_GB.UTF-8 sudo apt-get update sudo apt-get install git sudo apt-get install nodejs sudo apt-get install npm sudo mkdir -p /var/www/frontend/ sudo chown -R ubuntu:ubuntu /var/www/frontend/ cd /var/www/frontend/ git clone ubuntu@[IpAddresOfInstance1]:/var/www/frontend/. sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to 3000
Create the upstart script as mentioned in Step 4 for this server too.
Now the simple node applications are up and running on two seperate servers, the last part is getting them to work under out domain name.
Step 6: Setting up Route 53
- Go back to the AWS console
- Navigate to first region with a running instance
- Click elastic IPs
- Click Allocate New Address
- Click Yes, Allocate
- Click Associate Address
- Select instance
- Make a note of the IP address and public DNS
- Repeat for the other region
*Note from this point on you’ll have to SSH in via the elastic ip address / elastic public DNS
- Cick Services dropdown and choose route 53
- Click Create Hosted Zone
- Enter the Domain name
*You’ll need to set the dns entries for your domain name to point to the four domains listed under Delegation set
- Click create record set
- Change TYPE to A Name and enter the two elastic IP addresses above
We have a very simple aws server which is redunant, I’ve produced a quick screencast to show the result.
If you’re interested in following this experiment further please enter your email below.
Feedback / comments / suggestions / improvements are always welcomed.