Automation frenzy deployment using OpsWorks, Jenkins and AWS CLI
GNU/Linux DevOps Engineer - 09 September 2018 -
GNU/Linux DevOps Engineer - 09 September 2018 -
What is deployment: Deployment is what developers want the DevOps team to carry out.
They (Developers) code out some nice stuff which the above-mentioned people (DevOps) are responsible to handle the code with care and pass it to the production servers so the code is hosted in some way. Trust me it just sounds easy.
It’s an era of cloud so let’s take examples of cloud services especially taking AWS into account (we love AWS here in Talentica). So consider that your Infrastructure or servers shall be on AWS.
Now when setting up your infra (the platform to host your code) you shall chalk out a plan, a process to construct an architecture over it but what if you don’t know stuff about how infra works!
Well, there is this service AWS OPSWORKS which is quite simple to understand.
So OPSWORKS is based on another tool “chef-server”. You don’t need to know much about chef for using AWS OPSWORK though, still, Chef is a configuration management tool which follows idempotency and it is mostly scripted in Ruby language.
So, whatever you want the chef tool to run can be called as a “recipe”.
The recipe shall contain definitions (block of code) for what do you want your server to work upon.
Here is an example of a recipe to make the talking make some sense:
user "Add a user" do home "/home/joe" shell "/bin/bash" username "joe" end
Ruby code generally looks like “do … end”
Here the OpsWorks will fetch this block of code from wherever you want to say from local machine or by pulling it from GitHub/bitbucket directly on the server etc and then it will read the ruby code and it will create a user with username as “joe”.
Let us complicate things a bit-
Consider your infra /platform which hosts your website or whatever block of code on the INTERNET looks something like this:
Here on the bottom, there is database server (we use AWS RDS). The second bottommost level is a herd of servers. Well technically we call it as a cluster but that’s okay. But the catch is all the servers are duplicated, they all do the same thing. Why? Because we are” load balancing” between the servers that’s why.
NOW as I said let’s complicate things. Imagine you want the same architecture just for testing, you want to test your code first in one environment (consider the whole image above as one environment) So now we have two images same as above but in QA there are no users and it is not available directly on the internet (don’t ask why ! ) .
One fine day we need to add other environments for some other purpose call it as loadtest to check how much load our architecture can withstand. And we also want another environment for the demo env which shall be always available as we need to show a demo website which is not like QA also not like production.
This will create a problem statement “How am I supposed to handle this alone! ”
This is the part of the blog where we will have to dive deep into what’s OpsWorks.
STACKS: So, stack in the Infra sense is what all components are used in your environment. Talking about multiple environments as in our pictorial example we shall have 4 stacks named as prod-stack, QA-stack, demo-stack and loadtest-stack.
How to create them??? It’s easy to go to AWS CONSOLE -> SEARCH FOR OPSWORKS -> get started -> create stacks. I don’t want this blog to be that full of images. If you face any problem to do so maybe you can mail me.
LAYERS: wondering when will Jenkins come up in this blog? Wait!
So, talking about layers, I need to give a good example here.
Layers are the actual components within the stacks, they can also be categorized as applications.
Let’s go back to our stack scenario diagram where we will have a slight difference this time.
Picking up the “QA” environment. Here we have two applications hosted under the QA environment where QA is the “stack“, qa.abc.test.com and qa.test.com are the “layers”.
So here qa.abc.test.com is a branch of QA environment which hosts somewhat different code as compared to the main domain (qa.test.com)
Hence for different code, there shall be different hosting space, different deployment space, perhaps different servers.
Here is what AWS document says about what is OpsWork layers:
Every stack contains one or more layers, each of which represents a stack component, such as a load balancer or a set of application servers.
So, when we desire to make such kind of architecture OpsWork helps us a lot. It is very easy to simply add up layers.
Here is an example of how easily we can add layers just a click here a dropdown menu select there and you are done. You can integrate many other AWS services such as ECS with Opsworks. We can add a DB (RDS panel) as a layer too.
Opsworks nicely segregates the layers but also keeps them together in a single stack.
Deploying on the layers
1. BOOT-TIME Deployment
Boot time deployment is basically what stuff do you want to get installed when a new server (instance) is booted up. The stuff you specify will be installed on the new server at every boot up. You don’t need to install it again and again after launching new instances.
The installations are nothing but recipes running on the servers.
You wish to install apache server on all the servers in a particular layer or in the whole stack then write a ruby recipe (like we did for adding user) for installing apache server and boot up an instance to check if the apache is installed already.
There can be many such important recipes you will need to run on a newly launched instance.
JENKINS: Here is its entry.
Jenkins is a Continuous Integration Continuous Delivery tool.
It carries out amazing deployments smoothly. Here we are using Jenkins and Opsworks in a manner that Jenkins shall know these many points
1. How many stacks are present
2. How many layers are present in a stack
3. How much instances(servers) are present in the layers.
4. Which layer to deploy
5. Which layer not to deploy
6 PublicIP address of the instances on which we need to run the code-deploy
To know all these points, we have/ (require if you don’t have) AWS CLI (command line interface). Whereby using particular aws query command we get JSON outputs.
Jenkins can run these aws command and can get json outputs. Let’s take an example.
“AWS OpsWorks describe-stacks” This command will give a json output with the names of our stacks such as QA stack etc. Suppose you want to deploy on qa stack then from that json output we will simply have to fetch the “QA-stack “. We can use “jq” to parse the json outputs, here is an example:
OPS_STACK_ID=$(aws opsworks describe-stacks | jq '.Stacks  | select(.Name=="'"$ENV-stack"'")'| jq '.StackId' | cut -d '"' -f2)
(covers up point number 1)
here we will get the stack-id of our $env-stack where $env is a variable which is set as “QA” (parameterized in Jenkins). SO basically, Jenkins has got the QA-stack’s ID.
Jenkins will further describe this QA-stack ahead to get the json output for how many layers are present in this stack.
OPS_LAYER_ID=$(aws opsworks --region us-east-1 describe-layers --stack-id $OPS_STACK_ID |jq '.Layers | select (.Name=="'"qa.abc.test-layer"'")'| jq '.LayerId')
(covers up point number 2, 4, 5)
Using jq we can fetch/parse the layer id we desire by just passing the name to find it using the above command
after getting the layer id we can describe this layer to find out how many servers are we running under that layer. According to our QA infra diagram with two layers. The layer named as “qa.abc.test.com” has one instance which is hosting the domain.
aws opsworks –region us-east-1 describe-instances –layer-id $OPS_LAYER_ID | jq ‘.Instances.PublicIp’| wc -l
(covers number 3)
This command over here will simply return us the number of public IP of servers inside the layer.
aws opsworks –region us-east-1 describe-instances –layer-id $OPS_LAYER_ID | jq ‘.Instances.PublicIp’
(covers number 6)
This is the same command but will simply send out the values of the public IPs
we can ssh/ login into that server’s public IP and then we can run the deploy.sh shell script which will contain all the steps which are required to code deploy (like git pull or git clone etc .)
Here is what the Jenkins job code would look like:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ #!/bin/bash -x echo $BRANCH_NAME ################################################### ENV=qa keyfile=/var/lib/jenkins/.ssh/jenkins.pem user=jenkins subject=" anything you want" mail -s $subejct “email ids ” ###################################################
if [ -z "$BRANCH_NAME" ]; then echo "Exiting..Git branch name not set..!!" exit 1 fi echo "ENV=$ENV" > sshenv.txt echo "BRANCH_NAME=$BRANCH_NAME" >> sshenv.txt #this following command is imp anyways as we will need the stack id, so this command shall remain universal for any deployment OPS_STACK_ID=$(aws opsworks describe-stacks | jq '.Stacks | select(.Name=="'"$ENV-stack"'")'| jq '.StackId' | cut -d '"' -f2) OPS_LAYER_ID=$(aws opsworks --region us-east-1 describe-layers --stack-id $OPS_STACK_ID |jq '.Layers | select (.Name=="'"qa.abc.test-layer"'")'| jq '.LayerId' | cut -d '"' -f2) #now! that we have got the id we shall take a count of instances and its pub dns entries (instances on which we are going to deploy.) OPS_INSTANCE_COUNT=$(aws opsworks --region us-east-1 describe-instances --layer-id $OPS_LAYER_ID | jq '.Instances.PublicIp' | cut -d '"' -f2| wc -l) if [ "$OPS_INSTANCE_COUNT" -eq "0" ];then echo "Exiting as no servers present for deployment" exit 1 fi ### Run deploy via ssh in each server for i in $(aws opsworks --region us-east-1 describe-instances --layer-id $OPS_LAYER_ID | jq '.Instances.PublicIp' | cut -d '"' -f2); do echo $i; ##TESTING sudo scp -i $keyfile -o StrictHostKeyChecking=no sshenv.txt $user@$i:/tmp/envfile sudo ssh -i $keyfile -o StrictHostKeyChecking=no $user@$i 'bash -x /var/scripts/deploy.sh' done
Here I conclude that with OpsWorks, Jenkins and AWS CLI we have thus created a High availability architecture with one click/ AUTO deployment configured.