<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Xi Group Ltd. Company Blog &#187; Xi Group Ltd. Company Blog &#187; multi-cloud</title>
	<atom:link href="http://blog.xi-group.com/tag/multi-cloud/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.xi-group.com</link>
	<description>High-quality DevOps Services</description>
	<lastBuildDate>Tue, 09 Jun 2015 11:38:46 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=4.2.2</generator>
	<item>
		<title>How to implement multi-cloud deployment for scalability and reliability</title>
		<link>http://blog.xi-group.com/2014/07/how-to-implement-multi-cloud-deployment-for-scalability-and-reliability/</link>
		<comments>http://blog.xi-group.com/2014/07/how-to-implement-multi-cloud-deployment-for-scalability-and-reliability/#comments</comments>
		<pubDate>Fri, 18 Jul 2014 15:20:12 +0000</pubDate>
		<dc:creator><![CDATA[Ivo Vachkov]]></dc:creator>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Operations]]></category>
		<category><![CDATA[theCloud]]></category>
		<category><![CDATA[AWS CLI]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[cloudflare]]></category>
		<category><![CDATA[distributed systems]]></category>
		<category><![CDATA[dns]]></category>
		<category><![CDATA[elastic computing]]></category>
		<category><![CDATA[joyent]]></category>
		<category><![CDATA[multi-cloud]]></category>

		<guid isPermaLink="false">http://blog.xi-group.com/?p=279</guid>
		<description><![CDATA[Introduction This post will present interesting approach to scalability and reliability: How to implement multi-cloud application deployment ?! There are many reasons why this is interesting topic. Avoiding provider lockdown, reducing cloud provider outage impact, increasing world-wide coverage, disaster recovery / preparedness are only some of them. The obvious benefits of multi-cloud deployment are increased [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2>Introduction</h2>
<p style="text-align: justify;">This post will present interesting approach to scalability and reliability:</p>
<p style="text-align: center;"><strong>How to implement multi-cloud application deployment ?!</strong></p>
<p style="text-align: justify;">There are many reasons why this is interesting topic. Avoiding provider lockdown, reducing cloud provider outage impact, increasing world-wide coverage, disaster recovery / preparedness are only some of them. The obvious benefits of multi-cloud deployment are increased reliability and outage impact minimization. However, there are drawbacks too: supporting different sets of code to accommodate similar, but different services, increased cost, increased infrastructure complexity, different tools &#8230; Yet, despite the drawbacks, the possible benefits far outweigh the negatives!</p>
<p style="text-align: justify;">In the following article a simple service will be deployed in automated fashion over two different Cloud Service Providers: Amazon AWS and Joyent. Third provider, CloudFlare, will be used to service DNS requests. The choice of providers is not random. They are chosen because of particular similarities and because the ease of use. All of those providers have consistent, comprehensive APIs that allow automation through programming in parallel to the command line tools.</p>
<h2>Preliminary information</h2>
<p style="text-align: justify;">The service setup, described here, although synthetic, is representative of multiple usage scenarios. More complex scenarios are also possible. Special care should be taken to address use of common resources or non-replicable resources/states. Understand the dependencies of your application architecture before using multi-cloud setup. Or contact <a href="http://blog.xi-group.com/contact-us/">Xi Group Ltd.</a> to aid you in this process!</p>
<p style="text-align: justify;">The following Cloud Service Providers will be used to deploy executable code on:</p>
<ul>
<li><a href="https://aws.amazon.com/">Amazon AWS</a></li>
<li><a href="http://www.joyent.com/">Joyent</a></li>
</ul>
<p style="text-align: justify;">DNS requests will be served by <a href="https://www.cloudflare.com/">CloudFlare</a>. The test domain is: <strong>scalability.expert</strong></p>
<p style="text-align: justify;">Required tools are:</p>
<ul>
<li><a href="http://aws.amazon.com/cli/">Amazon AWS CLI</a></li>
<li><a href="https://github.com/joyent/node-smartdc">Joyent SmartDataCenter tools</a></li>
</ul>
<p style="text-align: justify;">Additional information can be found in <a href="http://aws.amazon.com/cli/">AWS CLI</a>, <a href="https://apidocs.joyent.com/cloudapi/">Joyent CloudAPI Documentation</a> and <a href="https://www.cloudflare.com/docs/client-api.html">CloudFlare ClientAPI</a>.</p>
<h2>Implementation Details</h2>
<p style="text-align: justify;">A service, website for <strong>www.scalability.expert</strong>, has to be deployed over multiple clouds. For simplicity, it is assumed that this is a static web site, served by NginX. It will run on Ubuntu 14.04 LTS. Instance types chosen in both AWS and Joyent are pretty limited, but should provide enough computing power to run NginX and serve static content. CloudFlare must be configured with basic settings for the DNS zone it will serve (in this case, the free CloudFlare account is used).</p>
<p style="text-align: justify;">Each computing instance, when bootstrapped or restarted, will start the NginX and register itself in CloudFlare. At that point it should be able to receive client traffic. Upon termination or shutdown, each instance should remove its own entries from CloudFlare thus preventing DNS zone pollution with dead entries. In a previous article, <a href="http://blog.xi-group.com/2014/06/how-to-implement-service-discovery-in-the-cloud/">How to implement Service Discovery in the Cloud</a>, it was discussed how <strong>DNS-SD</strong> can be implemented for similar setup with increased client complexity. In a multi-tier architecture this a proper solution. However, lack of control over the client browser may prove that a simplistic solution, like the one described here, is a better choice.</p>
<h3>CloudFlare</h3>
<p style="text-align: justify;">CloudFlare setup uses the free account and one domain, <strong>scalability.expert</strong>, is configured:</p>
<p><a href="http://blog.xi-group.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-18-at-1.18.32-PM.png"><img src="http://blog.xi-group.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-18-at-1.18.32-PM.png" alt="Screen Shot 2014-07-18 at 1.18.32 PM" width="985" height="154" class="alignnone size-full wp-image-288 img-thumbnail img-responsive" /></a> </p>
<p style="text-align: justify;">Basic configuration includes only one entry for the zone name:</p>
<p><a href="http://blog.xi-group.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-18-at-1.19.03-PM.png"><img src="http://blog.xi-group.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-18-at-1.19.03-PM.png" alt="Screen Shot 2014-07-18 at 1.19.03 PM" width="976" height="222" class="alignnone size-full wp-image-289 img-thumbnail img-responsive" /></a></p>
<p style="text-align: justify;">As seen by the orange cloud icon, the requests for this record will be routed through CloudFlare&#8217;s network for inspection and analysis!</p>
<h3>AWS UserData / Joyent Script</h3>
<p style="text-align: justify;">To automate the process of configuring instances, the following UserData script will be used:</p>
<p></p><pre class="crayon-plain-tag">#!/bin/bash -ex

# Debian apt-get install function
apt_get_install()
{
    DEBIAN_FRONTEND=noninteractive apt-get -y \
    -o DPkg::Options::=--force-confdef \
    -o DPkg::Options::=--force-confold \
    install $@
}
 
# Mark execution start
echo "STARTING" > /root/user_data_run
 
# Some initial setup
export DEBIAN_FRONTEND=noninteractive
apt-get update && apt-get upgrade -y

# Mark progress ...
echo "OS UPDATE FINISHED" >> /root/user_data_run
 
# Install required packages
apt_get_install jq nginx

# Mark progress ...
echo "SOFTWARE DEPENDENCIES INSTALLED" >> /root/user_data_run

# Create test html page
mkdir /var/www
cat > /var/www/index.html << "EOF"
<html>
    <head>
        <title>Demo Page</title>
    </head>
 
    <body>
        <center><h2>Demo Page</h2></center><br>
        <center>Status: running</center>
    </body>
</html>
EOF

# Configure NginX
cat > /etc/nginx/conf.d/demo.conf << "EOF"
# Minimal NginX VirtualHost setup
server {
    listen 8080;
 
    root /var/www;
    index index.html index.htm;
 
    location / {
        try_files $uri $uri/ =404;
    }
}
EOF
 
# Restart NginX with the new settings
/etc/init.d/nginx restart

# Mark progress ...
echo "NGINX CONFIGURED" >> /root/user_data_run

# /etc/init.d startup script
cat > /etc/init.d/cloudflare-submit.sh << "EOF"
#! /bin/bash
#
# Author: Ivo Vachkov (ivachkov@xi-group.com)
#
### BEGIN INIT INFO
# Provides: DNS-SD Service Group Registration / De-Registration
# Required-Start:
# Should-Start:
# Required-Stop:
# Should-Stop:
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description:    Start / Stop script for DNS-SD
# Description:          Use to JOIN/LEAVE DNS-SD Service Group
### END INIT INFO

set -e
umask 022

# DNS Configuration details
ZONE="scalability.expert"
HOST="www"
TTL="120"
IP=""

# CloudFlare oSpecific Settings
CF_HOST="https://www.cloudflare.com/api_json.html"
CF_SERVICEMODE="0" # 0: Disable / 1: Enable CloudFlare acceleration network

# Edit the following parameters with your specific settings
CF_TOKEN="cloudflaretoken" 
CF_ACCOUNT="account@cloudflare.com"

# Execution log file
LOG_FILE=/var/log/cloudflare-submit.log

source /lib/lsb/init-functions

export PATH="${PATH:+$PATH:}/usr/sbin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin"

# Get public IP
get_public_ip () {
        # Check what cloud provider this code is running on
        if [ ! -f "/var/lib/cloud/data/instance-id" ]; then
                echo "$0: /var/lib/cloud/data/instance-id is not available! Unsupported environment! Exiting ..."
                exit 1
        fi

        # Get the instance public IP address
        I_ID=`cat /var/lib/cloud/data/instance-id`
        if [[ $I_ID == i-* ]]; then
                # Amazon AWS
                IP=`curl http://169.254.169.254/latest/meta-data/public-ipv4`
        else
                # Joyent
                IP=`ifconfig eth0 | grep "inet addr" | awk '{print $2}' | cut -c6-`
        fi
}

# Default Start function
cloudflare_register () {
        # Get instance public IP address
        get_public_ip

        # Check the resutl
        if [ -z "$IP" ]; then
                echo "$0: Unable to obtain public IP Address! Exiting ..."
                exit 1
        fi

        # Execute update towards CloudFlare API
        curl -s $CF_HOST \
                -d "a=rec_new" \
                -d "tkn=$CF_TOKEN" \
                -d "email=$CF_ACCOUNT" \
                -d "z=$ZONE" \
                -d "type=A" \
                -d "name=$HOST" \
                -d "content=$IP" \
                -d "ttl=$TTL" >> $LOG_FILE
    
        # Get record ID for this IP
        REC_ID=`curl -s $CF_HOST \
                -d "a=rec_load_all" \
                -d "tkn=$CF_TOKEN" \
                -d "email=$CF_ACCOUNT" \
                -d "z=$ZONE" | jq -a '.response.recs.objs[] | .content, .rec_id' | grep -A 1 $IP| tail -1 | awk -F"\"" '{print $2}'`

        # Update with desired service mode
        curl -s $CF_HOST \
                -d "a=rec_edit" \
                -d "tkn=$CF_TOKEN" \
                -d "email=$CF_ACCOUNT" \
                -d "z=$ZONE" \
                -d "id=$REC_ID" \
                -d "type=A" \
                -d "name=$HOST" \
                -d "content=$IP" \
                -d "ttl=1" \
                -d "service_mode=$CF_SERVICEMODE" >> $LOG_FILE
}

# Default Stop function
cloudflare_deregister () {
        # Get instance public IP address
        get_public_ip

        # Check the resutl
        if [ -z "$IP" ]; then
                echo "$0: Unable to obtain public IP Address! Exiting ..."
                exit 1
        fi

        # Get record ID for this IP
        REC_ID=`curl -s $CF_HOST \
                -d "a=rec_load_all" \
                -d "tkn=$CF_TOKEN" \
                -d "email=$CF_ACCOUNT" \
                -d "z=$ZONE" | jq -a '.response.recs.objs[] | .content, .rec_id' | grep -A 1 $IP| tail -1 | awk -F"\"" '{print $2}'`

        # Execute update towards CloudFlare API
        curl -s $CF_HOST \
                -d "a=rec_delete" \
                -d "tkn=$CF_TOKEN" \
                -d "email=$CF_ACCOUNT" \
                -d "z=$ZONE" \
                -d "id=$REC_ID" >> $LOG_FILE
}

case "$1" in
start)
        log_daemon_msg "Registering $HOST.$ZONE  with CloudFlare ... " || true
        cloudflare_register
        ;;
stop)
        log_daemon_msg "De-Registering $HOST.$ZONE with CloudFlare ... " || true
        cloudflare_deregister
        ;;
restart)
        log_daemon_msg "Restarting ... " || true
        cloudflare_deregister
        cloudflare_register
        ;;
