Continuous deployment & AWS autoscaling using Ansible (+Docker ?) - amazon-ec2

My organization's website is a Django app running on front end webservers + a few background processing servers in AWS.
We're currently using Ansible for both :
system configuration (from a bare OS image)
frequent manually-triggered code deployments.
The same Ansible playbook is able to provision either a local Vagrant dev VM, or a production EC2 instance from scratch.
We now want to implement autoscaling in EC2, and that requires some changes towards a "treat servers as cattle, not pets" philosophy.
The first prerequisite was to move from a statically managed Ansible inventory to a dynamic, EC2 API-based one, done.
The next big question is how to deploy in this new world where throwaway instances come up & down in the middle of the night. The options I can think of are :
Bake a new fully-deployed AMI for each deploy, create a new AS Launch config and update the AS group with that. Sounds very, very cumbersome, but also very reliable because of the clean slate approach, and will ensure that any system changes the code requires will be here. Also, no additional steps needed on instance bootup, so up & running more quickly.
Use a base AMI that doesn't change very often, automatically get the latest app code from git upon bootup, start webserver. Once it's up just do manual deploys as needed, like before. But what if the new code depends on a change in the system config (new package, permissions, etc) ? Looks like you have to start taking care of dependencies between code versions and system/AMI versions, whereas the "just do a full ansible run" approach was more integrated and more reliable. Is it more than just a potential headache in practice ?
Use Docker ? I have a strong hunch it can be useful, but I'm not sure yet how it would fit our picture. We're a relatively self-contained Django front-end app with just RabbitMQ + memcache as services, which we're never going to run on the same host anyway. So what benefits are there in building a Docker image using Ansible that contains system packages + latest code, rather than having Ansible just do it directly on an EC2 instance ?
How do you do it ? Any insights / best practices ?
Thanks !

This question is very opinion based. But just to give you my take, I would just go with prebaking the AMIs with Ansible and then use CloudFormation to deploy your stacks with Autoscaling, Monitoring and your pre-baked AMIs. The advantage of this is that if you have most of the application stack pre-baked into the AMI autoscaling UP will happen faster.
Docker is another approach but in my opinion it adds an extra layer in your application that you may not need if you are already using EC2. Docker can be really useful if you say want to containerize in a single server. Maybe you have some extra capacity in a server and Docker will allow you to run that extra application on the same server without interfering with existing ones.
Having said that some people find Docker useful not in the sort of way to optimize the resources in a single server but rather in a sort of way that it allows you to pre-bake your applications in containers. So when you do deploy a new version or new code all you have to do is copy/replicate these docker containers across your servers, then stop the old container versions and start the new container versions.
My two cents.

A hybrid solution may give you the desired result. Store the head docker image in S3, prebake the AMI with a simple fetch and run script on start (or pass it into a stock AMI with user-data). Version control by moving the head image to your latest stable version, you could probably also implement test stacks of new versions by making the fetch script smart enough to identify which docker version to fetch based on instance tags which are configurable at instance launch.

You can also use AWS CodeDeploy with AutoScaling and your build server. We use CodeDeploy plugin for Jenkins.
This setup allows you to:
perform your build in Jenkins
upload to S3 bucket
deploy to all the EC2s one by one which are part of the assigned AWS Auto-Scaling group.
All that with a push of a button!
Here is the AWS tutorial: Deploy an Application to an Auto Scaling Group Using AWS CodeDeploy

Related

How do developers typically use Docker with a Java Maven project and AWS EC2?

I have a single Java application. We developed the application in Eclipse. It is a Maven project. We already have a system for launching our application to AWS EC2. It works but is rudimentary and we would like to learn about the more common and modern approaches other teams use to launch their Java Maven apps to EC2. We have heard of Docker and I researched the tool yesterday. I understand the basics of building an image, tagging it and pushing to either Docker Hub or Amazon's ECS service. I have also read through a few tutorials describing how to pull a Docker image into an EC2 instance. However, I don't know if this is what we are trying to do, given that I am a bit confused about the role Docker can play in our situation to help make our dev ops more robust and efficient.
Currently, we are building our Maven app in Eclipse. When the build completes, we run a second Java file that uses the AWS JDK for Java to
launch an EC2 instance
copy the.jar artifact from the build into this instance
add the instance to a load balancer and
test the app
My understanding of how we can use Docker is as follows. We would Dockerize our application and push it to an online repository according to the steps in this video.
Then we would create an EC2 instance and pull the Docker image into this new instance according to the steps in this tutorial.
If this is the typical flow, then what is the purpose of using Docker here? What is the added benefit, when we are currently ...
creating the instance,
deploying the app directly to the instance and also
testing the running app
all using a simple single Java file and functions from the AWS SDK for Java?
#GNG what are your objectives for containerization?
Amazon ECS is the best method if you want to operate in only AWS environment.
Docker is effective in hybrid environments i.e., on physical servers and VMs.
the Docker image is portable and complete executable of your application: it delivers your jar, but it can also include property files, static resources, etc... You package everything you need and deploy to AWS, but you could decide also to deploy the same image on other platforms (or locally).
Another benefit is the image contains the whole runtime (OS, jdk) so you dont rely on what AWS provides ensuring also isolation from the underlying infrastructure.

