Full Stack StoryJekyll2020-07-11T15:32:21+00:00http://sahilsk.github.io/Sonu K. Meenahttp://sahilsk.github.io/sonukr666@gmail.comhttp://sahilsk.github.io/articles/adoption-of-git-backed-workflow-gitops2018-12-29T11:03:43+00:002018-12-29T11:03:43+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<p>When I first read about GitOps workflow by <a href="https://www.weave.works/blog/gitops-operations-by-pull-request">weave.works</a>, I was a bit surprised by their audacity.
I mean moving your deploy button from a central policy & compliance controlled dashboard locked by active directory into the wild in git where it’s visible to prying eyes, dying to commit to see their code up and running in production. That’s really a daunting move.</p>
<p>Especially for a business where every outage means loss in revenue, why would someone take chances with failures?</p>
<p>On second thought, in this cloud era, it all make sense. I can think of two main driving factor for adoption of gitops in coming days</p>
<ul>
<li><strong>Velocity</strong>: Gone are the days when quarterly or monthly deployments were enough. So, we need to minimize manual intervention as least as we could. Excuse of security and compliance should not hinder adoption of new technology. With open mindset you can bring the lost velocity back to your team</li>
<li><strong>Inefficiency of traditional processes</strong> and <strong>Adoption of more and more open-source tools</strong>: People are trying their best to make this world a better place. Adoption of public clouds eg. AWS or Azure, has given all a common ground to solve a problem once and solve it for all. Tools like terraform, jenkins, and vast knowledge spread across stackoverflow is at your perusal. Battles have already been fought. Use their sacrifice to improve life of others.</li>
</ul>
<p>Now, let’s talk about what are the pre-requisites. So, what has made such pure automation backed deployment workflows like GitOps possibles?</p>
<ul>
<li><strong>Automate every manual steps</strong>: First and foremost be reasonable behind every process you have. Have a constructive arguments for having a manual step for a automatable workflow. Chances are you don’t need those manual interventions.</li>
<li><strong>Good test coverage</strong>: Adopt <a href="https://martinfowler.com/bliki/TestPyramid.html">test-pyramid</a> thinking. Have a fine balance between unit and functional tests. More functional tests means more time to complete. So, as much as you can, move 70% of your test cases in unit tests and keep rests for functional and end-to-end tests. This will help you balance velocity and reliability.</li>
<li><strong>Diff</strong>: Find a way to generate a diff of your already deployed application and to be deployed one. If you are using k8s you can leverage <a href="https://github.com/weaveworks/kubediff">kubediff</a> or if you are using terraform in your enviroment you can use <a href="https://www.terraform.io/docs/commands/plan.html">terraform plan</a> command. This will help you make decisions whether the new version is good to go without any destructive consequences. This step is very important and it’s very important to get it right. Destructive actions could be eg. giving application limit-requests that your cluster can’t handle, or too open or too close firewall policy, opening ports that are not supposed to be opened, etc.</li>
<li>
<p><strong>Git branch</strong>: Respect git branches and keep all branches as close as possible. For a promotion based environments you need to start with at least two branches: <strong>qa</strong> and <strong>master</strong> or (develop and master).</p>
<p>Every commit in qa branch is deployed in the qa environment. When QA guys give you a go-ahead for production, create a pull request out of QA branch and merge it in the master branch. This will be the trigger for deployment in the production. If anything fails, don’t rollback anything manually. Commit, send a new pull request and repeat.</p>
</li>
</ul>
<p>Sounds easy but you can’t go ahead and start doing gitops right away. You need a headstart. So, here are some simple steps to help you get started with gitOps.</p>
<p><img src="/images/gitops-gitrepo.jpg" alt="GitOps Workflow" /></p>
<ol>
<li>Create new repository</li>
<li>Create three(or more as per your enviroments) branches: QA, STAGING and PROD</li>
<li>Create deployment desciptors. One descriptors for each individual services which has the minimal application configuration required by your deployment automation. Eg.
<ul>
<li><code class="language-plaintext highlighter-rouge">Application version</code></li>
<li><code class="language-plaintext highlighter-rouge">healthcheck_endpoints</code></li>
<li><code class="language-plaintext highlighter-rouge">healthcheck retry and timeout</code>: Some application e.g java ones just takes a bit time to bootstrap.</li>
<li><code class="language-plaintext highlighter-rouge">domain and port</code></li>
<li><code class="language-plaintext highlighter-rouge">cpu/ram quota</code>: For docker/k8s applications, have a hard limit on resources</li>
<li><code class="language-plaintext highlighter-rouge">required ports</code></li>
<li><code class="language-plaintext highlighter-rouge">notification channels: [Emails][,Slack channels]</code></li>
<li><code class="language-plaintext highlighter-rouge">maintainer address</code></li>
</ul>
</li>
<li>Copy same descriptors in all the branches. By looking at those descriptors one should be able to tell which environment has what version of a paritcular service running. By looking at commits he should also be able to tell last deployments history.</li>
<li>Use jenkins to write following generic parametrized pipelines
<ul>
<li><strong>Healthcheck pipeline</strong>: Given set of parameters eg. service name, it goes and run health check for the service.</li>
<li><strong>Deploy Pipeline</strong>: Given service with version and enviroment, it should go and deploy it.</li>
<li><strong>Smoke Test Pipeline</strong>: Generic parametrized pipeline to run post deployment checks on a service specified</li>
<li><strong>Regression Test Pipeline</strong>: Generic parametrized pipeline to run end-to-end tests for any service specificed in the run arguments.</li>
</ul>
</li>
<li>Now, with all the generic pipelines ready, you need to build a high-level pipeline that combine all these steps together. These will be our Release Pipelines. It should have a notification stage before and end of pipeline to notify stakeholders including JIRA.
<ul>
<li><strong>QA Release Pipeline</strong>: <code class="language-plaintext highlighter-rouge">Deploy Pipeline</code> + <code class="language-plaintext highlighter-rouge">Healthcheck Pipeline</code></li>
<li><strong>Stage Release Pipeline</strong>: <code class="language-plaintext highlighter-rouge">Deploy Pipeline</code> + <code class="language-plaintext highlighter-rouge">Healthcheck Pipeline</code> + <code class="language-plaintext highlighter-rouge">Regression Pipeline</code></li>
<li><strong>Prod Release Pipeline</strong>: <code class="language-plaintext highlighter-rouge">Deploy Pipeline</code> + <code class="language-plaintext highlighter-rouge">Healthcheck Pipeline</code> + <code class="language-plaintext highlighter-rouge">Smoke Test Pipeline</code></li>
</ul>
</li>
<li>At this point you should be able to deploy your service using above release pipeline, passing parameters like service, version and environment to deploy any application in any envrionment. But only one flaw: It still require manual button press. Lets trigger these release pipeline using Git</li>
<li>Git-Monitor Pipeline: This pipeline will track pushes in each of the branches and based on the diff using tools discussed above, will trigger any of the <strong>Release Pipeline</strong>. Be caseful for writing this pipeline. It should have following notable checks
<ul>
<li>Commit message must not contain any message like <code class="language-plaintext highlighter-rouge">skip deployment</code>. If it does, then you’re not suppose to deploy this commit</li>
<li>Committer should be a whitelisted candidates</li>
<li>Commit message should have a valid JIRA ticket, where the pipeline go and check for valid approvals and commit deployment statuses as per compliance requirement.</li>
<li>Lastly, take the diff of the deployed version and the requested version to make decision to allow or reject.</li>
<li>IF all is good, call the <code class="language-plaintext highlighter-rouge">{ <Environment> Release Pipeline }</code> to deploy your changes.</li>
<li>While deploying for higher enviornments eg. prod, please take more conditions under consideration that suits your company culture and policy.</li>
</ul>
</li>
</ol>
<h2 id="git-branch-policy">Git Branch Policy</h2>
<p>Idea of promotional deployments is to move changes from lower environment to higher environments and each increment gives you a sense of more and more reliable changes coming upstream. Hence, it’s important that every environment has similar infrastructure setup( at low scale) and same set of instructions, and deployable artifacts.</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">QA Branch</code> : Ideally, every commit should make it here with least friction possible. Make your nightly build job pipeline to auto-commit the new version in this branch whenever the new application version is ready to trigger automatic deployment. <code class="language-plaintext highlighter-rouge">QA</code> are made to be broken, so failing fast is good. Hence, it should have zero manual intervention.</li>
<li><code class="language-plaintext highlighter-rouge">Stage Branch</code>: That should be comparatively stable and very close to production. If it’s broken then folks like capacity planning, regression testers will be very mad at you. Once you have a stable QA version ready, create a PR and merge it in this stage branch after peer review.</li>
<li><code class="language-plaintext highlighter-rouge">Prod Branch</code>: Apply the same scrutiny here.</li>
</ul>
<h2 id="extras">Extras</h2>
<ul>
<li>Integration with JIRA and Slack.</li>
<li>On every deployment failure, create a JIRA ticket and assign to the committer. This will help you improve reliability of your dpeloyments gradually</li>
<li>Pull reports out of git commits, JIRA tickets and pipelines to keep track of frequency of deployments, time to deploy, frequency of failed deployments, and use these metrics to improve your process.</li>
</ul>
<p>I’ve done something similar in our docker based services.</p>
<h2 id="benefits">Benefits</h2>
<ul>
<li>No baby sitting or hand holding during deployments.</li>
<li>QA, Devs, Testers no longer has to maintain or worry about deployments. They know new version is just one commit away.</li>
<li>Rollback is easy and transparent to the team.</li>
<li>Bringing sense of ownership to every commit: <strong>You break it, you fix it</strong></li>
</ul>
<p>Well, think no more, with unwavering faith in your team plunge into GitOps. And you should be able to reduce a significant toil work with this full fledge automatic deployment and rollover workflow.</p>
<p>This post is a summary of our adoption to GitOps workflow and learnings that are worth sharing with others.</p>
<p><a href="http://sahilsk.github.io/articles/adoption-of-git-backed-workflow-gitops/">Adoption of Git backed automation Workflows: GitOps</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on December 29, 2018.</p>http://sahilsk.github.io/articles/site-to-site-vpn-setup-on-aws2017-01-06T09:30:05+00:002017-01-06T09:30:05+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr666@gmail.com<h2 id="how-to-guide-on-setting-up-site-to-site-vpn-across-regions">How-to guide on setting up site-to-site vpn across regions.</h2>
<p>VPC peering allows you to peer VPC’s as long as they are in the same region and have unique CIDR. But what if your VPC’s are across regions.</p>
<p>Lets say you want connectivity between servers running in two different region: Singapore and Mumbai. You may want to setup database slaves in different regions for disaster recovery or your application may want to reach client side for business requirement? And, being DevOpSec you also want the traffic flow to be fully encrypted as well.</p>
<p>Whatever may be the reason you want fully encrypted traffic flow to-and-fro vpc in one region to another region. This article is about setting up one such solution to this problem using IPSec.</p>
<h2 id="ipsec-comes-into-picture">IPSec comes into picture</h2>
<p>IPSec is an Internet Engineering Task Force (IETF) standard suite of protocols that provides data authentication, integrity, and confidentiality as data is transferred between communication points across IP networks. Best part is IPSec provides data security at the IP packet level. IPSec emerged as a viable network security standard because enterprises wanted to ensure that data could be securely transmitted over the Internet. IPSec protects against possible security exposures by protecting data while in transit.</p>
<p>Ipsec-tools , openswan, strongswan, libreswan etc are few such implementations of IPSec Protocol.</p>
<p>IPSec emerged as a viable network security standard because enterprises wanted to ensure that data could be securely transmitted over the Internet. IPSec protects against possible security exposures by protecting data while in transit.</p>
<h2 id="how-are-we-doing">How are we doing?</h2>
<p>Read through this <a href="http://www.slashroot.in/linux-ipsec-site-site-vpnvirtual-private-network-configuration-using-openswan">article</a> before continuing from here.
I strongly recommend it. It’ll help you understand configuration parameters better.</p>
<ul>
<li>Launch two servers one in each VPC in public subnet with new security group</li>
<li>Install openswan on both of them</li>
<li>configure openswan</li>
<li>configure both VPCs route tables</li>
<li>Test connectivity</li>
</ul>
<p>For understanding let say we have following VPC’s in our infrastructure</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>region Private IP Public IP Subnet
-------------------------------------------------------------------------------
Mumbai 172.19.1.132 52.66.100.2 172.19.0.0/16
singapore(stage) 172.27.7.141 54.155.125.80 172.27.0.0/16
singapore(dev) 172.25.135.54 52.67.12.236 172.25.0.0/16
</code></pre></div></div>
<h2 id="installing-openswan-on-centos-7">Installing Openswan on CentOS 7</h2>
<p>Make sure you are launching a public server and accessible via internet. Thereafter, install openswan on them.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yum install openswan lsof
</code></pre></div></div>
<p>Install it at both side servers in singapore stage vpc and mumbai vpc.</p>
<h2 id="configure-openswan">Configure openswan</h2>
<h3 id="singapore-stage-vpc">Singapore Stage VPC:</h3>
<p>Create configuration file and put obvious details. For more understanding consider ‘left’ as your source i.e currently loggedin server detail and ‘right’ is your destination side details</p>
<p>Create configuration file <code class="language-plaintext highlighter-rouge">stg-sg-to-mumbai.conf</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /etc/ipsec.d
cat > stage-sg-to-mumbai.conf
conn stage-sg-to-mumbai
type=tunnel
authby=secret
left=%defaultroute
leftid=54.155.125.80
leftnexthop=%defaultroute
leftsubnet=172.27.0.0/16
right=52.66.100.2
rightsubnet=172.19.0.0/16
pfs=yes
auto=start
</code></pre></div></div>
<p>For authentication we’ll be using Pre Shared Key.</p>
<p>Create secret file with format similar to shown below:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> leftPublicIp RightPublicIp: PSK <KEY GOES HERE>
</code></pre></div></div>
<p>Create <code class="language-plaintext highlighter-rouge">stage-sg-to-mumbai-secret.secrets</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> cat > stage-sg-to-mumbai-secret.secrets
54.155.125.80 52.66.100.2: PSK "mySuperSecretGoesHere"
</code></pre></div></div>
<p>Restart swan and run verify</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service ipsec restart; tail -F /var/log/messages
service ipsec status
</code></pre></div></div>
<p>To verify use following command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ipsec verify
</code></pre></div></div>
<p>Next, disable check for source destination check. Go to <code class="language-plaintext highlighter-rouge">Action -> Networking -> Change Source/Dest. Check -> Disable</code>
<img src="/images/src-dest-disable.png" alt="source-destination check" /> and disable it.
<img src="/images/disablecheck.png" alt="disable prompt" /></p>
<p>Security group need to be tweaked too:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Type Protocol PortRange Source Why
All traffi All All 172.19.0.0/16 ie. receive from mumbai vpc
All traffic All All 172.25.0.0/16 ie. receive fromm singapore dev vpc
All traffic All All 52.66.100.2/32 ie. receive from mumbai openswan server
SSH TCP 22 <myJumpHostIp>/32 ie. ssh access via jump host only
ALL ICMP ALL N/A 0.0.0.0/0 ie. for mysql master-slave replication to work
</code></pre></div></div>
<h3 id="mumbai--vpc">Mumbai VPC</h3>
<p>Create configuration file <code class="language-plaintext highlighter-rouge">stg-mumbai-to-sg.conf</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /etc/ipsec.d
cat > stg-mumbai-to-sg.conf
conn stg-mumbai-to-sg
type=tunnel
authby=secret
left=%defaultroute
leftid=52.66.100.2
leftnexthop=%defaultroute
leftsubnet=172.19.0.0/16
right=54.155.125.80
rightsubnet=172.27.0.0/16
pfs=yes
auto=start
</code></pre></div></div>
<p>Again create secret. Make sure both side openswan servers has same secret key. Otherwise authentication will fail.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat > stg-mumbai-to-sg.secrets
52.66.100.2 54.155.125.80: PSK "mySuperSecretGoesHere"
</code></pre></div></div>
<p>Restart swan and run verify</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service ipsec restart; tail -F /var/log/messages
service ipsec status
</code></pre></div></div>
<p>To verify use following command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ipsec verify
</code></pre></div></div>
<p>Next, disable check for source destination check. Same way as we did in singapore region. Consult screenshots above.</p>
<p>Security group need to be tweaked too:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Type Protocol PortRange Source Why
All traffic All All 172.19.0.0/16 ie. receive from mumbai vpc
All traffic All All 172.25.0.0/16 ie. receive fromm singapore dev vpc
All traffic All All 54.155.125.80/32 ie. receive from singapore openswan server
SSH TCP 22 <myJumpHostIp>/32 ie. ssh access via jump host only
ALL ICMP ALL N/A 0.0.0.0/0 ie. for mysql master-slave replication to work
</code></pre></div></div>
<h4 id="oh-wait-we-have-two-vpc-running-in-singapore-region-stage-and-dev-how-do-we-connect-dev-vpc-also-with-mumbai-vpc-">oh wait.. we have two vpc running in singapore region: Stage and Dev. How do we connect Dev VPC also with mumbai VPC ?</h4>
<p>We’ll be required to launch one more openswan server running in dev VPC and make configuration at mumbai side vpc to receive traffic for this also.</p>
<h4 id="cant-we-use-the-same-openswan-public-server-that-weve-launched-in-stage-vpc">Can’t we use the same openswan public server that we’ve launched in stage VPC?</h4>
<p>No. because route tables are in different VPC. Route table won’t let you select instance running in different VPC to route traffic to. Therefore, you cannot your routing rules there. Hence, a second server need to be launched in dev vpc too.</p>
<p>At mumbai side, since we have only one VPC we can use the same openswan server but with one more configuration to add this dev vpc network information. Also, we’ll add one more route entry in the same route tables. Example entries are shown below.</p>
<h3 id="to-have-singapore-dev-vpc-connectivity-with-mumbai-vpc">To have singapore dev vpc connectivity with mumbai VPC</h3>
<ul>
<li>launch openswan server in public subnet of dev vpc using steps given above. Make sure you have a new security group here also.</li>
<li>Add following configuration changes</li>
</ul>
<h4 id="singapore-dev-vpc">Singapore Dev VPC</h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /etc/ipsec.d/
cat > dev-sg-to-mumbai.conf
conn dev-sg-to-mumbai
type=tunnel
authby=secret
left=%defaultroute
leftid=52.67.12.236
leftnexthop=%defaultroute
leftsubnet=172.25.0.0/16
right=52.66.100.2
rightsubnet=172.19.0.0/16
pfs=yes
auto=start
</code></pre></div></div>
<p>Don’t forget to add secret file as well</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat > dev-sg-to-mumbai.secrets
52.67.12.236 52.66.100.2: PSK "mySuperSecretGoesHere"
</code></pre></div></div>
<p>Restart swan and run verify</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service ipsec restart; tail -F /var/log/messages
service ipsec status
</code></pre></div></div>
<p>To verify use following command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ipsec verify
</code></pre></div></div>
<p>Next, disable check for source destination check. Same way as we did in singapore region. Consult screenshots pasted before.</p>
<h4 id="mumbai-vpc">Mumbai VPC</h4>
<p>Since we’re using same VPC we can use the same openswan server and add just a new configuration there</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /etc/ipsec.d
cat > dev-mumbai-to-sg.conf
conn mumbai-to-ap
type=tunnel
authby=secret
left=%defaultroute
leftid=52.66.100.2
leftnexthop=%defaultroute
leftsubnet=172.19.0.0/16
right=52.67.12.236
rightsubnet=172.25.0.0/16
pfs=yes
auto=start
</code></pre></div></div>
<p>Add secret as well</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat > dev-mumbai-to-sg.secrets
52.66.100.2 52.67.12.236: PSK "mySuperSecretGoesHere"
</code></pre></div></div>
<p>Restart swan and run verify</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service ipsec restart; tail -F /var/log/messages
service ipsec status
</code></pre></div></div>
<p>To verify use following command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ipsec verify
</code></pre></div></div>
<h2 id="modify-route-table">Modify route table</h2>
<p>We need to modify vpc route tables so that we can route traffic from singapore vpc to mumbai vpc and vice versa.
Route table simply says packet with given <code class="language-plaintext highlighter-rouge">Destination</code> should go via this <code class="language-plaintext highlighter-rouge">Target</code>. And ‘Target’ will send packet to its right owner.</p>
<p>Example:</p>
<h3 id="mumbai-vpc-route-table">Mumbai VPC Route table</h3>
<p>Here we’re modifying mumbai vpc route table. We’re telling it that packets with destination <172.25.0.0/16>(singapore dev vpc subnet) or <172.27.0.0/16>(singapore stage vpc subnet) should go via mumbai openswan server identified by instance id as shown in the screenshot. Do similar changes for all route tables whosever subnet you want connectivity to be setup.</p>
<p><img src="/images/routetableexample.png" alt="route table example config" /></p>
<p>Same changes are required at Singapore side stage VPC routebles.</p>
<h2 id="test-connectivity">Test Connectivity</h2>
<p>Lets say <code class="language-plaintext highlighter-rouge">Server-A-In-Sg</code> listening on port <code class="language-plaintext highlighter-rouge">XYZ</code> want to reach <code class="language-plaintext highlighter-rouge">Server-B-In-Mumbai</code> listening on port <code class="language-plaintext highlighter-rouge">PQR</code>. Server-A-In-Sg security group will allow port XYZ from Server-B-In-Mumbai private ip say, <code class="language-plaintext highlighter-rouge">172.19.x.y</code>.</p>
<p>Similarly, Server-B-In-Mumbai security group should allow traffic for port PQR from Server-A-In-Sg say, <code class="language-plaintext highlighter-rouge">172.25.p.q</code> .
That’s all required. You dont’ have to add openswan server ip also again here in security groups because they are already added in route table.</p>
<blockquote>
<p>PS: For mysql-slave replication to work do enable ICMP traffic also.</p>
</blockquote>
<p>To test you may use telnet utility:</p>
<p>From Server-A-In-Sg server try reaching Mumbai side server:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>telnet 172.19.x.y XYZ
</code></pre></div></div>
<p>From Server-B-In-Mum server try reaching Singapore side server:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>telnet 172.25.p.q PQR
</code></pre></div></div>
<p>If you see conected message you are all up.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Openswan configuration is very easy to understand and write. On AWS all firewall level settings are taken care by security grups and route table thereby making process more snappier.
One may have some concerns for production setup. Like how to make it highly available? There Linux-HA can be used with floating ip technique. But more on this, perhaps in next article.</p>
<h2 id="related-articles">Related articles</h2>
<ul>
<li><a href="https://aws.amazon.com/articles/5472675506466066">Connecting Multiple VPCs with EC2 Instances(IPSec)</a></li>
</ul>
<p><a href="http://sahilsk.github.io/articles/site-to-site-vpn-setup-on-aws/">Site-to-site Vpn Setup on Aws</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on January 06, 2017.</p>http://sahilsk.github.io/articles/faas-for-ec2-auditing2016-09-17T12:25:59+00:002016-09-17T12:25:59+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<p>We know FaaS, function as a service are now the big thing in the market.
AWS lambda, and webtask.io are few good implementations that help you write
serverless code.</p>
<p>You can read more about serverless architecture on <a href="http://www.martinfowler.com/articles/serverless.html">martin fowler
blog</a>.</p>
<p>Here i want to pen down one of the use case that fit perfectly for FaaS: Auditing</p>
<p>With growing team it become difficult to audit your infrastructure as more and
more resources are being created. Are tagging standards are being followed or not, are
security groups security guidelines are followed or not, or the right ssh-key
pair, image-id or what-not is used for creation of new resources or not.</p>
<p>So, wouldn’t it be great if we can write one service that poll aws resources
periodically and get us this audit report? YES. But …</p>
<p>You then have to create infrastructure for this service or cron to run. Launch server,
create image, put monitoring and what not. It’s a pain.</p>
<p>But there is one friendly, quick and very cheap way of doing it. Enter: FAAS.</p>
<p>Create your function and you are done. Seriously. That’s all it require.</p>
<p>Webtask.io is one such FaaS. Though AWS lambda is also there but i found webtask.io deployment more easier and snappy.</p>
<h2 id="difference-between-aws-lambda-vs-webtaskio">Difference between AWS Lambda vs Webtask.io</h2>
<ul>
<li>webtask.io currently supports only node.js and it support it pretty well. AWS
Lambda on the other hand have programming langauge supports.</li>
<li>webtask.io deployment is easy but how does it handle new deployment is kind of
scary. All happen behind the back for you. There is no canary testing support.
Like in case of failure you want to rollback to a old version. In
webtask.io you have to deploy it again, where in AWS Lambda you just need
switch pointer to last working code as in capistrano.</li>
<li>Code written for webtask.io can be run as it in aws lambda without little or
not change at all. Webtask.io support AWS lambda compatible <a href="https://webtask.io/docs/model">programming model</a> as well.</li>
<li>webtask.io has rich editor that not only highlight code, but also do syntax
check. 70% errors you can avoid here only.</li>
<li>AWS lambda docs are very rich and you can finally, every piece of information
there.</li>
<li>realtime debugging is very easy in webtask.io with their streaming logs. It
mean less context switching.</li>
<li>pricing ???</li>
</ul>
<p>While working with webtask.io i found some areas that can be improved further.
Here are some of them:</p>
<ul>
<li>Text editor has syntax check support but would be great if before deploying
webtask client itself can run a syntax check and throw error on console. It’s
painfully very sad seeing your baby crying due to a typo.</li>
<li>Webtask.io secrets and data storage strategy is very simple to use but
difficult to figure out in the starting. Little more documentation could have helped here.</li>
</ul>
<p>Here, in this short tutorial i’ll be using webtask.io for writing one auditing
service.</p>
<h2 id="what-are-we-doing">What are we doing?</h2>
<p>We’ll be creating a auditing service that check if launched instance has tags as
per audit rules or not.
Resource taggging has many benefits but important one is to track <a href="http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html#tag-resources-for-billing">aws resource billing</a></p>
<h2 id="how-are-we-doing">How are we doing?</h2>
<p>We’ll be writing a node.js program that will listen to cloudwatch events.
Cloudwatch is an aws service that emits aws events you can subscribe to. These
events can be a launch of an ec2 instance. This is what we’ll be tracking.
To subscribe out audit service to cloudwatch events we must create AWS SNS topic
where cloudwatch will send filtered out events pertaining to our rules only.</p>
<p><img src="/images/cloudwatch_event_rule.png" alt="Alt cloudwatch" /></p>
<p>When an instance is launched, event is emitted by cloudwatch and goes to SNS topic.
SNS topic(<code class="language-plaintext highlighter-rouge">ec2_launches_check</code>) will then hit our audit serivce endpoint with payload
containing instance id. On this instance id, our auditing service will run
audit checks.</p>
<p>Currently, we’re checking if instance has “name” and “service” tag
present or not. If it violate this rule, then our auditing service will dispatch alert.
There are different places where this alert logic can be put:</p>
<ul>
<li>Write in the code to send mail/pagerduty alert using 3rd party services like mailgun, etc.</li>
</ul>
<p>There is a problem with that. If tomorrow you have to update alert subscribers list, you then have to modify the code or update the environment.</p>
<p>Wouldn’t it be better if we can publish alert to one middleware where subscriber
can be added and removed conveniently through nice GUI? AWS SNS topic is one
such place. So, our audit service will publish alert to another AWS SNS topic(<code class="language-plaintext highlighter-rouge">ec2_audit_alert</code>). And
subscribers can subscribe to it via SMS, EMAIL or call another 3rd party
service.</p>
<p><img src="/images/faas_ec2_auditing.png" alt="Alt architecture" /></p>
<h2 id="imlementation-show-me-the-code">Imlementation: show me the code</h2>
<ul>
<li>Create two aws SNS topic: <code class="language-plaintext highlighter-rouge">ec2_launches_check</code>, and <code class="language-plaintext highlighter-rouge">ec2_audit_alert</code></li>
<li>Write audit service in node.js</li>
<li>Create webtask.io task and deploy it with aws credentials and alert topic
arn(<code class="language-plaintext highlighter-rouge">ec2_audit_alert</code>). Code is smart enough to subscribe to this sns automatically.</li>
<li>Create aws cloudwatch event rule and point it to <code class="language-plaintext highlighter-rouge">ec2_launches_check</code> sns.</li>
</ul>
<h2 id="here-is-the-result">Here is the result</h2>
<p><img src="/images/audit_result.png" alt="Alt audit-result" /></p>
<p>That’s it. You can the find <a href="https://github.com/sahilsk/webtask.io-examples">project repo
here</a></p>
<p><a href="http://sahilsk.github.io/articles/faas-for-ec2-auditing/">FaaS for Ec2 Auditing</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on September 17, 2016.</p>http://sahilsk.github.io/articles/how-to-write-a-cron2016-04-04T12:02:35+00:002016-04-04T12:02:35+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<h2 id="how-to-write-a-good-cron">How to write a good cron?</h2>
<p>A good cron should adhere to unix philosophy of single-responsibility-principle.
To elaborate further, your cron should do only one thing and should do it right.
Keeping cron code simple and modular will not only help you debug issues easily,
but also help you inherent learning from one cron to another.</p>
<p>Here are few learnings that one can use while writing workers.</p>
<h3 id="q-what-cron-should-do">Q. What cron should do?</h3>
<ul>
<li>Cron script should be light weight and should work as a helpers for workers.</li>
<li>Cron should create a job , push them to queue and finish. These job would then be processed by workers.</li>
<li>Cron should fail fast and finish fast</li>
</ul>
<h3 id="q-what-cron-should-not-do">Q. What cron should not do?</h3>
<ul>
<li>Cron should never do any processing task.</li>
<li>Cron should not to do any long running operation failure of which can create inconsistencies</li>
</ul>
<h2 id="other-important-considerations">Other important considerations:</h2>
<h3 id="logging">Logging</h3>
<ul>
<li>Logs are your single source of truth. If they’re lost, you are left scratching scratching your head finding answers to simple bugs</li>
<li>What to log and what not to log, however could be tricky. To keep it simple
we advise you never to log any client/customer data. If credentials or
secrets are required, that should also not be part of your log output.</li>
<li>Here are few simple commandments to follow:
<ul>
<li>Do no log client/customer data</li>
<li>Secrets and credentials should not be part of logs</li>
<li>No secrets should be provided as run arguments instead use wrapper run script, if required</li>
<li>Make use of environment variables as much as possible.</li>
</ul>
</li>
<li>Ship logs to graylog</li>
</ul>
<h3 id="alerting">Alerting</h3>
<ul>
<li>If your cron raise error it should raise alert right away.</li>
<li>Handle every exeception, categorise them and push them to sentry. If immediate attention is required then don’t be afraid to raise pagerduty alert</li>
<li>post errors/warning to sentry</li>
</ul>
<h2 id="faq">FAQ</h2>
<h4 id="q-how-to-know-if-my-cron-run-successfully-or-not">Q. How to know if my cron run successfully or not?</h4>
<p>A. — Read Logging part—</p>
<h4 id="q-how-to-get-alert-on-failed-cron-run">Q. How to get alert on failed cron run?</h4>
<p>A. Cron can be failed due to three reasons:</p>
<ul>
<li>
<p>System kill it eg. oom killer
Why was cron doing resource intensive operation at first place? Make it light weight</p>
</li>
<li>
<p>Exception raised in code
Poor exception handing can abort cron. So, improve code quality and log exception on sentry or graylog.
On exception raise pagerduty alerty right away</p>
</li>
<li>
<p>Somebody kill/shift/removed cron from server
– Read next faq –</p>
</li>
</ul>
<h4 id="q-what-if-somebody-removed-shiftremoved-cron-from-server">Q. What if somebody removed shift/removed cron from server?</h4>
<p>A. Improve team collaboration. Keep everybody in sync.
Avoid manual changes on server. Make crons part of code deployment.
If automation is not in place, contact DevOps to bring it ASAP</p>
<h4 id="q-how-to-check-if-cron-run-on-particular-day-or-not">Q. How to check if cron run on particular day or not?</h4>
<p>A. Check in graylog. If it’s not there check in sentry. If it is nowhere,
god bless you</p>
<h4 id="q-shouldnt-devops-monitor-cron-for-us">Q. Shouldn’t devops monitor cron for us?</h4>
<p>A. Go bald and die</p>
<p><a href="http://sahilsk.github.io/articles/how-to-write-a-cron/">How to Write a Cron?</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on April 04, 2016.</p>http://sahilsk.github.io/articles/how-to-write-a-good-worker2016-04-04T08:57:53+00:002016-04-04T08:57:53+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<h2 id="how-to-write-a-good-worker">How to write a good worker?</h2>
<p>A good worker should adhere to unix philosophy of single-responsibility-principle.
To elaborate further, your worker should do one thing and should do it right.
Keeping worker code simple and modular will not only help you debug issues
easily, but also help you inherent learning from one worker to another.</p>
<p>Here are few of these learnings that one can use while writing workers. In the
end you’ll have a robust worker that work as intended.</p>
<h3 id="logging">Logging</h3>
<ul>
<li>
<p>Logs are your single source of truth. If they’re lost, you are left scratching scratching your head finding answers to simple bugs</p>
</li>
<li>
<p>What to log and what not to log, however could be tricky. To keep it simple we
advise you never to log any client/customer data. If credentials or secrets are
required, that should also not be part of your log output.</p>
</li>
<li>
<p>Here are few simple commandments to follow:</p>
<ul>
<li>Do no log client/customer data</li>
<li>Secrets and credentials should not be part of logs</li>
<li>No secrets should be provided as run arguments instead use wrapper run script,
if required</li>
<li>Make use of environment variables as much as possible. They are more
reliable than human provided configs</li>
<li>Use graylog to send logs to, to avoid SSH</li>
</ul>
</li>
</ul>
<h3 id="retry-reque-die">Retry->Reque->Die</h3>
<ul>
<li>If worker run on some queue than for every message it failed to process, it
must push it back to queue to retry again.</li>
<li>It should not retry forever. After , let say 3 times retry it should raise alert</li>
<li>Use aws SQS deadletter queue and visibility timeout feature for this</li>
</ul>
<h3 id="alert">Alert</h3>
<ul>
<li>If your worker found any critical issue, it should raise alert or inform
other rather than depending on other to raise alert for you</li>
</ul>
<p>Third Party Service</p>
<ul>
<li>
<p>If worker is relying on any third party service, it should use circuit-breaker pattern</p>
<ul>
<li>Put timeout on these service response time</li>
<li>If service didn’t respond back , retry again and fail fast</li>
<li>Report or alert if 3rd party service is not reliable enough.</li>
<li>http://doc.akka.io/docs/akka/snapshot/common/circuitbreaker.html</li>
</ul>
<p><img src="http://sahilsk.github.io/images/circuit-breaker.png" alt="Circuit-Breaker" /></p>
</li>
</ul>
<p><a href="http://sahilsk.github.io/articles/how-to-write-a-good-worker/">How to Write a Good Worker?</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on April 04, 2016.</p>http://sahilsk.github.io/articles/how-to-create-a-good-ami2015-07-21T10:55:58+00:002015-07-21T10:55:58+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<h2 id="what-is-amazon-machine-imageami">What is Amazon Machine Image(AMI)?</h2>
<p>Quoting from wikipedia:</p>
<blockquote>
<p>An Amazon Machine Image (AMI) is a special type of virtual appliance that is used to instantiate (create) a virtual machine within the Amazon Elastic Compute Cloud (“EC2”). It serves as the basic unit of deployment for services delivered using EC2. ~wikipedia</p>
</blockquote>
<p>Thank you wikipedia (:</p>
<h2 id="benefits-of-using-ami">Benefits of using AMI</h2>
<ul>
<li>
<p>fast server provisioning and spinning</p>
<ul>
<li>
<p>With the base system ready you don’t need to perform same provisioning steps evertime you spin up new instance. Server Provisioning may include ntp setup, user provisioning eg. grant team access to server, application provisioning eg. installing app/web servers , or embedding orgnaization/3rd party credentials in environment variables and many more.</p>
</li>
<li>
<p>Since all steps are pre-baked in AMI what left for server is to start the service manager and start serving requests. AMI help you reduce new server provisioning time from 20-30 minutes to mere couple of minutes.</p>
</li>
</ul>
</li>
<li>
<p>Be ready for traffic spikes in time</p>
<ul>
<li>With surge in traffic if your infrastructure didn’t scale in time, there is no point of putting auto-scaling policies. Your server should be fast enough to spin fast so that they can start receving requests fast. AMI help minimize this time and thus answer your growing traffic in time.</li>
</ul>
</li>
<li>
<p>Known state of server</p>
<ul>
<li>Since all servers are spinned from same AMI it’s guarranteed that all are running same packages at same version. Thereby, eliminating surprises. Nobody likes <a href="http://martinfowler.com/bliki/SnowflakeServer.html">snowflake servers</a> and we should always strive to avoid configuration drift. This is one step towards <a href="http://martinfowler.com/bliki/ImmutableServer.html">immuatable servers</a></li>
</ul>
</li>
</ul>
<p>Considering benefit of AMI, it’s essentials to create a good AMI. Here are some steps that you can consider when you create AMI next time.</p>
<h2 id="how-to-create-a-good-ami">How to create a good AMI?</h2>
<h2 id="check-list">Check List:</h2>
<ol>
<li>Let bootup complete proper. check <code class="language-plaintext highlighter-rouge">/var/log/boot.log</code>. Maybe even let run for 5-7 mins before proceeding.</li>
<li>Update all system packages and reboot. ensure all is good here.</li>
<li>Stop all running application services</li>
<li>Check the mail queue (mailq/sendmail)</li>
<li>If needed flush the queue</li>
<li>once the queue is empty, you’re ready to actually make the image</li>
<li>Delete Shell history</li>
<li>Clean authorized keys</li>
<li>double check the code is deploying from the right source, boot it up again just in case, double check its using right source etc (if chef/puppet in use)</li>
<li>Issue stop to this instance</li>
<li>Proceed with ami creation</li>
</ol>
<hr />
<h2 id="delete-shell-history">Delete Shell history</h2>
<p>Always delete the shell history before creating your AMI.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find /root/.*history /home/*/.*history -exec rm -f {} \;
</code></pre></div></div>
<h2 id="clean--authorized-keys">Clean authorized keys</h2>
<p>If you’re creating Public AMI you may want to perform following steps:</p>
<ul>
<li>
<p>Exclude SSH authorized keys before creating your AMI.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> find / -name "authorized_keys" –exec rm –f {} \;
</code></pre></div> </div>
</li>
<li>
<p>Ensure that your private credentials for third-party applications and remote services are deleted</p>
<p>locate “authorized_keys” files on disk, when run as root:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> find / -name "authorized_keys" -print -exec cat {} \;
</code></pre></div> </div>
</li>
</ul>
<p>WARNING: Please execute above commands only if you know what you’re doing only.</p>
<hr />
<p>Your check list may differ depending on your use case. However, with this article i want to share some best practices, i developed while working on AMI, across.</p>
<p>Thanks for dropping by ;)</p>
<h2 id="references">References:</h2>
<ul>
<li><a href="https://aws.amazon.com/articles/0155828273219400">How To Share and Use Public AMIs in A Secure Manner</a></li>
</ul>
<p><a href="http://sahilsk.github.io/articles/how-to-create-a-good-ami/">How to create a Good AMI?</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on July 21, 2015.</p>http://sahilsk.github.io/articles/so-youre-writing-api-client2015-06-08T19:25:29+00:002015-06-08T19:25:29+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<p>With the advent of internet of things, especially rise of mobile devices has made modern web application to be served as SaaS: Software as a servic or simple service.</p>
<p>Now browser only don’t account for traffic surge but mobile applications as well. Few companies takes this to a new level by providing their service as a platform for other developer to write their own application above it. Thereby, rise in traffic is inevitable.</p>
<p>With start of <code class="language-plaintext highlighter-rouge">internet of things</code> API layer has become norm. This post is about writing clients that will consume API ie. API Clients.</p>
<p>If you’re writing API client first thing you need to decide if you want to show http response code to users or not?
If not, then how will you intimate user about errors? use custom error code. This is also good.</p>
<p>However, there is a better way: best of both world: Put both of them. Put status to align your response code with <a href="http://en.wikipedia.org/wiki/Http_error_codes">http status codes</a></p>
<p>I personally feel attaching HTTP status code with every response is a nice way of enriching api-client response.</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="err">data:</span><span class="w"> </span><span class="s2">"(optional) My data goes here"</span><span class="p">,</span><span class="w">
</span><span class="nl">"error"</span><span class="p">:</span><span class="w"> </span><span class="s2">"(optional) My error,if any, goes here"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Looking at above response consumer will only learn partial truth. It doesn’t say anything about api server response. This response block might work well with small number of api endpoints where errors could be made familiar after a very short usage, but doesn’t scale well beyond it.</p>
<p>Let’s enrich our response block with little few more fields.</p>
<h3 id="starting-with-errors-first">Starting with errors first</h3>
<p>Let’s start with an example :</p>
<p><a href="https://dev.twitter.com/overview/api/response-codes">Twitter api error response</a> look like this:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"errors"</span><span class="p">:[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="s2">"Sorry, that page does not exist"</span><span class="p">,</span><span class="w">
</span><span class="nl">"code"</span><span class="p">:</span><span class="mi">34</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Excerpt from Twitter Api documentation:</p>
<blockquote>
<blockquote>
<p>If you see an error response which is not listed in the <a href="https://dev.twitter.com/overview/api/response-codes">twitter error code table</a>, then fall back to the HTTP status code in order to determine the best way to address the error.</p>
</blockquote>
</blockquote>
<p>This says we need http response code as well if error code is missing in api resopnse. So, in api client response there should be <strong>http status code</strong>.</p>
<p>A simple informative api client response could be :</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">401</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Authentication"</span><span class="p">,</span><span class="w">
</span><span class="nl">"code"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">2334</span><span class="p">,</span><span class="w">
</span><span class="nl">"more_info"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"http://myApp.com/docs/errors/2334"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>This response block shows where to go head next to get more information on error.</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">status</code>: is aligned with http status code.</li>
<li><code class="language-plaintext highlighter-rouge">Code</code>: is used to add more information to this specific error.</li>
<li><code class="language-plaintext highlighter-rouge">more_info</code>:
In API design we always strive to be <strong>verbose</strong>. There is no harm. You can also give link to more documentation by using <code class="language-plaintext highlighter-rouge">more_info</code> field in your response block.</li>
</ul>
<p>More on <code class="language-plaintext highlighter-rouge">status</code>:</p>
<ul>
<li>
<p>Don’t try to handle every http status codes.</p>
<p>You can start with 3 codes first: <strong>200</strong>(OK), <strong>404</strong>(Not Found) & <strong>500</strong>(Internal Server Error).
Later on you can add more like following, if need arises.</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">201</code> - Created</li>
<li><code class="language-plaintext highlighter-rouge">304</code> - Not Modified</li>
<li><code class="language-plaintext highlighter-rouge">400</code> - Bad Request</li>
<li><code class="language-plaintext highlighter-rouge">401</code> - Unauthorized</li>
<li><code class="language-plaintext highlighter-rouge">403</code> - Forbidden</li>
</ul>
</li>
</ul>
<h3 id="enriching-response">Enriching response</h3>
<p>Having dealt with errors we can now proceed further with returning good responses.</p>
<p>I personally like attaching following field to api response:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Status</code> - HTTP Status code</li>
<li><code class="language-plaintext highlighter-rouge">Data</code> (optional) - Any data returned</li>
<li><code class="language-plaintext highlighter-rouge">Error Code</code> (optional) - HTTP code associated with the error</li>
<li><code class="language-plaintext highlighter-rouge">Error Message</code> (optional) - Message associated with the error</li>
<li><code class="language-plaintext highlighter-rouge">Error Explanation</code>(optional) - Additional error info</li>
</ul>
<p>Verbose? but verbosity is good otherwise developer has no way of knowing what are they doing wrong?</p>
<p>You don’t want them go bald by leaving them pulling their hair with no information but error code in response. Right?</p>
<h3 id="final-response-block">Final response block</h3>
<p>Combining all good parts together final response should include following fields:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">status</code> : HTTP Status code</li>
<li><code class="language-plaintext highlighter-rouge">data</code>(optional) : Data retreived as a result of request. It could be an array or single object</li>
<li><code class="language-plaintext highlighter-rouge">errors</code>(optional): Array of errors with <code class="language-plaintext highlighter-rouge">message</code>, <code class="language-plaintext highlighter-rouge">code</code> and <code class="language-plaintext highlighter-rouge">more_info</code> fields</li>
</ul>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="err"><HTTP</span><span class="w"> </span><span class="err">Status</span><span class="w"> </span><span class="err">code</span><span class="w"> </span><span class="err">></span><span class="p">,</span><span class="w">
</span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="err"><</span><span class="w"> </span><span class="err">Any</span><span class="w"> </span><span class="err">data</span><span class="w"> </span><span class="err">returned></span><span class="p">,</span><span class="w">
</span><span class="nl">"errors"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="err"><short</span><span class="w"> </span><span class="err">error</span><span class="w"> </span><span class="err">description></span><span class="p">,</span><span class="w">
</span><span class="nl">"code"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="err"><error</span><span class="w"> </span><span class="err">code</span><span class="w"> </span><span class="err">></span><span class="p">,</span><span class="w">
</span><span class="nl">"more_info"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="err"><</span><span class="w"> </span><span class="err">url</span><span class="w"> </span><span class="err">to</span><span class="w"> </span><span class="err">more</span><span class="w"> </span><span class="err">info</span><span class="w"> </span><span class="err">page</span><span class="s2">"
}
...
]
}
</span></code></pre></div></div>
<p>Isn’t it <strong>cleaner</strong>, <strong>informative</strong> and that <strong>without loosing</strong> any peice of information.</p>
<h2 id="references">References</h2>
<ul>
<li>http://stackoverflow.com/questions/942951/rest-api-error-return-good-practices</li>
<li>https://blog.apigee.com/detail/restful_api_design_tips_for_handling_exceptional_behavior</li>
<li>https://blog.apigee.com/detail/restful_api_design_what_about_errors</li>
<li>https://dev.twitter.com/overview/api/response-codes</li>
</ul>
<p><a href="http://sahilsk.github.io/articles/so-youre-writing-api-client/">So You're Writing Api Client</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on June 08, 2015.</p>http://sahilsk.github.io/articles/hands-on-facebook-reactjs2015-04-01T02:53:21+00:002015-04-01T02:53:21+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr666@gmail.com<p>With the news of facebook launching <a href="https://code.facebook.com/videos/786462671439502/react-js-conf-2015-keynote-introducing-react-native-/">react-native</a>, i couldn’t stop myself from learning <a href="https://facebook.github.io/react/">ReactJS</a>.</p>
<p>Earlier than that, i often ask myself this question on a thought of learning new javascript frameworks : <strong>Why do i need to learn one more?</strong>.</p>
<p>Wel, News of <em>react-native</em> pique my interest and forced me to step out of my comfort zone. I fire up the browser with ignited spirit to devour ReactJS. (:</p>
<h2 id="first-impression">First Impression</h2>
<p>With a background of MVC taught by backbone and angularjs, reactJS was totally new.
ReactJS is <strong>V</strong> in <strong>MVC</strong> . I then thought how’s it different from angularJS Directive or ember components?</p>
<p>I also got confused by <strong>one-way reactive data flow</strong>. What does it mean? Data often moves from back & forth.
ReactJS uses virtual DOM. So, how is it useful?</p>
<p>Without mulling over it much, i decided to build an RealTime application using it and when it comes to realTime twitter live feed often comes into mind.</p>
<p>So, i made Realtime status tracking application using ReactJS: <a href="http://track-tweets.herokuapp.com/">http://track-tweets.herokuapp.com/</a>. It took me only two days ( need not to forget i go to office in day time) to built this application.</p>
<p><img src="http://sahilsk.github.io/images/realtimeApp.png" alt="RealtTime App" /></p>
<p>Feature list:</p>
<ul>
<li>Show tweets on page load (render at server side)</li>
<li>As user scroll down and reach near bottom, more tweets appends from mongoDB powered database (lazy loading)</li>
<li>As new tweets show up on twitter matching track string, user get realtime notification about it</li>
</ul>
<p>Please find source code on <a href="https://github.com/sahilsk/track-tweets">github: sahilsk/track-tweets</a></p>
<p><img src="http://sahilsk.github.io/images/realtimeApp_full.png" alt="RealtTime App" /></p>
<p>In this post, i want to share my views on facebook ReactJS.</p>
<blockquote>
<p>NOTE: Views are totally personal and has nothing to do with organization, people or girls i might be connected to..</p>
</blockquote>
<h2 id="small-learning-curve">Small learning Curve</h2>
<p>Well, having removed <strong>M</strong> and <strong>C</strong> from <strong>MVC</strong> you’re left with only <strong>V</strong> to learn and that is <strong>ReactJS</strong>. So, learning curve is drastically reduced. In couple of minutes you can get started and rest you can learn as you go.</p>
<p>There getting started guide incredibly simple. Why incredible? because i didn’t trust it and take google help to search more advance ReactJS tutorials. You can save time if you stick with it( though googling won’t harm either).</p>
<p>You don’t need to learn about providers, service , factory or any more jargons you may have seen in other frameworks.</p>
<h2 id="tidy-manageable-code">Tidy manageable code</h2>
<p>In writing realTime application code often go messy. In reactJS components help you organize your code by allowing you to divide big application into smaller component.</p>
<p>For my application here the application components when put together look like:</p>
<p><strong>/react/components/tweetApp.react.js</strong></p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">---</span>
<span class="nx">render</span><span class="p">:</span> <span class="kd">function</span><span class="p">(){</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">tweetApp_wrapper</span><span class="dl">"</span> <span class="o">></span>
<span class="o"><</span><span class="nx">Tracker</span> <span class="nx">track</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">track</span><span class="p">}</span> <span class="sr">/</span><span class="err">>
</span> <span class="o"><</span><span class="nx">Tweets</span> <span class="nx">tweets</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">tweets</span><span class="p">}</span> <span class="sr">/</span><span class="err">>
</span> <span class="o"><</span><span class="nx">Notification</span> <span class="nx">count</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">unreadTweets</span><span class="p">.</span><span class="nx">count</span><span class="p">}</span>
<span class="nx">showUnreadTweets</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">showUnreadTweets</span><span class="p">}</span>
<span class="sr">/</span><span class="err">>
</span> <span class="o"><</span><span class="nx">Loader</span> <span class="nx">loading</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">loading</span><span class="p">}</span> <span class="sr">/> </span><span class="err">
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span>
<span class="p">)</span>
<span class="p">}</span>
<span class="o">---</span>
</code></pre></div></div>
<h2 id="cool-stuff">Cool stuff</h2>
<p>ReactJS <strong>Virtual DoM</strong> render the whole DOM in memory first and then push only the diff into the browser one.
It not only make browser rendering fast, but also enable you to render the DOM at server side. Cool isn’t it?</p>
<p>In my application when page open up it’s ReactJS server side rendered components that you see.
As shown in the snippet below <code class="language-plaintext highlighter-rouge">renderToString</code> method render component as string which i’m passing to my <a href="expressjs.com">expressJS</a> <code class="language-plaintext highlighter-rouge">index</code> view template.</p>
<p><strong>/server/routes/index.js</strong></p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">---</span>
<span class="kd">var</span> <span class="nx">markup</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">renderToString</span><span class="p">(</span> <span class="nx">TweetApp</span><span class="p">(</span> <span class="p">{</span><span class="dl">"</span><span class="s2">tweets</span><span class="dl">"</span><span class="p">:</span> <span class="nx">tweets</span> <span class="p">}</span> <span class="p">)</span> <span class="p">);</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="dl">"</span><span class="s2">index</span><span class="dl">"</span><span class="p">,</span>
<span class="p">{</span> <span class="dl">"</span><span class="s2">layout</span><span class="dl">"</span><span class="p">:</span> <span class="dl">'</span><span class="s1">../../server/views/layouts/main</span><span class="dl">'</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">tweets</span><span class="dl">"</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">tweets</span><span class="p">),</span>
<span class="dl">"</span><span class="s2">markup</span><span class="dl">"</span><span class="p">:</span> <span class="nx">markup</span>
<span class="p">}</span> <span class="p">);</span>
<span class="o">---</span>
</code></pre></div></div>
<p>Why is it important? Well, i care for my website reachability. So, i care about it SEO.
Though google crawler <em><a href="http://stackoverflow.com/questions/2061844/do-googles-crawlers-interpret-javascript-what-if-i-load-a-page-through-ajax">interpret</a></em> javascript, you still have to rely on third party services like <a href="https://prerender.io/">prerender.io</a> or phantomJS to boost your SEO.</p>
<h2 id="what-next">What next?</h2>
<p><a href="http://facebook.github.io/react-native/">Facebok react-native</a>: React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React.</p>
<p>At the time of writing this article react-native supports only iOS.</p>
<p><a href="https://facebook.github.io/flux/docs/overview.html">Facebook Flux</a>: application architecture bolstering uni-directional flow in applications.</p>
<p><a href="https://github.com/facebook/flow">Facebook Flow</a> : Adds static typing to JavaScript to improve developer productivity and code quality.
http://flowtype.org/</p>
<p>…and hopefully more in future. Be hopeful please…</p>
<h2 id="conclusion">Conclusion</h2>
<p>ReactJS, Flux & Flow are more about philosophical expect of development rather than learning few more technical jargons terms. phew…</p>
<p>My new year resolution is to learn more on ReactJS, REACT-Native, flux & flow.</p>
<p>Source code: <a href="https://github.com/sahilsk/track-tweets">sahilsk/track-tweets</a></p>
<p><a href="http://sahilsk.github.io/articles/hands-on-facebook-reactjs/">Hands on Facebook #reactjs</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on April 01, 2015.</p>http://sahilsk.github.io/articles/mongodb-standalone-server-in-docker2015-02-18T14:13:10+00:002015-02-18T14:13:10+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr666@gmail.com<h2 id="mongodb-245-inside-docker">MongoDB 2.4.5 inside Docker</h2>
<h2 id="dockerfile">Dockerfile</h2>
<p><strong>Dockerfile</strong> is to Docker what <em>Makefile</em> is to make</p>
<p>file <em>Dockerfile</em></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#</span>
<span class="c"># MongoDB 2.4.5 Dockerfile</span>
<span class="c">#</span>
<span class="c">#</span>
FROM ubuntu:12.04
MAINTAINER stackexpress <span class="s2">"http://stackexpress.com"</span>
RUN apt-get update
RUN apt-get <span class="nb">install</span> <span class="nt">-y</span> make gcc wget
RUN wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.5.tgz <span class="nt">-O</span> /tmp/pkg.tar.gz
RUN <span class="nb">ln</span> <span class="nt">-s</span> /opt/mongodb/bin/mongo /usr/local/bin/mongo
RUN <span class="nb">ln</span> <span class="nt">-s</span> /opt/mongodb/bin/mongod /usr/local/bin/mongod
RUN <span class="o">(</span><span class="nb">cd</span> /tmp <span class="o">&&</span> <span class="nb">tar </span>zxf pkg.tar.gz <span class="o">&&</span> <span class="nb">mv </span>mongodb-<span class="k">*</span> /opt/mongodb<span class="o">)</span>
RUN <span class="nb">rm</span> <span class="nt">-rf</span> /tmp/<span class="k">*</span>
RUN <span class="nb">mkdir</span> <span class="nt">-p</span> /data/db
<span class="c"># Define mountable directories.</span>
VOLUME <span class="o">[</span><span class="s2">"/data/db"</span><span class="o">]</span>
<span class="c"># Define working directory.</span>
WORKDIR /data
EXPOSE 27017
EXPOSE 28017
CMD <span class="o">[</span><span class="s2">"/opt/mongodb/bin/mongod"</span>, <span class="s2">"--rest"</span><span class="o">]</span>
</code></pre></div></div>
<h2 id="build">Build</h2>
<p>Now we’ll build the above Dockerfile and tag it under <code class="language-plaintext highlighter-rouge">sahilsk/mongo_2.4.5</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">## CD to 'Dockerfile' directory</span>
<span class="nv">$ </span>docker build <span class="nt">-t</span> sahilsk/mongo_2.4.5 <span class="nb">.</span>
</code></pre></div></div>
<h2 id="run">RUN</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker run -d sahilsk/mongo_2.4.5
</code></pre></div></div>
<h2 id="lets-do-some-benchmarking">Lets do some benchmarking</h2>
<p>We’ll employ <a href="http://docs.mongodb.org/manual/reference/program/mongoperf/"><em>mongoperf</em></a> here.</p>
<blockquote>
<p>Mongoperf is a utility for checking disk i/o performance of a server independent of MongoDB. It performs simple timed random disk i/o’s.</p>
</blockquote>
<p>…to be continued</p>
<p><a href="http://sahilsk.github.io/articles/mongodb-standalone-server-in-docker/">MongoDB Standalone Server in Docker</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on February 18, 2015.</p>http://sahilsk.github.io/articles/database-in-docker2015-02-18T13:29:37+00:002015-02-18T13:29:37+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<p>Rarely you might have heard of people running database in container in production environment. If there are any, gutsy they must be.</p>
<p>Database is critical component of every three tier service. With advent of NoSQL especially Document type databases, like MongoDB, database selection also play a role in deciding your technology stack. Though with failure of any component in stack may take down your whole service along, however, with database down you also looses data.</p>
<blockquote>
<p>Critics may say, Hey, same is true for any stateful component. But how many stateful component you see beside database nowadays? Smart people don’t uses file for persisting any information. Almost, all application states including sessions are stored in persistent fast accessible layer which will be 99% a database.</p>
</blockquote>
<h2 id="so-should-i-dare-to-run-database-in-docker">So, Should i dare to run database in Docker?</h2>
<p>Very daunting question it might look but if we paraphrase it, it looks like this:</p>
<p>With database running,</p>
<ol>
<li>I should not lost my data.</li>
</ol>
<p>My data should persist on disk and should stay there even when service is stop.</p>
<ol>
<li>I should be able to collect database metrics</li>
</ol>
<p>Most of the metrics usually come from logs. Need not to mention logs also help us in debugging in case some anomally occur in operation.</p>
<ol>
<li>I should be able to shutdwon gracefully, if not in use</li>
</ol>
<p>Some database require cleaning operation on shutdown phase. It also remove lock and release resources in cleaning step. When database is forcefully killed some resources not get released. Usually database respond to SYSINT and SYSKILL command by capturing them and taking decision.</p>
<ol>
<li>I should be able to start it with last saved data.</li>
</ol>
<p>When database re-start, it should resume operation from last saved state. State is usually saved in files(disk). So, effective journaling should be there.</p>
<ol>
<li>I should have no latency i.e
<ul>
<li>no network latency</li>
</ul>
<p>In distributed environment network latency can become a overhead. When there are thousands of IOPS per seconds it can easily become bottleneck.</p>
</li>
</ol>
<ul>
<li>
<p>no disk i/o latency</p>
<p>Though memory and journaling help in minimizing disk i/o operations. But a faster disk access always lead to faster throughput. With hardwares getting cheaper, SSD has gained popularity. Being fast often means fast operation.</p>
</li>
</ul>
<ol>
<li>
<p>I should be able to scale it</p>
<p>Through master-master replica or master-slave replica</p>
</li>
</ol>
<p>Not that daunting now. Right?</p>
<p>Let me recap docker performance impact on application running inside it.
In performance, it’s tantamount to speed you get natively. Here’s a brief overview on it.</p>
<ul>
<li>
<p><strong>CPU</strong> : CPU performance is totally Native. Same as you get without running inside Docker.</p>
</li>
<li>
<p><strong>I/O</strong> : Docker support<a href="http://www.projectatomic.io/docs/filesystems/"> many storage backends</a>. Device Mapper is being used by default and can be switched as per need. However, being said this simply switching storage backend won’t get you faster <strong>iops</strong> that you get natively. However, if you use <a href="https://docs.docker.com/userguide/dockervolumes/https://docs.docker.com/userguide/dockervolumes/">docker volumes</a> you’ll get native speed. It also has few extra advantages which i’ll cover in some future post.</p>
</li>
<li>
<p><strong>Memory</strong> : Docker set aside a little memory for memory accounting. However, it can be native i.e No overhead, if you disable memory accounting (useful for hptc, probably not for everything else)</p>
</li>
<li>
<p><strong>Network</strong>: There is no overhead if you run with <code class="language-plaintext highlighter-rouge">-–net host</code>. It’s useful for > 1Gb/s workloads of if you have a high packet rate eg. VOIP, Gaming.</p>
</li>
</ul>
<p>I might be missing few other things connected especially to application like Database. Pardon my ignorance. Here, i’d appreciate few help from community to add their views in the comment.</p>
<p><a href="http://sahilsk.github.io/articles/database-in-docker/">Database in Docker</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on February 18, 2015.</p>http://sahilsk.github.io/articles/application-monitoring-dashboard-solution2014-12-19T23:53:42+00:002014-12-19T23:53:42+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<p>In this post i’d discuss some of the option available for application
monitoring. As your application grows, your technology stack also grows
and so the surprises that comes along. These often lead to out-of-service
statuses which I presume no organization,small or big, can bear.</p>
<p>So, let’s get started.</p>
<p><strong>Application Monitoring</strong> : It can include minimum monitoring of application
live status and can extend upto application performance monitoring.
When you have all these metrics before you, you’ll be able to gauge your
infrastructure efficiency and scalability in more predictive manner.</p>
<p>Imaging your application is getting popular and no. of users are increasing
day by day. With given metrics you’ll be able to see how many RAM, CPU or instances
are being used and how much is available. With current resource utilization and
growing user base stats in hand, you can take necessary measures to ensure smooth operation of your
service.</p>
<h2 id="what-are-these-metrics-that-we-should-be-wary-about">What are these metrics that we should be wary about?</h2>
<p>Let’s start from server itself.</p>
<p>Few Important Metrics are: <strong>RAM</strong> , <strong>CPU</strong>, <strong>Disk space</strong>, <strong>bandwidh</strong>, <strong>Disk I/O</strong>
, <strong>DB Read/Write</strong> etc.</p>
<ul>
<li>
<p><strong>Disk I/O</strong></p>
<p>Processor will wait till process finish reading file. So, having a fast Disk input/output operations on a physical disk will improve your application performance significantly.</p>
<p>That’s why SSD’s are nowadays popular. 30% faster file opening speed than traditional HDD. File Copy or Write Speed of SSD is typically about 200 MB/s -550 MB/s while of HDD it’s very low around 50-12MB/s.</p>
<p>You can easily find the difference in turnaround time of your Disk I/O heavy application by just changing a single hardware.
But do you really require HDD? See your application metrics and answer yourself ;)</p>
</li>
<li>
<p><strong>RAM</strong></p>
<p>More the ram, more process can run and stay in memory for long.
This mean less Disk I/O and page swapping.
With hardware getting cheap, having extra RAM won’t cost much.</p>
<p>However, knowing when to increase RAM is the purpose of this post. One option is just take note of RAM usage in last couple of days and decide your next step.</p>
</li>
<li>
<p><strong>CPU</strong></p>
<p>For computation heavy application just RAM is not enough. You need powerful mind to process them all. So, do watch your CPU performances as well. Generally, if metrics shows CPU usage greater than 80% for most of the time, it means you should upgrade to more powerful machines with more cores inside.</p>
</li>
<li>
<p><strong>Bandwidth</strong></p>
<p>Not only it’ll help track your monthly bandwidth bills but also help you trace anomaly. Many times watching bandwidth usage pattern give you clues on what’s happing wrong if anything is going wrong.</p>
</li>
</ul>
<h2 id="next-step-is-how-to-get-these-metrics">Next Step is, how to get these metrics?</h2>
<p>Start with Web server. If you uses nginx then gather its statistics.
Afterward, gather App Server statistics. If you have RoR then you might have used or tried unicorn. So, you might need to dig into its log file to gather metrics out of it.</p>
<ul>
<li>
<p><strong><a href="https://www.phusionpassenger.com/documentation_and_support">PHusion Passenger</a></strong></p>
<p><code class="language-plaintext highlighter-rouge">Phusion Passenger</code> make all this easy as it’s a web server and App Server, both.
It provide Administration tools that allow you to detect whether an application is stuck and non-responsive.</p>
<p>It let you Watch and monitor many application-level, process-level and system-level statistics from a central place.</p>
<ul>
<li>CPU, memory and swap usage, both system-wide and per-process.</li>
<li>Connections and requests.</li>
<li>Hypervisor VM interference rates.</li>
<li>Load averages, fork rates and swap rates.</li>
<li>Application-level backtraces.</li>
</ul>
<p>Best part is <em>Easy integration with external tools</em>.
These statistics are queryable over an HTTP JSON API, allowing you to easily integrate these statistics with external tools.</p>
<p>These stats can be pushed into a centralized storage (Mongodb or mysql).</p>
</li>
<li>
<p><strong><a href="https://collectd.org/">CollectD</a></strong></p>
<p>collectd is a daemon which collects system performance statistics periodically and provides mechanisms to store the values in a variety of ways, for example in RRD files.
Out of the box it provide multitude of <a href="https://collectd.org/wiki/index.php/Table_of_Plugins">plugins</a> ( cpu, memory, network, disk etc).
For bandwidth usage you can look at <a href="https://github.com/Cosmologist/collectd-network-bandwidth-usage">collectd-network-bandwidth-usage</a> plugin.</p>
<p>These stats can be collected in Mongodb through <a href="4"> Write MongoDB plugin</a> or can be pushed into Graphite db through <a href="https://github.com/indygreg/collectd-carbon">collectd-carbon</a> plugin.</p>
</li>
</ul>
<h2 id="how-to-create-a-monitoring-dashboard-">How to create a monitoring Dashboard ?</h2>
<p>Let me start with minimal monitoring to advance monitoring options that can be used to monitor your application and the servers it’s running on.</p>
<ul>
<li>
<p>Minimum Application Monitoring: (Monit)</p>
<p><a href="http://mmonit.com/monit/">monit</a> can be used to monitor your endpoints. It provide a nice and simple web interface to see live status.</p>
<blockquote>
<p>Monit is a small Open Source utility for managing and monitoring Unix systems. Monit conducts automatic maintenance and repair and can execute meaningful causal actions in error situations.</p>
</blockquote>
<p>It provide a nice Web GUI where you can see live status of application interfaces and services.</p>
<p>If any service goes down or resource utilization crosses threshold, it’ll take action specified by you. Action can be restarting the crashed service, shooting mail to system admin or execution of your provided script or command.</p>
<p>Monit can help you if you have small infrastrcture. But as the infrastructure grows, handling Dashboard for every server would be weary. So, to ease this you can use <a href="https://github.com/karmi/monittr">Monittr</a>.</p>
<blockquote>
<p>Monittr provides a Ruby interface for the Monit systems management system. Its main goal is to aggregate statistics from multiple Monit instances and display them in an attractive web interface.</p>
</blockquote>
<p>For live monitoring and getting on-time system update on service crash/down or excessive resource utilization, Monit can serve your purpose.</p>
<p>If you want to read resource utilization pattern, to gauge your infrastructure growth and scale infrastructure accordingly you need to store all these metrics somewhere in centralized storage or Database.
Next solution let you read past stored data as well.</p>
</li>
</ul>
<p>Recently I come across a application monitoring architecture being used in one of the pioneer bread & breakfast service provider.
This solution is taken out of them.</p>
<ul>
<li>Monitoring like a boss ( Design Yourself)</li>
</ul>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">Phusion Passenger CollectD+
+ +
| |
| |
v v
Mongodb Carbon<span class="o">(</span>Graphite<span class="o">)</span>
+-------++----------+
<span class="o">||</span>
<span class="o">||</span>
<span class="o">||</span>
+-----vv-----+
| |
| JSON API |
| |
| |
+-----+------+
|
v
+------------+
| Your cool |
| Dashboard |
| |
+------------+ </code></pre></figure>
<p>Send <em>Passenger</em> data into MongoDB. Send <em>CollectD</em> metrics into <em>Graphite</em> database(<em>whisper</em>). Graphite provide JSON API interface <a href="http://graphite.readthedocs.org/en/latest/render_api.html">render url api</a> which can provide data endpoint to real time metrics.</p>
<p>Now, with collected JSON data from MongoDB and Carbon, you can have a common central JSON API endpoint that can power your dashboard to visualize metrics.</p>
<h3 id="little-on-choosing-technology-for-building-dashboard">Little on choosing technology for building Dashboard</h3>
<p>The big problem broken down into small sub problems.</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">
Get Data -> Store data -> Provide JSON Interface -> Pull & Visualize Data</code></pre></figure>
<p>For building <em>realtime dashboard</em> you can use any javascript MVC framework. <strong>AngualarJS</strong> or <strong>emberJS</strong> .</p>
<p>For creating widgets ( gauge, pie chart, geomap etc) you can use <strong>AngularJS</strong> template <a href="https://docs.angularjs.org/guide/directive">directives</a> or <strong>emberjs</strong> <a href="http://emberjs.com/guides/components/">components</a>.</p>
<p>While these approaches are fine, but i would like to introduce <a href="http://webcomponents.org/">web components</a> here, specially <a href="https://www.polymer-project.org/">polymer</a>.</p>
<blockquote>
<p>Web Components usher in a new era of web development based on encapsulated and interoperable custom elements that extend HTML itself. Built atop these new standards, Polymer makes it easier and faster to create anything from a button to a complete application across desktop, mobile, and beyond.</p>
</blockquote>
<p>With polymer you can create custom widgets very cleanly. Best part is you can re-use them in your next cool projects.</p>
<p>So, plugging peices together through standard interface you can build a nice appliclation monitoring dashboard for your infrastructure.</p>
<p><a href="http://sahilsk.github.io/articles/application-monitoring-dashboard-solution/">Application Monitoring Dashboard Solution</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on December 19, 2014.</p>http://sahilsk.github.io/articles/do-we-need-a-application-configuration-manager2014-11-11T08:39:10+00:002014-11-11T08:39:10+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<h1 id="do-we-need-a-centralized-application-configuration-manager-">Do we need a centralized application configuration manager ?</h1>
<p>NOTE: Please don’t get confused with Configuration Management tools like Ansible or opscode-chef. Here, the point is after application deployment on server if any configuration change in run parameter is required, then how to avail those to your already running application?</p>
<p>Let’s start with deployment. For deployment any CM tool will do: Ansible,chef. I prefer Ansible as it leave almost zero footprint on deployed server.</p>
<p>For application configuration management, you’ve two ways:</p>
<ol>
<li>
<p>Run your cm script(ansbile,chef/puppet) again, OR</p>
</li>
<li>
<p>Make your application listen to configuration change event.</p>
<p>In case of any change, your application should pull changed configuration, update itself and restart (if required,in most cases it’ll be)</p>
</li>
</ol>
<h2 id="ill-chose-first-option-and-i-have-reasons-for-it">I’ll chose first option. And I have reasons for it.</h2>
<p>In production environment(especially, of payment sites) I cannot afford my servers to behave in unpredictable manner. Change in configuration should be tested first in staging, then should go through canary testing before replicating changes in all production instances.</p>
<p>If you are planning of creating application configuration manager, then be prepared to make your applications to handle cases that comes with this change. Few of those cases are included here:</p>
<ul>
<li>
<p>what if centralized configuration server is down?</p>
<p>Your centralized configuraiton server could easily become single point of failure and can become bottlneck. So, additional care need to put here of maintaining it. You need to find ways to make it more fault tolerant and highly available. After all you have given promise of 99.999% availability to your end customers.</p>
</li>
<li>
<p>what to do if configuration change event triggered?</p>
<p>This, however, is the toughest case to handle and the sole purpose of bringing centralize configuration manager in stack.
To propagate a change, first need to make sure that on first server changes reflected perfectly i.e <em>Canary Test Passed</em> and it’s running smoothly. Only then, change should be allowed to be reflected on rest of the instances. So, this incremental update you need to implement, handle & test.</p>
<p>Simplest implementation could be just a fast database(preferably in-memory db like redis) with fault-tolerance, & high availability. If you use Redis then you can also make use of its pub-sub feature.
If you need to reflect changes speedily, then distributed key-value db like zookeeper or etc can be used.</p>
<p>Basically you’ll end up writing one daemon that does and make decision likes rolling back on failure, notify your monitoring server about the propagated change and its effect: Was it successful ? Why it failed? blah blah?</p>
</li>
</ul>
<p>Oh, dear you just added one more component in your architecture. That mean maintenance, support, bug fixing, release and finally, more headache.</p>
<h2 id="i-would-prefer-first-option-as-it-makes-my-life-simple-here-is-how">I would prefer first option as it makes my life simple. Here is how?</h2>
<p>What makes an ideal production server?</p>
<ul>
<li>
<p><strong>Immutable server</strong>:</p>
<p>A server that once deployed, is never modified, merely replaced with a new updated instance. Even slightest change like configuration key change should not be allowed. This way we can keep our infrastructure in known-state all the time.</p>
</li>
<li>
<p><strong>phoenix server</strong>:</p>
<p>Servers should automatically re-syncs with a known baseline. Tools like Ansible, Puppet and Chef have facilities to do this. Due to many chaotic reasons if server reboots then you can simply make use of CM features like <code class="language-plaintext highlighter-rouge">chef-client</code> in case of opscode-chef and <code class="language-plaintext highlighter-rouge">ansible-pull</code> in case of Ansible, to bring server back to known-state.</p>
</li>
</ul>
<p>I use Ansible to create immutable server instances. If any change i need propagate i re-run my ansible script, update changes, test, and if passes, then run the script on all other servers.
For automatically re-syncs on restart/boot i run <code class="language-plaintext highlighter-rouge">ansible-pull</code> that pulls changes automatically.</p>
<p><a href="http://sahilsk.github.io/articles/do-we-need-a-application-configuration-manager/">Do We Need a Application Configuration Manager?</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on November 11, 2014.</p>http://sahilsk.github.io/articles/why-docker2014-11-09T14:45:14+00:002014-11-09T14:45:14+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<h1 id="because-we-all-love-docker-3-3-3">Because we all love Docker. <3 <3 <3</h1>
<blockquote>
<p>Build, Ship and Run Any App, Anywhere
- The Docker team</p>
</blockquote>
<p>Docker is all the rage. Let me start this post by putting some metrics here taken from docker official <a href="https://github.com/docker/docker">github repository</a> on 9th Nov’14 :</p>
<ul>
<li>
<p><strong>16438</strong> github stars</p>
<p>Stars are just another way of saying “I love <em>docker</em>”</p>
</li>
<li>
<p>Forked <strong>3225</strong> times</p>
<p>Just another way of saying “I care for docker”.</p>
</li>
<li>
<p><strong>666</strong> active contributors</p>
<p>open-source community is committed in improving docker more and more. Not only this, with recent collaboration with RedHat, Microsoft and few other cloud providers docker is getting more secure, more reliable and now on a path to become cross-platform soon. Yes, window users soon be able to get the taste of this open-source recipe</p>
</li>
<li>
<p><strong>77</strong> releases</p>
<p>With more releases coming <em>Docker</em> is getting <em>better and better</em> and this metric conveyed the same. With every new release comes good news for the community.</p>
<p>Limit of 127 aufs layer has been removed in earlier version. With 0.9, Docker dropped LXC as the default execution environment, 0.11, comes tightened <em>security</em> , API consistency and more stability, 0.12 with pause/unpause notable feature, 1.0.0 brought more stability and production support, and with 1.0.1 brought enhance security for lxc driver.</p>
<p>You can read more about changelog <a href="https://github.com/docker/docker/blob/release/CHANGELOG.md">here</a></p>
</li>
</ul>
<p><img src="/images/contributor_github.png" alt="Alt Contributors " /></p>
<p>Docker Project was released as open source in March 2013. Since then these numbers are increasing day by day.</p>
<p>Not only this, many startups have been built around docker. <em>Runnable.com</em>, <em>Stackdock</em>, <em>orchard</em>, <em>tutum</em>, <em>quay.io</em>, <em>deis.io</em>, etc to name a few.
There is one beautifully created mindmeister map on <a href="http://www.mindmeister.com/389671722/docker-ecosystem">docker ecosyster</a> created by Krishnan Subramanian. You will find more names in there.</p>
<p>With Heavily active community, more security enhancement and soon getting cross-platform : I think these stats are enough to build confidence in Docker And to bring it in production without cringing.
Let me hight few more points on Docker here in this post.</p>
<h2 id="same-performance-at-almost-zero-cost">Same performance at almost zero cost</h2>
<blockquote>
<p>With negligible resource use, you get the same performance as you get running without it.</p>
</blockquote>
<p>Well, firstly docker provide a <em>virtual environment</em> for your technology stack to run in, unlike others who merely provide you just another virtual machine where resources are tightly coupled and worst part is they are not shareable.
With <code class="language-plaintext highlighter-rouge">docker</code> you get almost zero performance downgrade.</p>
<p>In performance, it’s tantamount to speed you get natively. Here’s a brief overview on it.</p>
<ul>
<li><strong>CPU</strong> : Native</li>
<li><strong>I/O</strong> : Native on volumes
make sure that your data set etc. is on volumes)</li>
<li><strong>Memory</strong> : Docker set aside a little memory for memory accounting. However, it can be native. No overhead if you disable memory accounting (useful for hptc, probably not for everything else)</li>
<li><strong>Network</strong>: There is no overhead if you run with ``–net host` (useful for > 1Gb/s workloads) (or if you have a high packet rate eg. VOIP, Gaming.)</li>
</ul>
<blockquote>
<p>Productivity and efficiency are just nothing but synonyms of Docker.</p>
</blockquote>
<p>So, with docker you can get the same performance for your technology stack as you gets natively. Besides, you can share resources among many containers. Thereby, leveraging resources efficiently, and thus spinning up less number of servers.</p>
<blockquote>
<p>Where Security, Reliability, Community & production Support make Docker stand apart, performance and super awesome feature list makes it a must have component of every stack.</p>
</blockquote>
<h2 id="notable-docker-features">Notable docker features</h2>
<ul>
<li>
<p>Pause/Unpause container</p>
<p>While Stop and Start feature was already there in the Docker, but with recently released docker, you can now <code class="language-plaintext highlighter-rouge">pause</code> and <code class="language-plaintext highlighter-rouge">unpause</code> your container as well.</p>
<p><em>Why do you care?</em> You can always use SIGSTOP and SIGCONT on all the processes in the process tree for a container to implement it yourself but they are not always sufficient for stopping and resuming tasks in userspace.</p>
<p>That’s where <a href="https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt">cgroup freezer</a> comes into picture and same is now implemented in docker to avail pause/unpause functionality.<br />
Docker also exposes this functionality via its API.</p>
</li>
<li>
<p>Build Once, Run Anywhere</p>
<p><em>No more configuration drift, no more surprises</em> : This is what Docker guarantee. This is a huge win for DevOps community.</p>
<p>A experience sysAdmin know steps used to successful deployment of stack on one machine doesn’t necessarily bring the same result in other machine as well.
But with Docker now it’s possible to achieve <code class="language-plaintext highlighter-rouge">immutable servers</code> , thereby, keeping infrastructure clean from <em>snowflakes</em> ones. Yeepeee!!!</p>
</li>
<li>
<p>Zero Downtime Deployment</p>
<p>With the advancement in technology zero downtime deployment is possible. Now you no longer need to put “out of service for maintenance” sign board any longer on your product.</p>
<p>Docker just happen to be one such technology which allow you to achieve this at negligible cost. Without switching back/forth on environment servers, you can deploy your changes, do canary testing and see the features rolling in production right before your eyes without cringing.</p>
</li>
<li>
<p>Spinning up new instances is a breeze</p>
<p>Some scenerio demands spinning up more server in minimum time to accommodate sudden surge in traffic and when traffic goes down, these servers should perish. Whether you use <em>aws auto-scaling</em> or in-house automation tools, it surely takes minimum of 2 or 3 minutes(without counting server spin-up time) to launch a new application instances. For heavily traffic sites like e-commerce on events like big sale or new product launch sale , these 2-3 minutes is enough to wipe out the entire stock in a flash.
Recenlty, leading ecommerce giant of India: Flipkart witnessed public outrage when their infrastructure failed to scale up as per demand. Though they claim to have 5000 servers ready at per usal but even then they failed to keep the end customer happy. Outburst of customer on social platform like twitter and fb was clearly <a href="http://gadgets.ndtv.com/internet/news/flipkart-big-billion-day-sale-riddled-with-problems-602498">seen</a> .</p>
<p>As a DevOps, we used to provide on-demand instances using chef-server and aws auto-scaling prior to witnessing miracles of Docker. Whenever a new instance was needed auto-scaling spinned up a new server using pre-configured ami. When server boots up, upstart script run chef-client to pull latest files and configuration required to run the application. This all took 5 to 6 minutes typically.
With docker now it takes 1-2 minutes or less, which is a big win.</p>
</li>
<li>
<p>Maintainable Deployment Scripts</p>
<p>Docker provide Dockerfile for building image. These images when run are called <strong>“containers”</strong>. Whether you want to install nginx or a framework like <code class="language-plaintext highlighter-rouge">ror</code> , everything you can define in Dockerfile in simple to learn and understand dsl.</p>
<p>Best part is you can share your images with each other. If you want mysql image, you can simple pull <a href="https://registry.hub.docker.com/_/mysql/">mySQL image</a> from <a href="https://registry.hub.docker.com">docker hub</a>. Best part is, <em>write once, deployed many times</em>.</p>
</li>
<li>
<p>SysAdmin chores made easy and tidy</p>
<ul>
<li>Backups</li>
<li>Logging</li>
<li>Remote access</li>
<li>Moving containers around</li>
<li>etc etc</li>
</ul>
<p>With mountable volumes, such chores are made very easy. Just spin up your cleaning container using volumes from application containers and with separation-of-concerns you got a tidy way of cleaning and backups of your application.</p>
<blockquote>
<p>Docker comes as a boon to chaotic, cluttered life of sysAdmin by making everything easy to handle, maintain and share.</p>
</blockquote>
</li>
</ul>
<p>With the incorporation of one tool in the production not only entire vertical in the organisation get the benefits but also end customers</p>
<ul>
<li>Fast change roll out & deployment</li>
<li>Less number of server spins therefore, reduction in mothly</li>
<li>Easier to write and create Dockerfile leads to short learning curve for new member in the team</li>
<li>High availability of service keeps customer confident intact.</li>
</ul>
<p>With Docker there is a win-win for all stakeholders.</p>
<p><a href="http://sahilsk.github.io/articles/why-docker/">Why docker?</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on November 09, 2014.</p>http://sahilsk.github.io/articles/rubyonrails-app-on-docker-part-iii-answering-failures2014-10-07T02:42:48+00:002014-10-07T02:42:48+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<h1 id="rubyonrails-app-on-docker-part-iii-making-it-robust-final-conclusion">RubyOnRails App On Docker: Part-III Making it Robust, final conclusion</h1>
<p>At this point i assume you have containerized RoR app up and running. You can stop and start container at a breeze. Here, we’ll try to answer Scale and HA questions for each of our components one by one.</p>
<ul>
<li>
<p>Database</p>
<ul>
<li>
<p>SCALE & HIGH AVAILABILITY</p>
<p>You can configure mysql replicas. There are two configuration, of which one you can choose based on your need.</p>
<ol>
<li>
<p><a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-mysql-master-master-replication">Master-Master</a></p>
<p>Choose this if you have more writes(update, insert) than reads(select) operations.</p>
</li>
<li>
<p><a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-master-slave-replication-in-mysql">Master-Slave</a></p>
<p>This is useful if you have more read(select) operations</p>
</li>
</ol>
<p>(Setting up these configuration is out of scope of this article.)</p>
</li>
<li>
<p>Backup & Restore</p>
<p>You can use <a href="http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html"><code class="language-plaintext highlighter-rouge">mysql_dump</code> </a> Or <a href="http://dev.mysql.com/doc/refman/5.1/en/mysqlhotcopy.html"><code class="language-plaintext highlighter-rouge">mysqlhotcopy</code></a> , if tables are MyISAM.
There is one awesome article on backup & restore: <a href="https://www.digitalocean.com/community/tutorials/how-to-backup-mysql-databases-on-an-ubuntu-vps">How To Backup MySQL Databases on an Ubuntu VPS</a>. I urge you to read it.</p>
</li>
<li>
<p>Logs management</p>
<p>logs are created under <code class="language-plaintext highlighter-rouge">/var/log</code> directory. You can use syslog to ship them to a centralized location, or better if you have <code class="language-plaintext highlighter-rouge">ELK</code> stack setup that will ship logs to elasticsearch database then you can create a nice visualization for team to look at.</p>
</li>
</ul>
</li>
<li>
<p>Application</p>
<ul>
<li>
<p>SCALE</p>
<p>Now you can launch ror containers.Each container is running at different port eg. 49172, 49173 etc. If traffic increase, you want to scale your infrastructure by launching more similar instances. Here comes LoadBalancer into picture.</p>
<p>On launching new container, just make its entry in this loadbalancer configuration.
And when container goes down, take off the entry. There is a tool that can help you out with this chore: <a href="https://github.com/sahilsk/BackendsUpdater">BackendUpdater</a>. Basically, it listen to docker events and accordingly update your loadbalancer configuration file followed by configuration reload (<code class="language-plaintext highlighter-rouge">nginx reload</code>). More about it in next post.</p>
</li>
<li>
<p>High Availability</p>
<p>For maintenance or upgrade you can take out containers and do your upgrade. When done, bring them back. One by one you can do upgrade, thereby performing canary testing.</p>
<p>Also, this enable you zero downtime deployment of your upgrades.</p>
</li>
</ul>
</li>
</ul>
<h3 id="why-do-we-need-a-loadbalancer">Why do we need a loadbalancer?</h3>
<p><strong>Loadbalancer</strong> : Loadbalancers are one or more servers that forward the traffic to our backend application servers.<br />
Loadbalancer is required to distributed load among servers. Load distribution is required if there is huge traffic hitting your service and your single server is not able to withstand it.<br />
If you’re running some resource (cpu, ram etc) intensive jobs, like image processing or rendering then also you need a way to distribute load to other idle or lightly utilized servers.</p>
<p>Loadbalancer is not only used to distribute load only but also to ease deployment with minimal downtime. Just take one server out of pool of servers and do your maintenace or upgradation there. When you are done, put it back online. After your canary testing you can perform the same for other servers as well</p>
<p>So, here in RoR application we’re assuming our application to go incredibly famous.Thereby, bringing thousands hits per second. So, to accomodate these many request we’ll put loadbalancers.</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">... +-------+
| |
| L | +-+---------+---+
| O | | +---------+ |
T T T +------> | A | | | myApp|01| |
R R R | D | | +------+--+ |
A A A <<span class="nt">------</span>+ | B +--------> | +--------+
F F F | A | | +------+--+ | | |
F F F +------> | L <<span class="nt">--------</span>+ | myApp|02| | +---> |DATABASE|
I I I | A | | +------+--+ | <<span class="nt">---</span>+ | |
C C C <<span class="nt">-------</span> | N | | | +--------+
| C | | +------+--+ |
| E | | | myApp|N | |
| R | | +---------+ |
| | +-+---------+---+
+-------+ </code></pre></figure>
<p><strong>loadbalancer</strong></p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="err">#</span> <span class="nb">Set</span> <span class="nx">your</span> <span class="nx">server</span>
<span class="err">#</span> <span class="nx">server_name</span> <span class="nx">www</span><span class="p">.</span><span class="nx">example</span><span class="p">.</span><span class="nx">com</span><span class="p">;</span>
<span class="nx">upstream</span> <span class="nx">containers</span> <span class="p">{</span>
<span class="err">#</span> <span class="nx">Add</span> <span class="nx">a</span> <span class="nx">list</span> <span class="k">of</span> <span class="nx">your</span> <span class="nx">application</span> <span class="nx">servers</span>
<span class="err">#</span> <span class="nx">Each</span> <span class="nx">server</span> <span class="nx">defined</span> <span class="nx">on</span> <span class="nx">its</span> <span class="nx">own</span> <span class="nx">line</span>
<span class="err">#</span> <span class="nx">Example</span><span class="p">:</span>
<span class="err">#</span> <span class="nx">server</span> <span class="nx">IP</span><span class="p">.</span><span class="nx">ADDR</span><span class="p">:</span><span class="nx">PORT</span> <span class="nx">fail_timeout</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="nx">server</span> <span class="mf">127.0</span><span class="p">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">49172</span> <span class="nx">fail_timeout</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="nx">server</span> <span class="mf">127.0</span><span class="p">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">49173</span> <span class="nx">fail_timeout</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">server</span> <span class="p">{</span>
<span class="err">#</span> <span class="nx">Port</span> <span class="nx">to</span> <span class="nx">listen</span> <span class="nx">on</span>
<span class="nx">listen</span> <span class="mi">80</span><span class="p">;</span>
<span class="nx">location</span> <span class="o">/</span> <span class="p">{</span>
<span class="err">#</span> <span class="nb">Set</span> <span class="nx">proxy</span> <span class="nx">headers</span>
<span class="nx">proxy_set_header</span> <span class="nx">Host</span> <span class="nx">$host</span><span class="p">;</span>
<span class="nx">proxy_set_header</span> <span class="nx">X</span><span class="o">-</span><span class="nx">Real</span><span class="o">-</span><span class="nx">IP</span> <span class="nx">$remote_addr</span><span class="p">;</span>
<span class="nx">proxy_set_header</span> <span class="nx">X</span><span class="o">-</span><span class="nx">Forwarded</span><span class="o">-</span><span class="nx">For</span> <span class="nx">$proxy_add_x_forwarded_for</span><span class="p">;</span>
<span class="nx">proxy_pass</span> <span class="na">http</span><span class="p">:</span><span class="c1">//containers;</span>
<span class="err">#</span> <span class="nx">Turn</span> <span class="nx">on</span> <span class="nx">nginx</span> <span class="nx">stats</span>
<span class="nx">stub_status</span> <span class="nx">on</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<ul>
<li>
<p> </p>
<ul>
<li>
<p>Backup ( No restoring here) & Logs management</p>
<p>Since application is stateless, & all information is stored in Database. But still we sometime need to take backups for logs or other items. Here comes role of <code class="language-plaintext highlighter-rouge">volumes</code> into picture.</p>
<p>In dockerfile, we’d mentioned mountable directories.</p>
</li>
</ul>
</li>
</ul>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c"># Define mountable directories.</span>
VOLUME <span class="o">[</span><span class="s2">"/etc/dailyReport"</span>, <span class="s2">"/var/log/dailyReport"</span>, <span class="s2">"/etc/nginx/sites-enabled"</span>, <span class="s2">"/etc/nginx/certs"</span>, <span class="s2">"/etc/nginx/conf.d"</span>, <span class="s2">"/var/log/nginx"</span><span class="o">]</span> </code></pre></figure>
<p>Let’s make use of them.</p>
<h3 id="volumes">Volumes</h3>
<p><strong>volume</strong> help us create mountable directories inside containers. They are <a href="https://docs.docker.com/userguide/dockervolumes/">docker volumes</a>. These are helpful in number of cases, one of which is <strong>shipping logs</strong>.<br />
Lets have one container that does the job of shipping logs. Separtion of concerns, by having one container that does one job and does it perfectly.<br />
We’ll create new container called <code class="language-plaintext highlighter-rouge">data container</code> which will inherits volumes from our app container</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$sudo docker run -d --volumes-from app-001.example.com --name shiplogs.example.com myDockerfile/shiplogs
</code></pre></div></div>
<p>Inside this container <code class="language-plaintext highlighter-rouge">/var/log/dailyReport</code> is accessible where app container is squirting log. In our <code class="language-plaintext highlighter-rouge">shiplogs</code> container we can have a process that ships logs from there to centralized repository. (What that process could be, is left for future post. )</p>
<p>Similary you can access reverse proxy logs by reading <code class="language-plaintext highlighter-rouge">/var/log/nginx</code>. It’s Useful for debugging purpose for figuring out strange behavior of your application.</p>
<p>Another mount directory is <code class="language-plaintext highlighter-rouge">/etc/dailyReport</code> . This one is created to store all configuration files.
Why? If you want to edit run.sh, or unicorn.rb or reverse proxy configuration then you can do this without actually re-building image.</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"> <span class="nx">$docker</span> <span class="nx">run</span> <span class="o">-</span><span class="nx">it</span> <span class="o">--</span><span class="nx">rm</span> <span class="o">-</span><span class="nx">v</span> <span class="o">/</span><span class="kd">var</span><span class="sr">/log/</span><span class="nx">dailyReport</span><span class="p">:</span><span class="o">/</span><span class="kd">var</span><span class="sr">/log/</span><span class="nx">dailyReport</span> <span class="o">-</span><span class="nx">v</span> <span class="o">/</span><span class="nx">etc</span><span class="o">/</span><span class="nx">dailyReport</span><span class="p">:</span><span class="o">/</span><span class="nx">etc</span><span class="o">/</span><span class="nx">dailyReport</span> <span class="o">-</span><span class="nx">v</span> <span class="o">/</span><span class="kd">var</span><span class="sr">/run/my</span><span class="nx">sqld</span><span class="p">:</span><span class="o">/</span><span class="kd">var</span><span class="sr">/run/my</span><span class="nx">sqld</span><span class="p">:</span><span class="nx">ro</span> <span class="o">-</span><span class="nx">p</span> <span class="mi">49173</span><span class="p">:</span><span class="mi">80</span> <span class="o">--</span><span class="nx">restart</span><span class="o">=</span><span class="dl">"</span><span class="s2">always</span><span class="dl">"</span> <span class="o">-</span><span class="nx">e</span> <span class="dl">"</span><span class="s2">RAILS_ENV=production</span><span class="dl">"</span> <span class="o">--</span><span class="nx">name</span> <span class="nx">app</span><span class="o">-</span><span class="mi">001</span><span class="p">.</span><span class="nx">example</span><span class="p">.</span><span class="nx">com</span> <span class="nx">myDockerfiles</span><span class="o">/</span><span class="nx">dailyreport</span> <span class="o">/</span><span class="nx">bin</span><span class="o">/</span><span class="nx">bash</span></code></pre></figure>
<p>Here i’ve mounted <code class="language-plaintext highlighter-rouge">/var/log/dailyReport</code> and <code class="language-plaintext highlighter-rouge">/etc/dailyReport</code> directory of host onto container. This will make the container to use my configuration files stored at <code class="language-plaintext highlighter-rouge">/etc/dailyReport</code>. Also, i can see the logs created on host directory for debugging purpose.</p>
<h2 id="conclusion">Conclusion</h2>
<p>To recap everything, we’ve containerized RoR application and we’re running one or more instance of it behind loadbalancer. I’ve also tried my best to answer scale, availability and fault tolerance problem related to each component. So, with this i close my article.<br />
Comments are most welcome. If you’ve have any query or have better suggestion, you can write down in comments.</p>
<p>Later on, i’ll pen down centralized logging solution with ELK stack and my experience while working on it.
So, stay tuned. ;)</p>
<p><a href="http://sahilsk.github.io/articles/rubyonrails-app-on-docker-part-iii-answering-failures/">RubyOnRails App On Docker: Part-III Making it Robust, final conclusion</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on October 07, 2014.</p>http://sahilsk.github.io/articles/rubyonrails-app-on-docker-part-ii-containerize-app2014-10-01T09:42:48+00:002014-10-01T09:42:48+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<h1 id="rubyonrails-app-on-docker-part-ii-how-are-we-doing">RubyOnRails App On Docker: Part-II How are we doing?</h1>
<p>Assumption:</p>
<p>You’re free to name your application and docker namespace anything you want. However, to make this article more readable, i’m using undersigned names.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>application name: `dailyReport`
docker user namespace: `myDockerfiles`
</code></pre></div></div>
<p>Index</p>
<ul>
<li>Setup and Install database</li>
<li>Containerize RoR Apps</li>
<li>Setup Reverse Proxy using Nginx</li>
</ul>
<ol>
<li>
<h2 id="setup-and-install-database">Setup and Install database</h2>
</li>
</ol>
<p>For this application we’ll use MySQL. There are two ways to run MySQL</p>
<ul>
<li>Run without container</li>
<li>Run inside Docker</li>
</ul>
<h2 id="q-any-performance-impact-when-runng-inside-container">Q. Any performance impact when runng inside Container?</h2>
<p>In docker, cpu performance is native, disk latency is native, memory is not native but could be made. Same is true for network latency.</p>
<p>Nowadays hardware are cheap but software are costly. So, we don’t need to worry about little memory that Docker keep aside. If you really want to squash every single drop, then there are ways to do so. Network latency also can be made as fast as of native. This small minor reduction we can bear.</p>
<p>So, having compromised with Memory and Network latency, we’re proceeding to Dockerize MySQL instance.</p>
<p>Luckily, there is already mysql Dockerfile ready in the docker hub: <a href="https://github.com/dockerfile/mysql">MySQL Dockerfile</a></p>
<p><strong>dockerfile/mysql</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#</span>
<span class="c"># MySQL Dockerfile</span>
<span class="c">#</span>
<span class="c"># https://github.com/dockerfile/mysql</span>
<span class="c">#</span>
<span class="c"># Pull base image.</span>
FROM dockerfile/ubuntu
<span class="c"># Install MySQL.</span>
RUN <span class="se">\</span>
apt-get update <span class="o">&&</span> <span class="se">\</span>
<span class="nv">DEBIAN_FRONTEND</span><span class="o">=</span>noninteractive apt-get <span class="nb">install</span> <span class="nt">-y</span> mysql-server <span class="o">&&</span> <span class="se">\</span>
<span class="nb">rm</span> <span class="nt">-rf</span> /var/lib/apt/lists/<span class="k">*</span> <span class="o">&&</span> <span class="se">\</span>
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s1">'s/^\(bind-address\s.*\)/# \1/'</span> /etc/mysql/my.cnf <span class="o">&&</span> <span class="se">\</span>
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s1">'s/^\(log_error\s.*\)/# \1/'</span> /etc/mysql/my.cnf <span class="o">&&</span> <span class="se">\</span>
<span class="nb">echo</span> <span class="s2">"mysqld_safe &"</span> <span class="o">></span> /tmp/config <span class="o">&&</span> <span class="se">\</span>
<span class="nb">echo</span> <span class="s2">"mysqladmin --silent --wait=30 ping || exit 1"</span> <span class="o">>></span> /tmp/config <span class="o">&&</span> <span class="se">\</span>
<span class="nb">echo</span> <span class="s2">"mysql -e 'GRANT ALL PRIVILEGES ON *.* TO </span><span class="se">\"</span><span class="s2">root</span><span class="se">\"</span><span class="s2">@</span><span class="se">\"</span><span class="s2">%</span><span class="se">\"</span><span class="s2"> WITH GRANT OPTION;'"</span> <span class="o">>></span> /tmp/config <span class="o">&&</span> <span class="se">\</span>
bash /tmp/config <span class="o">&&</span> <span class="se">\</span>
<span class="nb">rm</span> <span class="nt">-f</span> /tmp/config
<span class="c"># Define mountable directories.</span>
VOLUME <span class="o">[</span><span class="s2">"/etc/mysql"</span>, <span class="s2">"/var/lib/mysql"</span><span class="o">]</span>
<span class="c"># Define working directory.</span>
WORKDIR /data
<span class="c"># Define default command.</span>
CMD <span class="o">[</span><span class="s2">"mysqld_safe"</span><span class="o">]</span>
<span class="c"># Expose ports.</span>
EXPOSE 3306
</code></pre></div></div>
<p>Dockerfile is quite simple. Isn’t it? In starting few lines, we’re installing mysql server and granting user root all privileges.</p>
<p>Line 24, however, need little elboration. Data directory will enable direct access to configuration and data files. This I’ll answer in my part-III. For now, lets put parts rolling.</p>
<p>Let’s setup and run mysql</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#Pull and Run mysql image</span>
<span class="nb">sudo </span>docker run <span class="nt">-d</span> <span class="nt">--name</span> mysql <span class="nt">-p</span> 3306:3306 dockerfile/mysql
</code></pre></div></div>
<p>This one line is suffice to run mysql server up and running.
To verify , we’ll start mysql client using the same image but different command.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>docker run <span class="nt">-it</span> <span class="nt">--rm</span> <span class="nt">--link</span> mysql:mysql dockerfile/mysql bash <span class="nt">-c</span> <span class="s1">'mysql -h $MYSQL_PORT_3306_TCP_ADDR'</span>
</code></pre></div></div>
<h3 id="how-to-connect-our-application-with-database">How to connect our application with database?</h3>
<p>There are actually two way to specify mysql connection to our app.</p>
<ul>
<li>
<p>mouting default mysql unix sock</p>
<p>This is useful if you don’t want to run mysql publicly. And for this tutorial, i’ve done the same.
I had database installed on my server. So, I’ll mount <code class="language-plaintext highlighter-rouge">/var/run/mysqld</code> on my container, thereby enabling rails to find default mysql endpoint to connect with.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker run -d -p 49172:80 -v /var/run/mysqld:/var/run/mysqld:ro --restart="always" -e "RAILS_ENV=production" myDockerfiles/dailyreport
</code></pre></div> </div>
</li>
<li>
<p>Specify connection string</p>
<p>If you want to use database running somewhere accessible through IP/Port, then you can specify these connection string in an environment variable <code class="language-plaintext highlighter-rouge">DATABASE_URL</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker run -d -p 49172:80 --restart="always" -e "RAILS_ENV=production" -e "DATABASE_URL='mysql2://username:password@IP/DB_NAME" myDockerfiles/dailyreport
</code></pre></div> </div>
</li>
</ul>
<ol>
<li>
<h2 id="containerize-ror-apps">Containerize RoR Apps</h2>
</li>
</ol>
<p>RoR framework already comes with sensible default best practices of Software Development.
However, there are few configuration that i’d like to stress on:</p>
<ul>
<li>
<p>Session Storage</p>
<p>Store session information in database. This will enable our app to behave more like stateless app. Also, this is essential if we want to scale our infrastructure further</p>
</li>
<li>
<p>Secrets</p>
<p>Database configuration, RoR Secret key (SECRET_KEY_BASE) , environment , smtp credentials, or other 3rd party addons secret that your app might be using, should not be hardcoded in configuration file. Instead, they should be picked from environment.</p>
</li>
</ul>
<p>Here’s one example showing database credentials being picked from environment.</p>
<p><strong>config/database.yml</strong></p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">production</span><span class="pi">:</span>
<span class="s"><<</span><span class="pi">:</span> <span class="nv">*default</span>
<span class="na">database</span><span class="pi">:</span> <span class="s"><%= ENV['DATABASE_PROD'] %></span>
<span class="na">username</span><span class="pi">:</span> <span class="s"><%= ENV['DATABASE_USERNAME'] %></span>
<span class="na">password</span><span class="pi">:</span> <span class="s"><%= ENV['DATABASE_PASSWORD'] %></span>
</code></pre></div></div>
<p>Similary, we’ll specify SMTP parameters. If you’re using any 3rd party service, like (mailgun, aws secrets etc), credentails should not be hardcoded, rather should be set in environment for the process to pick while running.</p>
<p>For setting up database credentials in environment, there’s a shorthand provided by RoR:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase"
</code></pre></div></div>
<p>NOTE: Setting <code class="language-plaintext highlighter-rouge">DATABASE_URL</code> environment variable will take precendence over config file params, & merge with config files to populate db connection setting.</p>
<h3 id="app-server-for-ror-unicorn">App Server for RoR: Unicorn</h3>
<p>We’ll choose widely adopted Unicorn as our web server.</p>
<p><strong>unicorn.rb</strong></p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Set the working application directory</span>
<span class="c1"># working_directory "/path/to/your/app"</span>
<span class="n">working_directory</span> <span class="s2">"/opt/dailyReport"</span>
<span class="c1"># Unicorn PID file location</span>
<span class="n">pid</span> <span class="s2">"/var/run/unicorn.pid"</span>
<span class="c1"># Path to logs</span>
<span class="n">stderr_path</span> <span class="s2">"/var/log/dailyReport/unicorn.err.log"</span>
<span class="n">stdout_path</span> <span class="s2">"/var/log/dailyReport/unicorn.log"</span>
<span class="c1"># Unicorn socket</span>
<span class="n">listen</span> <span class="s2">"/tmp/unicorn.dailyReport.sock"</span>
<span class="c1"># Number of processes</span>
<span class="c1">## Rule of thum: 2x per core</span>
<span class="n">worker_processes</span> <span class="mi">2</span>
<span class="c1"># Time-out</span>
<span class="n">timeout</span> <span class="mi">30</span>
</code></pre></div></div>
<h3 id="web-server-for-ror-nginx">Web Server for RoR: Nginx</h3>
<p>As the rail guides says, best practice to serve assets is through nginx. Here nginx will also serve as reverse proxy by masking unix socket and giving illusion of app running at http port.</p>
<p>To make assets serving faster, we’ll gzip our styelsheets and javascripts. How? This is not in the scope of this article, however in rails simple <code class="language-plaintext highlighter-rouge">rake assets:precompile</code> command does the trick.
Our web server will have assets block that will server these compressed files.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>upstream app <span class="o">{</span>
<span class="c"># Path to Unicorn SOCK file, as defined previously</span>
server unix:/tmp/unicorn.dailyReport.sock <span class="nv">fail_timeout</span><span class="o">=</span>0<span class="p">;</span>
<span class="o">}</span>
server <span class="o">{</span>
listen 80<span class="p">;</span>
server_name localhost<span class="p">;</span>
<span class="c"># Application root, as defined previously</span>
root /opt/dailyReport/public<span class="p">;</span>
try_files <span class="nv">$uri</span>/index.html <span class="nv">$uri</span> @app<span class="p">;</span>
location @app <span class="o">{</span>
proxy_set_header X-Forwarded-For <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
proxy_set_header Host <span class="nv">$http_host</span><span class="p">;</span>
proxy_redirect off<span class="p">;</span>
proxy_pass http://app<span class="p">;</span> <span class="c"># point to our upstream server list</span>
<span class="o">}</span>
<span class="c">#Server compressed assets</span>
location ~ ^/<span class="o">(</span>assets<span class="o">)</span>/ <span class="o">{</span>
gzip_static on<span class="p">;</span> <span class="c"># to serve pre-gzipped version</span>
expires max<span class="p">;</span>
add_header Cache-Control public<span class="p">;</span>
<span class="o">}</span>
error_page 500 502 503 504 /500.html<span class="p">;</span>
client_max_body_size 4G<span class="p">;</span>
keepalive_timeout 10<span class="p">;</span>
<span class="o">}</span>
</code></pre></div></div>
<h4 id="how-will-we-start-our-app">How will we start our app?</h4>
<p>Here comes run.sh into picture. We’ve written our startup script in this file.</p>
<p><strong>run.sh</strong></p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">RAILS_ENV</span><span class="o">=</span><span class="vg">$RAILS_ENV</span>
<span class="p">:</span> <span class="err">$</span><span class="p">{</span><span class="no">RAILS_ENV</span><span class="p">:</span><span class="o">=</span><span class="s2">"development"</span><span class="p">}</span>
<span class="n">export</span> <span class="no">RAILS_ENV</span>
<span class="no">SECRET_KEY_BASE</span><span class="o">=</span><span class="vg">$SECRET_KEY_BASE</span>
<span class="p">:</span> <span class="err">$</span><span class="p">{</span><span class="no">SECRET_KEY_BASE</span><span class="p">:</span><span class="o">=</span><span class="s2">"f38c575fcf0a2b0e7c7f002a873d54d78104581ebe069bf2b1afad04014d1e10245b259b872b0e12189ef2ce3fca4c73a9b5103aaf4aad1f4"</span><span class="p">}</span>
<span class="n">export</span> <span class="no">SECRET_KEY_BASE</span><span class="o">=</span><span class="vg">$SECRET_KEY_BASE</span>
<span class="c1">## Setting DB</span>
<span class="no">DB_NAME</span><span class="o">=</span><span class="s2">"dailyReport_${RAILS_ENV}"</span>
<span class="c1">#DATABASE_URL="mysql2://root:root@localhost/${DB_NAME}"</span>
<span class="c1"># Trap sigkill and sigterm: otherwise dockr stop/start will complain for stale unicorn pid</span>
<span class="nb">trap</span> <span class="s2">"pkill unicorn_rails ; exit "</span> <span class="no">SIGINT</span> <span class="no">SIGTERM</span> <span class="no">SIGKILL</span>
<span class="n">echo</span> <span class="s2">"Stopping unicorn_rails, if already running"</span>
<span class="n">pkill</span> <span class="n">unicorn_rails</span>
<span class="n">echo</span> <span class="s2">"cleaning tmp files"</span>
<span class="n">rm</span> <span class="o">-</span><span class="n">rf</span> <span class="n">tmp</span><span class="o">/*</span>
<span class="n">echo</span> <span class="s2">"Restart Reverse Proxy"</span>
<span class="n">service</span> <span class="n">nginx</span> <span class="n">restart</span>
<span class="n">echo</span> <span class="s2">"Running unicorn"</span>
<span class="n">bundle</span> <span class="nb">exec</span> <span class="n">unicorn_rails</span> <span class="o">-</span><span class="n">c</span> <span class="sr">/etc/</span><span class="n">dailyReport</span><span class="o">/</span><span class="n">unicorn</span><span class="p">.</span><span class="nf">rb</span> <span class="o">-</span><span class="no">E</span> <span class="vg">$RAILS_ENV</span> <span class="o">-</span><span class="n">d</span>
</code></pre></div></div>
<p>let’s wrap these lines inside <code class="language-plaintext highlighter-rouge">run.sh</code> file which will serve as our app startup script.</p>
<p>We wrote <code class="language-plaintext highlighter-rouge">run.sh</code>,and <code class="language-plaintext highlighter-rouge">unicorn.rb</code> file. We’ve also replaced hardcoded database, SMTP and 3rd party credentials with environment variables.
Now now need to wrap our app and unicorn in a container.</p>
<p>For this we’ll create two dockerfiles</p>
<ul>
<li>
<p>Base Dockerfile</p>
<p>It’ll contain latest version of ruby and rails installed.
Since ruby 1.9.x EOL is near. The newer 2.1.x version is comparatively fast, and bug free.
So, we’ll use ruby 2.1.2 and we’ll get it installed by rbenv. It’ll also help us to update ruby version without re-building docker image again. <strong>how?</strong></p>
</li>
</ul>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Note down its container id</span>
docker run <span class="nt">-it</span> baseDockerImage /bin/bash
<span class="nv">$ </span>rbenv <span class="nb">install </span>ruby 2.1.3
<span class="nv">$ </span><span class="nb">exit
</span>docker commit <span class="nt">-m</span> <span class="s2">"ruby2.1.3"</span> CONTAINER_ID
</code></pre></div></div>
<ul>
<li>
<p>Main Dockerfile</p>
<p>This will be our Dockerfile for our application. It’ll include ‘unicorn.rb’, ‘run.rb’ and ‘reverse proxy’ configuration. Basically, everything that’s required to run ror app natively.</p>
</li>
</ul>
<hr />
<p><strong>myDockerfiles/base_ruby</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#
# Ruby with rbenv Dockerfile
#
# Pull base image.
FROM dockerfile/ubuntu
# Install some dependencies
RUN apt-get update
RUN apt-get install -y git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties
# Install rbenv to install ruby
RUN git clone git://github.com/sstephenson/rbenv.git /usr/local/rbenv
RUN echo '# rbenv setup' > /etc/profile.d/rbenv.sh
RUN echo 'export RBENV_ROOT=/usr/local/rbenv' >> /etc/profile.d/rbenv.sh
RUN echo 'export PATH="$RBENV_ROOT/bin:$PATH"' >> /etc/profile.d/rbenv.sh
RUN echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh
RUN chmod +x /etc/profile.d/rbenv.sh
# Install rbenv plugin: ruby-build
RUN mkdir /usr/local/rbenv/plugins
RUN git clone https://github.com/sstephenson/ruby-build.git /usr/local/rbenv/plugins/ruby-build
# Let's not copy gem package documentation
RUN echo "gem: --no-ri --no-rdoc" > ~/.gemrc
ENV RBENV_ROOT /usr/local/rbenv
ENV PATH $RBENV_ROOT/bin:$RBENV_ROOT/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Install ruby
RUN rbenv install 2.1.2
RUN rbenv local 2.1.2
RUN rbenv global 2.1.2
## Install Rails
RUN apt-get install -y software-properties-common
RUN add-apt-repository ppa:chris-lea/node.js
RUN apt-get update
RUN apt-get install -y nodejs
## Finally, install Rails
RUN gem install rails
RUN rbenv rehash
CMD /bin/bash
</code></pre></div></div>
<p>Let’s build and tag it</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> <span class="s2">"myDockerfiles/base_ruby"</span> <span class="nb">.</span>
<span class="c"># Run and test</span>
docker run <span class="nt">-it</span> <span class="nt">--rm</span> myDockerfiles/baseRubyImg /bin/bash <span class="nt">-c</span> <span class="s1">'ruby -v'</span>
</code></pre></div></div>
<p>Here comes our main app Dockerfile that we will use</p>
<p><strong>myDockerfiles/main</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#</span>
<span class="c"># dailyReport in Container</span>
<span class="c">#</span>
<span class="c"># Pull base image.</span>
FROM myDockerfiles/base_ruby
<span class="c"># Fill dependencies for mysql2 gem</span>
RUN apt-get <span class="nb">install</span> <span class="nt">-y</span> libmysqlclient-dev libmysqlclient18 ruby-dev
<span class="c"># Install Nginx.</span>
RUN <span class="se">\</span>
add-apt-repository <span class="nt">-y</span> ppa:nginx/stable <span class="o">&&</span> <span class="se">\</span>
apt-get update <span class="o">&&</span> <span class="se">\</span>
apt-get <span class="nb">install</span> <span class="nt">-y</span> nginx <span class="o">&&</span> <span class="se">\</span>
<span class="nb">rm</span> <span class="nt">-rf</span> /var/lib/apt/lists/<span class="k">*</span> <span class="o">&&</span> <span class="se">\</span>
<span class="nb">chown</span> <span class="nt">-R</span> www-data:www-data /var/lib/nginx
<span class="c"># Pull repository from private github repos</span>
<span class="c">### Create .ssh dir in home directory</span>
RUN <span class="nb">mkdir</span> <span class="nt">-p</span> /root/.ssh
<span class="c"># Add your private key here. (Create a separate key, so that you can revoke it later)</span>
ADD ./id_rsa /root/.ssh/id_rsa
RUN <span class="nb">chmod </span>700 /root/.ssh/id_rsa
RUN <span class="nb">echo</span> <span class="s2">"Host github.com</span><span class="se">\n\t</span><span class="s2">StrictHostKeyChecking no</span><span class="se">\n</span><span class="s2">"</span> <span class="o">>></span> /root/.ssh/config
<span class="c"># Setup Reverse Proxy : Add reverse proxy config here</span>
ADD ./dailyReport_nginx.conf /etc/nginx/sites-enabled/default
RUN service nginx reload <span class="o">&&</span> service nginx restart
WORKDIR /opt/dailyReport
<span class="c"># Pull project : Replace with your github handle and repository</span>
RUN git clone git@github.com:sahilsk/dailyReport.git <span class="nb">.</span>
<span class="c"># Install gem</span>
RUN gem <span class="nb">install </span>bundler
RUN bundle <span class="nb">install
</span>RUN rbenv rehash
<span class="c"># Pre-compile app production assets</span>
RUN <span class="nv">RAILS_ENV</span><span class="o">=</span>production bundle <span class="nb">exec </span>rake assets:precompile
<span class="c"># Add unicorn config here </span>
ADD ./unicorn.rb /etc/dailyReport/unicorn.rb
<span class="c"># Run script</span>
ADD ./run.sh /etc/dailyReport/run.sh
<span class="c"># Define mountable directories.</span>
VOLUME <span class="o">[</span><span class="s2">"/etc/dailyReport"</span>, <span class="s2">"/var/log/dailyReport"</span>, <span class="s2">"/etc/nginx/sites-enabled"</span>, <span class="s2">"/etc/nginx/certs"</span>, <span class="s2">"/etc/nginx/conf.d"</span>, <span class="s2">"/var/log/nginx"</span><span class="o">]</span>
<span class="c"># Expost port 80</span>
EXPOSE 80
<span class="c"># Set environment variables</span>
ENV RAILS_ENV development
<span class="c">#</span>
CMD /bin/bash /etc/dailyReport/run.sh
</code></pre></div></div>
<p>Let’s build out main app now.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker build -t myDockerfiles/dailyreport .
</code></pre></div></div>
<p>It all goes well, you now have two images built succesfully.</p>
<p>Having build two images, you can see them using docker commands</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker images
</code></pre></div></div>
<p>Now lets run our app container</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$docker run -d -p 49172:80 -v /var/run/mysqld:/var/run/mysqld:ro --restart="always" -e "RAILS_ENV=production" myDockerfiles/dailyreport
</code></pre></div></div>
<p>You can visit <em>localhost:49172</em> and confirm if your app is launched</p>
<p>You can run more than one instance. Simple change the port and execute.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$docker run -d -p 49173:80 -v /var/run/mysqld:/var/run/mysqld:ro --restart="always" -e "RAILS_ENV=production" myDockerfiles/dailyreport
</code></pre></div></div>
<h1 id="references">References:</h1>
<ul>
<li>Dockerfile and scripts used here are on <a href="https://github.com/sahilsk/RoR-Dockerized">github</a></li>
</ul>
<p><a href="http://sahilsk.github.io/articles/rubyonrails-app-on-docker-part-ii-containerize-app/">RubyOnRails App on Docker: Part-II Containerizing App</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on October 01, 2014.</p>http://sahilsk.github.io/articles/rubyonrails-app-on-docker-part-i-understanding-specs2014-09-27T09:42:48+00:002014-09-27T09:42:48+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr.meena@gmail.com<h1 id="rubyonrails-app-on-docker-part-i-what-are-we-doing">RubyOnRails App On Docker: Part-I What are we doing?</h1>
<p>In this post, I’ll try to pen down steps to deploy RubyOnRails using Docker.
Before i begin, i assume readers to have basic understanding of Docker and Dockerfile. Albeit i’m trying to keep my post generic, independent of application layer technology, but having little RoR knowledge will help them get best out of this article.</p>
<p>Docker is all the rage nowadays. Though linux containers are there in linux for many years, but their real potential was sighted by Jérôme Petazzoni. Being a nescent technology doesn’t stop CTO from rolling it out on their Production.
<a href="http://runnable.com" title="runnable.com">Runnable</a>, <a href="newrelic.com" title="newrelic.com">NewRelic</a>, <a href="http://shippable.com" title="shippable.com">Shippable</a> etc, are all living on the edge and using Docker in their Day-to-day production as well as development work.</p>
<h3 id="what-influence-cto-decision">What influence CTO Decision?</h3>
<p>As a CTO, you need to think on wide perspective before adopting any new technology. Scalability, High Availability, Downtime, skills availability in team, time to learn etc etc. To put in simple terms, its not easy for new technology to come in limelight so easily. Technologies like HAProxy, Zookeeper are all battle tested and proven ones. But same is not true for Docker.</p>
<p>However, wide early adoption of Docker by many silicon valleys lean startups has debunked this fact. Their stories has inspired many others. You can read one from NewRelic <a href="http://blog.newrelic.com/2014/08/12/docker-centurion/">here</a></p>
<p>Recently, Amazon web service have started giving Docker container support.
Recent Docker <a href="https://blog.docker.com/2014/08/announcing-docker-1-2-0/">v1.2.0</a> release comes with enhanced security features that further support Docker acceptance in Production.
RedHat collaboration with Docker further emphasize that <strong>Docker is ready for production</strong>.</p>
<h3 id="coming-to-the-post-let-me-paraphrase-the-title-of-this-article">Coming to the post, let me paraphrase the title of this article:</h3>
<blockquote>
<p>Deploying RoR app using Docker</p>
</blockquote>
<p>Let me break down the word “Deployment” as per DevOps dictionary:</p>
<ul>
<li>Setup and configure Unicorn</li>
<li>Setup and configure Reverse Proxy: Nginx</li>
<li>Setup Database : MySQL</li>
<li>Pre-compile Assets and configure db settings</li>
</ul>
<p>Wait, there’s more. How will you <code class="language-plaintext highlighter-rouge">scale</code> your application? How will you ensure <code class="language-plaintext highlighter-rouge">High availability</code>(further onwards as HA) of your service and commit 99.999% uptime to your customers?</p>
<p>Lets give them a short visit here:</p>
<ul>
<li>
<p><code class="language-plaintext highlighter-rouge">SCALABILITY</code></p>
<p>If you application is based on <a href="http://12factor.net">12 factors</a> commandment , then your app is likely to be scalable. If you don’t know these 12 factors, i strongly suggest you to visit the <a href="http://12factor.net">site</a> and skim it in one go.</p>
<p>Expanding further, Apps can be of two type:</p>
<ul>
<li>
<p>Stateless</p>
<p>Stateless applications are easy to scale up and down. If it’s <a href="http://12factor.net">12factor</a> app then scalability is as easy as spinning up/down more instances. 12 factors commandment make scalability a breeze.</p>
</li>
<li>
<p>Stateful</p>
<p>Stateful application, like Databases, are comparatively difficult to scale. However, some database does provide clustering and sharding, out of the box. You’ll like to consider this criteria while making DBMS decision for your app.</p>
</li>
</ul>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">HIGH AVAILABILITY</code></p>
<p>With the advancement in technology, Zero Downtime deployment is no longer a dream. If your infrastructure does not yet support zero downtime deployment, then indeed you’re living in rock age. 12 factors app also enable you to avail zero downtime deployment.</p>
</li>
</ul>
<h4 id="finally-some-sys-admin-chores">Finally, some sys-admin chores:</h4>
<ol>
<li>
<p>Backup & Restore</p>
<p>Backup database data, or configuration files periodically and ship them to a safe place (Centralized server or S3 Buckets )</p>
</li>
<li>
<p>Logs Management</p>
<p>Logs are no longer neglected in today’s age of Big-Data. Management need information to aid their decisions. Logs help them provide those inputs. These inputs can be Geographical, or User browsing or buying trend, all gathered from logs.</p>
</li>
</ol>
<hr />
<p>Now, having knowns the full requirement, we’ll visit them one by one in this series of articles divided in three different parts.</p>
<ol>
<li>
<p>Part-I : What are we doing?</p>
<p>Understanding the full deployment requirement.</p>
</li>
<li>
<p>Part-II : How are we doing?</p>
<p>This part will include:</p>
<ul>
<li>Setup and Installation of Database</li>
<li>Containerize RoR App with webserver</li>
<li>Reverse Proxy : Why and How?</li>
</ul>
</li>
<li>
<p>Parth-III : Conclusion</p>
<p>In this last article I’ll revisit this post to answer our deployment requirements.</p>
</li>
</ol>
<p><a href="http://sahilsk.github.io/articles/rubyonrails-app-on-docker-part-i-understanding-specs/">RubyOnRails App on Docker: Part-I Understanding Specs</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on September 27, 2014.</p>http://sahilsk.github.io/articles/hello-world2014-09-03T03:00:00+00:002014-09-03T03:00:00+00:00Sonu K. Meenahttp://sahilsk.github.iosonukr666@gmail.com<p>You’ll find this post in your <code class="language-plaintext highlighter-rouge">_posts</code> directory - edit this post and re-build (or run with the <code class="language-plaintext highlighter-rouge">-w</code> switch) to see your changes!
To add new posts, simply add a file in the <code class="language-plaintext highlighter-rouge">_posts</code> directory that follows the convention: YYYY-MM-DD-name-of-post.ext.</p>
<h2 id="sample-heading">Sample Heading</h2>
<h3 id="sample-heading-2">Sample Heading 2</h3>
<p>Jekyll also offers powerful support for code snippets:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">print_hi</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"Hi, </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="n">print_hi</span><span class="p">(</span><span class="s1">'Tom'</span><span class="p">)</span>
<span class="c1">#=> prints 'Hi, Tom' to STDOUT.</span></code></pre></figure>
<p>Check out the <a href="http://jekyllrb.com">Jekyll docs</a> for more info on how to get the most out of Jekyll. File all bugs/feature requests at <a href="https://github.com/jekyll/jekyll">Jekyll’s GitHub repo</a>.</p>
<p><a href="http://sahilsk.github.io/articles/hello-world/">Hello World</a> was originally published by Sonu K. Meena at <a href="http://sahilsk.github.io">Full Stack Story</a> on September 03, 2014.</p>