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.
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.
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.
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 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 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 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.
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.
/
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 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
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).
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).
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:
:applicationThis is the name of your PHP application. It should contain only letters, numbers, and underscores.
:repo_urlThis is your Git repository URL. This URL must point to a Git repository, and the repository must be accessible from your remote server.
:deploy_toThis 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_releasesThis is the number of old releases that should be retained in case you want to roll back your application to an earlier version.
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
in Chapter 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}
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.
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/
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.
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:deploydodesc"Build"after:updated,:builddoonroles(:web)dowithinrelease_pathdoexecute:composer,"install --no-dev --quiet"endendendend
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.
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
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:
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.