*)
        log_action_msg "Usage: $0 {start|stop|restart}" || true
        exit 1
esac

exit 0
EOF

# Add it to the startup / shutdown process
chmod +x /etc/init.d/cloudflare-submit.sh
update-rc.d cloudflare-submit.sh defaults 99

# Mark progress ...
echo "CLOUDFLARE SCRIPT INSTALLED" >> /root/user_data_run

# Register with CloudFlare to start receiving requests
/etc/init.d/cloudflare-submit.sh start

# Mark execution end
echo "DONE" > /root/user_data_run</pre><p></p>
<p style="text-align: justify;">This UserData script contains three components:</p>
<ol>
<li>
<p style="text-align: justify;"><strong>Lines 0 &#8211; 62</strong>: Boilerplate, OS update, installation and configuration of NginX;</p>
</li>
<li>
<p style="text-align: justify;"><strong>Lines 64 &#8211; 215</strong>: cloudflare-submit.sh, main script that will be called on startup and shutdown of the instance. cloudflare-submit.sh will register the instance&#8217;s public IP address with CloudFlare and set required protection. By default, protection and acceleration is off. Additional configuration is required to make this script work for your setup, account details must be configured in the specified variables!</p>
</li>
<li>
<p style="text-align: justify;"><strong>Lines 217 &#8211; 228</strong>: Setting proper script permissions, configuring automatic start of cloudflare-submit.sh and executing it to register with CloudFlare. </p>
</li>
</ol>
<p style="text-align: justify;">Code is reasonably straight-forward. init.d startup script is divided to multiple functions and output is redirected to a log file for debugging purposes. External dependencies are kept to a minimum. Distinguishing between AWS EC2 and Joyent instances is done by analyzing the instance ID. In AWS, all EC2 instances have instance IDs starting with &#8216;i-&#8216;, while Joyent uses (by the looks of it) some sort of UUID. This part of the logic is particularly important if the code should be extended to support other cloud providers!</p>
<p style="text-align: justify;">Both AWS and Joyent offer Ubuntu 14.04 support, so the <strong>same code can be use to configure the instances</strong> in automated fashion. This is particularly handy when it comes to data driven instance management and <a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">the DRY principle</a>. Command line tools for both cloud providers also offer similar syntax, which makes it easier to utilize this functionality.</p>
<h3>Amazon AWS</h3>
<p style="text-align: justify;">Staring new instances within Amazon AWS is straight-forward, assuming <strong>awscli</strong> is properly configured:</p>
<p></p><pre class="crayon-plain-tag">aws ec2 run-instances \
    --image-id ami-018c9568 \
    --count 1 \
    --instance-type t1.micro \
    --key-name test-key \
    --security-groups test-sg \
    --user-data file://userdata-script.sh</pre><p></p>
