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:
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.
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:
git pull
Here are the disadvantages of this deployment method:
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 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 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.
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
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.
Ansistrano deploys your application following the Capistrano flow:
ansistrano_keep_releases
parameter. In following examples you will se how this parameter worksLet'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
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.
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:
3.128.78.30