Modern PHP (2015)
Part III. Deployment, Testing, and Tuning
Chapter 9. Deployment
We’ve got a provisioned server running nginx and PHP-FPM. Now we need to deploy our PHP application to a production server. There are many ways to push code into production. FTP was a popular way to deploy PHP code back when PHP developers first started banging rocks together. FTP still works, but today there are safer and more predictable deployment strategies. This chapter shows you how to use modern tools to automate deployment in a simple, predictable, and reversible way.
Version Control
I assume you are using version control, right? If you are, good job. If you aren’t, stop what you are doing and version control your code. I prefer to version control my code with Git, but other version control software like Mercurial works, too. I use Git because it’s what I know, and it works seamlessly with popular online repositories like Bitbucket and GitHub.
Version control is an invaluable tool for PHP application developers because it lets us track changes to our codebase. We can tag points in time as a release, we can roll back to a previous state, and we can experiment with new features on separate branches that do not affect our production code. More important, version control helps us automate PHP application deployment.
Automate Deployment
It is important that you automate application deployment so that it becomes a simple, predictable, and reversible process. The last thing you want to worry about is a complicated deployment process. Complicated deployments are scary, and scary things are used less often.
Make It Simple
Instead, make your deployment process a simple one-line command. A simple deployment process is less scary, and that means you’re more likely to push code to production.
Make It Predictable
Make your deployment process predictable. A predictable process is even less scary because you know exactly what it is going to do. It should not have unexpected side effects. If it runs into an error, it aborts the deployment process and leaves the existing codebase in place.
Make It Reversible
Make your deployment process reversible. If you accidentily push bad code into production, it should be a simple one-line command to roll back to the previous stable codebase. This is your safety net. A reversible deployment process should make you excited—not afraid—to push code into production. If you screw up, just roll back to the previous release.
Capistrano
Capistrano is software that automates application deployment in a simple, predictable, and reversible way. Capistrano runs on your local machine and talks with remote servers via SSH. Capistrano was originally written to deploy Ruby applications, but it’s just as useful for any programming language—including PHP.
How It Works
You install Capistrano on your local workstation. Capistrano deploys your PHP application to a remote server by issuing SSH commands from your local workstation to the remote server. Capistrano organizes application deployments in their own directories on the remote server. Capistrano maintains five or more application deployment directories in case you must roll back to an earlier release. Capistrano also creates a current/ directory that is a symlink to the current application deployment’s directory. Your production server’s Capistrano-managed directory structure might look like Example 9-1.
Example 9-1. Example directory structure
/
home/
deploy/
apps/
my_app/
current/
releases/
release1/
release2/
release3/
release4/
release5/
When you deploy a new application release to production, Capistrano first retrieves the latest version of your application code from its Git repository. Next, Capistrano places the application code in a new release directory. Finally, Capistrano symlinks the current/ directory to the new release directory. When you ask Capistrano to roll back to a previous release, Capistrano points the current/ directory symlink to a previous release directory. Capistrano is an elegant and simple deployment solution that makes PHP application deployments simple, predictable, and reversible.
Install
Install Capistrano on your local machine. Do not install Capistrano on your remote servers. You’ll need ruby and gem, too. OS X users already have these. Linux users can install ruby and gem with their respective package managers. After you install ruby and gem, install Capistrano with this command:
gem install capistrano
Configure
After you install Capistrano, you must initialize your project for Capistrano. Open a terminal, navigate to your project’s topmost directory, and run this command:
cap install
This command creates a file named Capfile, a directory named config/, and a directory named lib/. Your project’s topmost directory should now have these files and directories:
Capfile
config/
deploy/
production.rb
staging.rb
deploy.rb
lib/
capistrano/
tasks/
The Capfile file is Capistrano’s central configuration file, and it aggregates the configuration files located in the config/ directory. The config/ directory contains configuration files for each remote server environment (e.g., testing, staging, or production).
NOTE
Capsitrano configuration files are written in the Ruby language. However, they are still easy to edit and understand.
By default, Capistrano assumes you have multiple environments for your application. For example, you might have separate staging and production environments. Capistrano provides a separate configuration file for each environment in the config/deploy/ directory. Capistrano also provides the config/deploy.rb configuration file, which contains settings common to all environments.
In each environment, Capistrano has the notion of server roles. For example, your production environment may have a front-facing web server (the web role), an application server (the app role), and a database server (the db role). Only the largest applications necessitate this architecture. Smaller PHP applications generally use only one machine that runs the web server (nginx), application server (PHP-FPM), and database server (MariaDB).
For this demonstration, I’m only going to use Capistrano’s web role and ignore its app and db roles. Capistrano’s roles let you organize tasks to be executed only on servers that belong to a given role. This isn’t something we’re going to worry about here. However, I am going to respect Capistrano’s notion of server environments. This demonstration will use the production environment, but the following steps are equally applicable to other environments (e.g., staging or testing).
The config/deploy.rb file
Let’s look at the config/deploy.rb file. This configuration file contains settings common to all environments (e.g., staging and production). Most of our Capistrano configuration settings go in this file. Open the config/deploy.rb file in your preferred text editor and update these settings:
:application
This is the name of your PHP application. It should contain only letters, numbers, and underscores.
:repo_url
This is your Git repository URL. This URL must point to a Git repository, and the repository must be accessible from your remote server.
:deploy_to
This is the absolute directory path on your remote server in which your PHP application is deployed. This would be /home/deploy/apps/my_app as shown in Example 9-1.
:keep_releases
This is the number of old releases that should be retained in case you want to roll back your application to an earlier version.
The config/deploy/production.rb file
This file contains settings only for your production environment. This file defines the production environment roles, and it lists the servers that belong to each role. We’re only using the web role, and we have only one server that belongs to this role. Let’s use the server we provisioned inChapter 7. Update the entire config/deploy/production.rb file with this content. Make sure you replace the example IP address:
role :web, %w{deploy@123.456.78.90}
Authenticate
Before we deploy our application with Capistrano, we must establish authentication between our local computer and our remote servers, and between our remote servers and the Git repository. We already discussed how to set up SSH key-pair authentication between our local computer and remote server. You should also establish SSH key-pair authentication between your remote servers and the Git repository.
Use the same instructions we discussed earlier to generate an SSH public and private keypair on each remote server. The Git repository should have access to each remote server’s public key; both GitHub and Bitbucket let you add multiple public SSH keys to your user account. Ultimately, you must be able to clone the Git repository to your remote servers without a password.
Prepare the Remote Server
We’re almost ready to deploy our application. First, we need to prepare our remote server. Log in to your remote server with SSH and create the directory in which we’ll deploy our PHP application. This directory must be readable and writable by the deploy user. I like to create a directory for my applications in the deploy user’s home directory, like this:
/
home/
deploy/
apps/
my_app/
Virtual host
Capistrano symlinks the current/ directory to the current application release directory. Update your web server’s virtual host document root directory so that it points to Capistrano’s current/ directory. Given this filesystem diagram, your virtual host document root might become/home/deploy/apps/my_app/current/public/; this assumes your PHP application contains a public/ directory that serves as the document root. Restart your web server to load your virtual host configuration changes.
Software dependencies
Your remote server doesn’t need Capistrano, but it does need Git. It also needs any software required to run your PHP application. You can install Git with these commands:
# Ubuntu
sudo apt-get install git;
# CentOS
sudo yum install git;
Capistrano Hooks
Capistrano allows us to run our own commands at specific moments (or hooks) during application deployment. Many PHP developers manage application dependencies with Composer. We can install Composer dependencies during each Capistrano deployment with a Capistrano hook. Open the config/deploy.rb file in your preferred text editor and append this Ruby code:
namespace :deploy do
desc "Build"
after :updated, :build do
on roles(:web) do
within release_path do
execute :composer, "install --no-dev --quiet"
end
end
end
end
TIP
If your project uses the Composer dependency manager, make sure Composer is installed on your remote servers.
Our application’s dependencies are now installed automatically after each production deployment. You can read more about Capistrano hooks on the Capistrano website.
Deploy Your Application
Now’s the fun part! Make sure you’ve committed and pushed your most recent application code to your Git repository. Then open a terminal on your local computer and navigate to your application’s topmost directory. If you’ve done everything correctly, you can deploy your PHP application with this one-line command:
cap production deploy
Roll Back Your Application
In the off chance you deploy bad code to your production environment, you can roll back to a previous release with this one-line command:
cap production deploy:rollback
Further Reading
I’ve only scratched the surface. Capistrano has many more features that further streamline your deployment workflow. Capistrano is my favorite deployment tool, but there are many other tools available, including:
§ Deployer
§ Magallanes
§ Rocketeer
What’s Next
We’ve provisioned a server, and we’ve automated our PHP application deployments with Capistrano. Next we’ll discuss how to ensure our PHP applications run as expected. To do this, we’ll use testing and profiling.