<h3>Joyent</h3>
<p style="text-align: justify;">Starting news instances within Joyent is somewhat more complex, but there is comprehensive <a href="https://apidocs.joyent.com/cloudapi/">documentation</a>:</p>
<p></p><pre class="crayon-plain-tag">sdc-createmachine \
    --account account_name \
    --keyId aa:bb:cc:dd:ee:ff:gg:hh:ii:jj:kk:ll:mm:nn:oo:pp \
    --name test \
    --package "4dad8aa6-2c7c-e20a-be26-c7f4f1925a9a" \
    --tag Name=test \
    --url "https://us-east-1.api.joyentcloud.com" \
    --metadata "Name=test" \
    --image 286b0dc0-d09e-43f2-976a-bb1880ebdb6c \
    --script userdata-script.sh</pre><p></p>
<p style="text-align: justify;">This particular example will start new SmartMachine instance using the <strong>4dad8aa6-2c7c-e20a-be26-c7f4f1925a9a</strong> package (g3-devtier-0.25-kvm, 3rd generation, virtual machine (KVM) with 256MB RAM) and <strong>286b0dc0-d09e-43f2-976a-bb1880ebdb6c</strong> (ubuntu-certified-14.04) image. SSH key details are supplied through the specific combinations of Web-interface settings and SSH key signature. For the list of available packages (instance types) and images (software stacks) consult the API: <a href="https://apidocs.joyent.com/cloudapi/#ListPackages">ListPackages</a>, <a href="https://apidocs.joyent.com/cloudapi/#ListImages">ListImages</a>.</p>
<p style="text-align: justify;"><strong>NOTE</strong>: Joyent offers rich Metadata support, which can be quite flexible tool when managing large number of instances!</p>
<h2>Successful service configuration</h2>
<p style="text-align: justify;">Successful service configuration will result in proper DNS entries to be added to the <strong>scalability.expert</strong> DNS zone in CloudFlare:</p>
<p><a href="http://blog.xi-group.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-18-at-4.12.43-PM.png"><img src="http://blog.xi-group.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-18-at-4.12.43-PM.png" alt="Screen Shot 2014-07-18 at 4.12.43 PM" width="1031" height="374" class="alignnone size-full wp-image-292 img-thumbnail img-responsive" /></a></p>
<p style="text-align: justify;">After configured TTL, those should be visible world-wide:</p>
<p></p><pre class="crayon-plain-tag">:~> nslookup www.scalability.expert
Server:         8.8.4.4
Address:        8.8.4.4#53