How to run Ansible play-book command from remote server

I need to install and configure all new system start with auto-scaling in aws as per the requirements , like if it is a app server install nodejs with respective git code for deployment using with Ansible.
How Ansible identify a new system came up and need to do this all configuration.
Here is a guide from ansible docs how to handle autoscaling with Ansible: https://docs.ansible.com/ansible/latest/scenario_guides/guide_aws.html#autoscaling-with-ansible-pull
The problem on this approch is, that you need the whole provisining prozess on startup. This takes much time and is error prone.
A common solution is to build a custom AMI with all infrastructure needed for your service and only deploy your current code to this maschine.
A good tool to build custom AMIs is Packer. A Guide for AWS is available here. https://www.packer.io/docs/builders/amazon.html

Deploy Java executable in EC2

I have written a little java tool to benchmark NoSQL databases. Because I dont have enough computers I want to run the benchmark tool and some database nodes in the Amazon EC2.
Is that possible?
-> Can I deploy a java app in the EC2 without any further config.?
Thank you
Can I deploy a java app in the EC2 without any further config
Yes. If you were running a typical web app, you might investigate Elastic BeanStalk. But that wouldn't work for benchmarking.
EC2 computers are just computers, except instead of installing the OS manually, you get to select a pre-installed OS to boot from, called an AMI. You could look around for an image with Java pre-installed, but it's fairly easy to boot your favorite Ubuntu/Fedora/Centos/AmazonLinux and do "apt-get install java" or "yum install java".
At first, you'll upload your program to the box and SSH in to test it. But when you get a workflow going, it's better to upload your program to S3, then have the box download it at boot. (S3 is usually faster than your upload speed, and more reliable.)
If you have just a "tiny" bit of config to do at boot, you can use cloud-init. This will run a pre-defined script at boot. (Just put the commands in the EC2 user-data config at boot.) It could be as simple as 3 commands: install java, download my app, run my app.
For more sophisticated operations, you'll want to use Chef, Puppet, or Ansible to orchestrate multiple servers.
But for something simple like your benchmarking idea, you can easily "roll your own" using the AWS API. Use a library (Boto for Python, Fog for ruby. I'm sure there are several for Java) to write a program that does the following:
1) launch an instance with a cloud-init script that installs a NoSQL DB
2) wait for it to get an IP.
3) launch another instance with a cloud-init script that configures your java test program, and passes in the IP from step 2.
4) waits for it all to run, then collects the run info (or maybe the info is stored in S3 so you can collect it later)
5) cleans up by terminating the instances (It helps to tag them so you can clean up easier)
You could do all this manually, but when you find a bug, you'll want to re-run everything, and automation will make that a breeze. Plus, you'll want to repeat your findings on various instance sizes.
Once you get things working, you can switch to spot instances when running your actual benchmarks: They take longer to launch, but can save a ton of money. So spot instances are annoying for development, but perfect for running bulk tests where you don't care about the launch time.
You can think of EC2 as just a set of computers that you can rent time on. You have total control over the EC2 VMs, and can install and run almost any software you want on them, including database servers and your java app.
You'll probably find the practical limitation is the amount of time you want to spend setting them up. You'll need to sign up for an Amazon account, set up your instances, install an OS, install DB servers, install your java app, etc...
See http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html to get going.

Is it possible to get TeamCity to stop & restart Amazon EC2 instances for build agents?

I have TeamCity (7.0.2) successfully spinning up an EC2 VM from a custom AMI, running our build, and sending back the build artifacts.
However, even when I used to do this with older TeamCity versions, I was always unhappy with the notion that it simply terminates the instances after they are done, and then creates new instances using the configured AMI next time a build agent is needed.
Can I get TeamCity to issue "stop" commands instead, followed by "start" commands? This has a tonne of advantages - quicker spin-up time, allowing for named instances in the agent stats, and saving the Mercurial clone to EBS for the next build are just three.
p.s. I guess I could use chained builds to call the EC2 API directly rather than use the in-built cloud support, but that sounds like a lot of work and feels flaky
We plan to provide support of EBS instances start stop in TeamCity 7.1
Please vote for TW-16419
TeamCity 7.0 may leak EBS volumes TW-12517

How to sync my EC2 instance when autoscaling

When autoscaling my EC2 instances for application, what is the best way to keep every instances in sync?
For example, there are custom settings and application files like below...
Apache httpd.conf
php.ini
PHP source for my application
To get my autoscaling working, all of these must be configured same in each EC2 instances, and I want to know the best practice to sync these elements.
You could use a private AMI which contains scripts that install software or checkout the code from SVN, etc.. The second possibility to use a deployment framework like chef or puppet.
The way this works with Amazon EC2 is that you can pass user-data to each instance -- generally a script of some sort to run commands, e.g. for bootstrapping. As far as I can see CreateLaunchConfiguration allows you to define that as well.
If running this yourself is too much of an obstacle, I'd recommend a service like:
scalarium
rightscale
scalr (also opensource)
They all offer some form of scaling.
HTH

Resources