Hot Deploying PHP on OpenShift

Hot deployment helps avoid application downtime

When you push changes to OpenShift the service stops your application then builds and deploys the new code before starting the app back up again. This means your application is temporarily unavailable, and may be unnecessary depending on your changes. To avoid downtime you can opt to hot deploy your code instead. In this blog post we'll look at how to do that for PHP applications, but many other cartridge types also support hot deployment.

Set up

To try out these instructions you are going to need an OpenShift Online account. If you don't have one yet, you can sign up for free here.

You should also install the OpenShift client tools on your machine. There are instructions on how to do that for a variety of operating systems at the OpenShift Dev Center. Once they are installed, run the rhc setup command.

Create a PHP application

With the OpenShift client tools ready to go, creating a new PHP application is a one-liner:

$ rhc create-app myphpapp php-5.3

When the above command is executed in your terminal, your application will be created and cloned. You should see output that concludes with something similar to the following:

Your application 'myphpapp' is now available. 

SSH to: 
Git remote: ssh://
Cloned to:  /home/codemiller/code/myphpapp 

Run 'rhc show-app myphpapp' for more details about your app. 

Open a web browser window and go to your new application, using the URL given on the command line.

Explore PHP cartridge repository structure

Change into the directory where your application was cloned and view the contents, including hidden files and directories (ls -a on *nix systems).

You should see php, libs and misc directories as well as the .openshift directory, which contains OpenShift configuration. Inside .openshift are three other directories: action_hooks, cron and markers.

In the php directory you will find the index.php file that defines what you currently see at the application URL.

Change code and deploy

As it happens there is no actual PHP in the default index.php, so let's replace it with a simple Hello World page. Open php/index.php and change the content to the following:

        <title>Hello World!</title>
        <?php echo '<h1>Hello World</h1>'; ?>

Save the file and run the following Git commands in your terminal to commit the change and push it to the cloud.

$ git commit -am "Updated index page"
$ git push

In the output there will be messages similar to the following, showing that the PHP cartridge has been stopped and restarted:

remote: Stopping PHP cartridge 
remote: Waiting for stop to finish 
remote: Building PHP cartridge 
remote: Starting application myphpapp 
remote: Starting PHP cartridge 

If you try to access your application during the push you may receive a 503 HTTP status code and see an Apache 'Service Temporarily Unavailable' page. This is what we want to avoid by using hot deployment.

Change application to hot deploy

Changing your application to hot deploy on OpenShift is as easy as adding an empty file in the right location. Within your PHP application's Git repository, navigate to .openshift/markers/ and create a file there called hot_deploy. Use Git to add and commit the file and push your changes.

$ cd applicationName/.openshift/markers
$ touch hot_deploy
$ git add hot_deploy
$ git commit -m "Adding hot deployment marker"
$ git push

The output should now include messages that show the application has been rebuilt but the cartridge has not been restarted:

remote: Not stopping cartridge php because hot deploy is enabled 
remote: Building PHP cartridge 
remote: Starting application myphpapp 
remote: Not starting cartridge php because hot deploy is enabled 

If you refresh your application during the push, this time you will not see a 'Service Temporarily Unavailable' page, but rather simply get the new version of the page once it becomes available. When you make further changes to your application and push them to the cloud, they will now be deployed without a server restart. Pretty simple, huh!

Change back to regular deployment

To change your application back to the default so that the PHP cartridge restarts when you push new content, remove the hot_deploy marker.

$ rm applicationName/.openshift/markers/hot_deploy
$ git commit -am "Removing hot deployment marker"
$ git push

Hot deploying applications built with Jenkins

Hot deployment works even if you are using Jenkins to build your application on another gear and having it synced back to where the server is running. You enable hot deployment with a marker file as described above.

Hot deploying Zend apps

Hot deployment can also be enabled for the Zend cartridge by adding the hot_deploy marker file as detailed above.

Hot deploying scalable applications

The process for enabling hot deployment is exactly the same for scalable applications. When you hot deploy a scalable application, you will see output indicating that both the PHP and HAProxy cartridges are still running. The new version is synced to each gear while the application remains available.

remote: Not stopping cartridge php because hot deploy is enabled 
remote: Not stopping cartridge haproxy because hot deploy is enabled 
remote: Building PHP cartridge 
remote: Starting application myphpapp 
remote: Not starting cartridge haproxy because hot deploy is enabled 
remote: Application will not be stopped during gear sync due to presence of hot_deploy marker 
remote: Not starting cartridge php because hot deploy is enabled 

As we have seen, hot deploying PHP applications on OpenShift is simple, which means you have more time to focus on your apps. Happy coding!

What's Next

Interesting, I have never messed with doing the hot deploys, but it sounds useful. Is there a list of cartridges that this will and will not play nice with? Python, Rails, Java, etc?

I believe that was also linked on the blog, but here's a link to the User Guide section on Hot Deployment.

What are the consequences of enabling hot-deploy? I mean, if you have to push a lot of code (changed) could it happen that an application will eventually fail for some user(s) (online) when they request a page and only some part of the code is pushed/applied ? or is the push transactional?