Non-authoritative answer:
Name:   www.scalability.expert
Address: 54.83.175.90
Name:   www.scalability.expert
Address: 165.225.137.102

:~></pre><p></p>
<p style="text-align: justify;">As seen, both AWS (54.83.175.90) and Joyent (165.225.137.102) IP addresses are returned, i.e. DNS Round-Robin. Service can simply be tested with:</p>
<p></p><pre class="crayon-plain-tag">:~> curl http://www.scalability.expert:8080/
<html>
    <head>
        <title>Demo Page</title>
    </head>

    <body>
        <center><h2>Demo Page</h2></center><br>
        <center>Status: running</center>
    </body>
</html>
:~></pre><p></p>
<p style="text-align: justify;">Resulting calls can be seen in the NginX log files on both instances:</p>
<p><a href="http://blog.xi-group.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-18-at-5.30.50-PM.png"><img src="http://blog.xi-group.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-18-at-5.30.50-PM.png" alt="Screen Shot 2014-07-18 at 5.30.50 PM" width="1284" height="1083" class="alignnone size-full wp-image-301 img-thumbnail img-responsive" /></a></p>
<p style="text-align: justify;"><strong>NOTE</strong>: CloudFlare protection and acceleration features are explicitly disabled in this example! It is strongly suggested to enabled them for production purposes!</p>
<h2>Conclusion</h2>
<p style="text-align: justify;">It should be clear now, that whenever software architecture follows certain design principles and application is properly decoupled in multiple tiers, the whole system can be deployed within multiple cloud providers. DevOps principles for automated deployment can be implemented in this environment as well. The overall system is with improved scalability, reliability and in case of data driven elastic deployments, even cost! Proper design is key, but the technology provided by companies like Amazon and Joyent make it easier to turn whiteboard drawings into actual systems with hundreds of nodes!</p>
<p>References</p>
<ul>
<li><a href="http://blog.xi-group.com/2014/06/how-to-implement-service-discovery-in-the-cloud/">How to implement Service Discovery in the Cloud</a></li>
<li><a href="https://aws.amazon.com/">https://aws.amazon.com/</a></li>
<li><a href="http://aws.amazon.com/cli/">http://aws.amazon.com/cli/</a></li>
<li><a href="http://www.joyent.com/">http://www.joyent.com/</a></li>
<li><a href="https://github.com/joyent/node-smartdc">https://github.com/joyent/node-smartdc</a></li>
<li><a href="https://apidocs.joyent.com/cloudapi/">https://apidocs.joyent.com/cloudapi/</a></li>
<li><a href="https://www.cloudflare.com/">https://www.cloudflare.com/</a></li>
<li><a href="https://www.cloudflare.com/docs/client-api.html">https://www.cloudflare.com/docs/client-api.html</a></li>
</ul>
<div class="rpbt_shortcode">
<h3>Related Posts</h3>
<ul>
					
			<li><a href="http://blog.xi-group.com/2014/06/how-to-implement-service-discovery-in-the-cloud/">How to implement Service Discovery in the Cloud</a></li>
					
			<li><a href="http://blog.xi-group.com/2015/02/how-to-deploy-single-node-hadoop-setup-in-aws/">How to deploy single-node Hadoop setup in AWS</a></li>
					
			<li><a href="http://blog.xi-group.com/2015/01/userdata-teplate-for-ubuntu-14-04-ec2-instances-in-aws/">UserData Template for Ubuntu 14.04 EC2 Instances in AWS</a></li>
					
			<li><a href="http://blog.xi-group.com/2014/11/small-tip-how-to-use-block-device-mappings-to-manage-instance-volumes-with-aws-cli/">Small Tip: How to use &#8211;block-device-mappings to manage instance volumes with AWS CLI</a></li>
					
			<li><a href="http://blog.xi-group.com/2015/01/small-tip-how-to-use-aws-cli-filter-parameter/">Small Tip: How to use AWS CLI &#8216;&#8211;filter&#8217; parameter</a></li>
			</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.xi-group.com/2014/07/how-to-implement-multi-cloud-deployment-for-scalability-and-reliability/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
