Deploy automation

At some point, your application will be deployed to production. If your application is small and you only use a few containers/servers, everything will be fine, you can easily manage all your resources (containers, VMs, servers, and so on) by hand in each deployment. However, what happens if you have hundreds of resources you need to update on each deployment? In this case, you need some kind of deployment mechanism; even if you have a small project and only one container/server, we recommend automating your deployment.

The main benefits of using an automatic deployment process are as listed:

  • Easy to maintain: Most of the time, the steps needed by the deployment can be stored in files so that you can edit them.
  • Repeatable: You can execute the deployment again and again and it will follow the same steps each time.
  • Less error-prone: We are humans and, as humans, we make mistakes multitasking.
  • Easy to track: There are multiple tools you can use to keep a log of everything that happens in every commit. These tools can also be used to create groups of users who can make deploys. The most common tools you can use are Jenkins, Ansible Tower, and Atlassian Bamboo.
  • Easy to release more often: Having a deployment pipeline in place will help you develop and deploy faster because you will not spend time dealing with the push of your code to production.

Let's look at some ways to automate your deployments, starting with the simplest options and increasing the complexity and features more and more. We will analyze the pros and cons of each one so that, at the end of the chapter, you will be available to choose the perfect deployment system for your project.

Simple PHP script

This is the most simple way you can automate your deployments--you can add a script to your code (in a public location), as shown in the following code:

    <?php
    define('MY_KEY', 'this-is-my-secret-key');
    if ($_SERVER['REQUEST_METHOD'] === 
    'POST' && $_REQUEST['key']  === MY_KEY) {
        echo shell_exec('git fetch && git pull origin master');
    }

In the preceding script, we only do a pull from master if the script is reached with the correct key. As you can see, it is very easy and it can be fired by anyone who knows the secret key, for example, by a browser. If your code repository allows the set up of webhooks, you can use them to fire your script each time a push or commit is done in your project.

Here are the pros of this deployment method:

  • It's easy to create if the work required is small, for example, a git pull
  • It's easy to keep track of changes to the script
  • It's easy to be fired by you or any external tools

Here are the disadvantages of this deployment method:

  • The web server user needs to be able to use the repo
  • It increases in complexity when you need to deal with, for example, branches or tags
  • It is not easy to use when you need to deploy to multiple instances, you will need external tools like rsync
  • Not very secure. If your key gets found out by a third party, they can deploy on your server whatever they want

In an ideal world, all your commits to production will be perfect and pristine, but you know the truth--at some point in the future, you will need to roll back all your changes. If you have this deployment method in place and you want to create a rollback strategy, you have to increase the complexity of your PHP script so that it can manage tags. Another not-recommended option is, instead of adding a rollback to your scripts, you can do, for example, a git undo and push all the changes again.

Ansible and Ansistrano

Ansible is an IT automation engine that can be used to automate cloud provisioning, manage configurations, deploy applications, or orchestrate services among other uses. This engine does not use an agent, so there is no need for additional security infrastructure, it was designed to be used through SSH. The main language used to describe your automation jobs (also called playbooks)is YAML and its syntax is similar to English. Due to the fact that all your playbooks are simple text files, you can store them easily in your repository. An interesting feature that you can find in Ansible is its Galaxy, a hub of add-ons you can use in your playbooks.

Ansible requirements

Ansible uses the SSH protocol to manage all the hosts, and you only need to install this tool on one machine--the machine you will use to manage your fleet of hosts. The main requisite for the control machine is Python 2.6 or 2.7 (from Ansible 2.2 it has support for Python 3), and you can use any OS except Microsoft Windows.

The only requirement on the managed hosts is Python 2.4+, which comes installed by default by most of the UNIX-like operating systems.

Ansible installation

Assuming that you have the correct Python version on your control machine, installing Ansible is very easy with the help of the package managers.

On RHEL, CentOS and similar linux distributions execute the following command to install Ansible:

sudo yum install ansible

The Ubuntu command is as follows:

sudo apt-get install software-properties-common 
&& sudo apt-add-repository ppa:ansible/ansible 
&& sudo apt-get update 
&& sudo apt-get install ansible

The FreeBSD command is as follows:

sudo pkg install ansible

The Mac OS command is as follows:

sudo easy_install pip 
&& sudo pip install ansible

What is Ansistrano?

Ansistrano is an open source project composed with ansistrano.deploy and ansistrano.rollback, two Ansible Galaxy roles used to easily manage your deployments. It's considered to be the Ansible port for Capistrano.

Once we have Ansible available on our machine, it is very easy to install the Ansistrano roles with the following command:

ansible-galaxy install carlosbuenosvinos.ansistrano-deploy  carlosbuenosvinos.ansistrano-rollback

After the execution of this command, you will be able to use Ansistrano in your playbooks.

How does Ansistrano work?

Ansistrano deploys your application following the Capistrano flow:

  1. Setup phase: In this phase, Ansistrano creates the folder structure that will hold the application releases.
  2. Code update phase: In this phase, Ansistrano puts your release in your hosts; it can use rsync, Git, or SVN among other methods.
  3. Symlink phase (see below): After the new release is deployed, it changes the current softlink that points the available release to the new release location.
  4. Cleanup phase: In this phase Ansistrano removes old releases stored in your hosts. You can configure the number of releases in your playbooks through the ansistrano_keep_releases parameter. In following examples you will se how this parameter works

Tip

With Ansistrano, you can hook custom tasks to be executed before and after each task.

Let's look at a simple example to explain how it works. Imagine that your application is deployed to /var/www/my-application; the contents of this folder will be similar to the following example after your first deployment:

-- /var/www/my-application
 |-- current -> /var/www/my-application/releases/20161208145325
 |-- releases
 |   |-- 20161208145325
 |-- shared

As you can see from the preceding example, the current symlink points to the first release we have in our host. Your application will always be available in the same path, /var/www/my-application/current, so you can use this path in any place you need, for example, NGINX or PHP-FPM.

As your deployments continue, Ansistrano will deal with the deploys for you. The next example will show you what your application folder will look like after a second deployment:

-- /var/www/my-application
 |-- current -> /var/www/my-application/releases/20161208182323
 |-- releases
 |   |-- 20161208145325
 |   |-- 20161208182323
 |-- shared

As you can see from the preceding example, now we have two releases in our hosts and symlink was updated to point to the new version of your code. What happens if you do a rollback with Ansistrano? Easy, this tool will remove the latest release you have in your hosts and update the symlink. In our example, your application folder content will be similar to this:

-- /var/www/my-application
 |-- current -> /var/www/my-application/releases/20161208145325
 |-- releases
 |   |-- 20161208145325
 |-- shared

Tip

To avoid problems, if you try to roll back and Ansistrano can't find a previous version to move to, it will do nothing, keeping your hosts without changes.

Deploying with Ansistrano

Now, let's create a small automation system with Ansible and Ansistrano. We are assuming that you have a known and persistent infrastructure available where you will push your app or microservice. Create a folder in your development environment to keep all your deployment scripts.

In our case, we previously created three VMs in our local environment with SSH enabled. Note that we are not covering the provisioning of those VMs but if you want, you can even use Ansible to do it for you.

The first thing you need to create is a hosts file. In this file, you can store and group all your servers/hosts so that you can later use them in the deployment:

[servers:children]
 production
 staging

[production]
192.168.99.200
192.168.99.201

[stageing]
192.168.99.100

In the preceding configuration, we created two groups of hosts-–production and staging. On each one of them, we have a few hosts available; in our case, we set up the IP address of our local VM for testing purposes, but you can use URIs if you want. One of the advantages of grouping your hosts is the ability you have to even create bigger groups; for example, you can create a group formed by other groups. For example, we have a servers group that wraps all the production and staging hosts. If you are wondering what happens if you have a dynamic environment, no problem; Ansible has your back and comes with multiple connectors that you can use to get your dynamic infrastructure, for example, from AWS or Digital Ocean, among others.

Once you have your hosts file ready, it is time to create our deploy.yml file where we will store all the tasks we want to execute in our deployment. Create a deploy.yml file with the following content:

