Capistrano is a tool to perform tasks on multiple servers over SSH. We can use Capistrano to deploy code on multiple servers running under auto-scaling. Below is one of the use cases which I solved with the help of Capistrano and bash scripts. I’ve used Capistrano for code deployment and its management using bash shell script.
I have to deploy the code on multiple servers under AWS auto-scaling keeping in mind that no server comes up or goes down during deployment. The next task is to achieve the code integrity on all the servers at a time. All the servers must be running the same code from git repository.
Note: Before moving to the solution, please ensure that:
- You have already setup Capistrano on a server which can login into an application node via key-based authentication and is able to deploy the code on it.
- You’ve used the files “deploy.rb” (if single environment) or staging.rb and production.rb (If multiple environments) to insert the remote IP of the application nodes.
- The application node is able to SSH on the master Capistrano server to read some specific purpose text files (CURRENT_REVISION & PREVIOUS_REVISION) which I have used to make my solution more feasible (will be explained in the later part).
- All the application nodes and master Capistrano server should be authenticated to clone git repository.
I followed two approaches to solve the whole use case:
There is a master Capistrano server which will be treated as the main utility server which can invoke the Capistrano’s tasks on application nodes.
Problems solved by this approach:
- You can trigger the deployments on all the production/staging instances from this utility server at a particular time.
- You can quickly rollback the code on all the servers to the previous version, if new code fails to execute.
- You need to make sure that while deploying, no new server in auto-scaling comes up or any current server goes down. For the time being, you need to pause your auto-scaling process. For this I’ve used AWS CLI to make the desired number of servers same as minimum and maximum value in auto-scaling group. Now the auto-scaling has been paused for the time you are deploying on the servers using Capistrano. Once, you are finished with the deployments, you can again set the values of auto-scaling group parameters to the previous values to make auto-scaling process active again. I’ve written some custom bash scripts to automate all this procedure. You can clone my git repository to use those scripts.
- Also, I’ve used two text files which I’ve mentioned above. The files are CURRENT_REVISION and PREVIOUS_REVISION. The CURRENT_REVISION file will store the git commit ID of the code which is currently running on the production servers. The file PREVIOUS_REVISION stores the git commit ID of the code which was previously deployed on the server. The intent of using these files is to make the rollback flow easier. I am updating the file CURRENT_REVISION after every successful deployment on all the production instances. The old value of file CURRENT_REVISION gets moved to PREVIOUS_REVISION once deployment is successful. The file CURRENT_REVISION will only get updated when you have deployed a new commit ID. If you are deploying the current commit ID again and again, the content of the files will not change. In this way, you can ensure that you always have commit ID of previous code in the file PREVIOUS_REVISION which you can use at the time of rollback.
- For quick rollback to previous version, Capistrano reads the content of the file PREVIOUS_REVISION and deploy that commit ID on all the production instances.
- You can also deploy a specific commit ID on all the production instances. For this, you need to pass the parameter cap -s branch=<commit_id_to_be_deployed> deploy. This command will deploy the passed commit ID to all the remote servers mentioned inside ruby configuration file of Capistrano. I’ve also made a script for the same.
- You can also shoot custom mails regarding the status of the deployment to the concerned person. I’ve used the sendmail utility to send custom mails.
Once you have setup all this and your deployment process is working fine. As auto-scaling is active now, if any new server comes up then it will be having older code which you never want to happen. You have to maintain the code integrity on all the servers. The new server which is coming up must have the latest code which is running on all the production instances. To achieve this, I have installed Capistrano on each application node.
Let us suppose, a new server is coming up under auto-scaling, then I’ve written a custom bash script, which will perform the following tasks at the startup time of the server :-
- The new server will first SSH on the master Capistrano server to read the content of the file CURRENT_REVISION to get the commit ID of the code, which is already running on all the production instances.
- After getting the commit ID, the application node will deploy the code of that git commit ID on itself as each application node is also a Capistrano node in itself. To make Capistrano deploy on itself, you can mention “localhost” in the remote IP in configuration file of Capistrano.
In this way, the code integrity will be achieved. You can download all the scripts from my git repository and can use in them accordingly.
Git repository URL : https://github.com/tarunsaxena79/capistrano_scripts