---
- name: Deploying a specific branch to the servers
 hosts: servers
 vars:
     ansistrano_allow_anonymous_stats: no
     ansistrano_current_dir: "current"
     ansistrano_current_via: "symlink"
     ansistrano_deploy_to: "/var/www/my-application"
     ansistrano_deploy_via: "git"
     ansistrano_keep_releases: 5
     ansistrano_version_dir: "releases"

     ansistrano_git_repo: "[email protected]:myuser/myproject.git"
     ansistrano_git_branch: "{{ GIT_BRANCH|default('master') }}"

 roles:
     - { role: carlosbuenosvinos.ansistrano-deploy }

Thanks to Ansistrano, our deployment tasks are very easy to define, as you can see from the preceding example. What we did is create a new task that will be executed in all the hosts wrapped under the tag servers, and define a few variables available for the Ansistrano role. Here, we defined where we will deploy our application on each host, the method we will use for the deploy (Git), how many releases we will keep in the hosts (5), and the branch we want to deploy.

An interesting feature of Ansible is that you can pass variables from the command line to your generic deployment process. This is what we do in the following line:

ansistrano_git_branch: "{{ GIT_BRANCH|default('master') }}"

Here, we are using a GIT_BRANCH variable to define which branch we want to deploy; if Ansible can't find this defined variable, it will use master.

Are you ready to test what we have done? Open a terminal and go to the location where you have stored the deployment tasks. Imagine that you want to deploy the latest versions of your code to your production hosts; you can do it with the following command:

ansible-playbook deploy.yml --extra-vars "GIT_BRANCH=master" --limit production -i hosts

In the preceding command, we are telling Ansible to use our deploy.yml playbook and we also defined our GIT_BRANCH to be master so that this branch will be deployed. As we have all our hosts in the hosts file and we only want to make the deployment to the production hosts, we limited the execution to the desired hosts with --limit production.

Now, imagine that you have a new version ready, all your code was committed and tagged under the v1.0.4 tag, and you want to push this release to your staging environment. You can do it with a very simple command:

ansible-playbook deploy.yml --extra-vars "GIT_BRANCH=v1.0.4" --limit staging -i hosts

As you can see, deploying your application is very easy with Ansible/Ansistrano and it is even easier to roll back to a previously deployed release. To manage the rollbacks, you only need to create a new playbook. Create a rollback.yml file with the following content:

---
- name: Rollback
 hosts: servers
 vars:
     ansistrano_deploy_to: "/var/www/my-application"
     ansistrano_version_dir: "releases"
     ansistrano_current_dir: "current"
 roles:
     - { role: carlosbuenosvinos.ansistrano-rollback }

In the preceding piece of code, we are using the Ansistrano rollback role to move to the previous deployed release. If you only have one release in your hosts, Ansible will not undo the changes because it is not possible. Do you remember the variable we set up in the deploy.yml file, called ansistrano_keep_releases? This variable is very important to know how many rollbacks you can do in your hosts, so adjust it to your needs. To roll back your production servers to the previous release, you can use the following command:

ansible-playbook rollback.yml --limit production -i hosts

As you can see, Ansible is a very powerful tool that you can use for your deployments, but it is not used only for deployments; you can even use it for orchestration, for example. With a vibrant community and with RedHat supporting the project, Ansible is a necessary tool.

Tip

Ansible has an enterprise version of a web tool that you can use to manage all your Ansible playbooks. Even though it needs a paid subscription, if you manage less than ten nodes, you can use it for free.

Other deployment tools

As you can imagine, there are multiple and different tools that you can use to do your deployments and we cannot cover all of them in this book. We wanted to show you a simple one (PHP scripts) and a more complex and powerful one (Ansible), but we don't want you to finish this chapter without knowing the other tools that you can use:

  • Chef: This is an interesting open source tool you can use to manage your infrastructure as code.
  • Puppet: This is an open source configuration management tool with a paid enterprise version.
  • Bamboo: This is a continuous integration server from Atlassian and, of course, you need to pay to use this tool. This is the most complete tool you can use combine with the Atlassian catalog of products.
  • Codeship: This is a cloud continuous deployment solution that aims to be a tool focused on being an end-to-end solution for running tests and deploying apps
  • Travis CI: This is a similar tool to Jenkins used for continuous integration; you can also use it to make your deployments.
  • Packer, Nomad, and Terraform: These are different tools from HashiCorp that you can use to write your infrastructure as code.
  • Capistrano: This is a well-known remote server automation and deployment tool, which is easy to understand and easy to use.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.78.30