Deployment of PHP Applications
We’ve all been there, working through how we are going to be deploying the next latest and greatest solution for our company. Going through all of the rigger just to think, hey wait a second, how are we going to handle the deployment process and integrating our current solution with what we have ready for a release. Release management is always simple but yet so complex.
This all starts off with versioning, if you are not versioning your application, you have bigger problems to solve. Stop reading and get on to working with Git or SVN; If you think that it is too small for versioning, crawl back in your hole and do everyone a favor and quit the profession (not really, but really). Versioning is the main key to your deployment, you need to be able to version everything, utilize branches for major features and be fully confident in that you will not be dropping productivity in the work schedule due to the deployment in a few days.
The next item on the critical path is having an adequate bug tracker, you need to ensure that you have a solution that supports milestones or releases. These help you to match up the tickets with the release that you will be pushing out the code for. When you make a commit, ensure that it is matched to a ticket in this system as it will be very important later.
Let us start off with the version control structure, in which, we will utilize the standard structure: /trunk, /branches, /tags. In your trunk you will essentially commit anything such as bug fixes, minor features and anything that is not going to take a long time or cause issues in relation to the current code base. Branches will in turn handle your release branch, major features and/or major architectual changes. This may or may not be how you handle it, but I feel that the release branch has to come out of a separate area than the trunk and have the ability to be merged (take it or leave it).
Everything in the release branch must come from the trunk, the trunk is going to be your latest development copy and/or integration copy. You should have an environment that has continuous integration, the current copy on a machine and is controlled through your post-commit hook. In order to merge to your release branch, you should setup a script to do this automatically when it comes to release time and ensure you have a test environment.
In my current environment I do this through the svn merge-info. This process works as such:
- Create a Hash Map of Available Revisions
- Look at the Commit Log and Mark Associated Tickets
- Look up Tickets from the Release
- Merge Revisions to the Release Branch
From here the environment is updated, we also utilize items such as LiquiBase and DBDeploy to handle our database versioning depending on the system that is being utilized. This ensures that we are handing the migration to the current version of the software. By this, we have a pre-deployment file as well as a post-deployment file (depending on the system, however, it is always implemented in this way). From here we run our system through functional testing and unit testing.
If anything is to be fixed, we apply it in the trunk and follow the merging process again before our deployment to our test environment. All of these deployments are handled through svn switch for our lower environments. You will not want to do this when you are in a production environment.
Once the release has been verified to being correct by a QA staff or whomever is in charge of verifying a release, a tagging operation takes place to ensure that we have a mark at the specific location if we ever would have to go back to a prior release. This is where the operations can be a little more crazy. When deploying to a server farm, you need to ensure that you have handled the pre-deployment and post-deployment adequately in order to provide your users the best experience. If you deploy database changes that the applications code was not ready for, you have just provided your users with a failure of your system.
Apply your pre-deployment database changes and/or system changes, then follow up by processing each web server. Do an export of the changes (so that there is not revisioning information) into a release directory. Your can either move the current release to a tag (which has more performance) or create a symlink to the current release. After these changes have been made apply the post-release database or system changes.
You can automate these deployments through Phing, Ant, or a custom script. It is all up to you. I’ve done it through a custom script rather than Ant. This is due to specific requirements, you might find that different departments would rather have a separate process due to their involvement.
While this process will not work for everyone, I believe it will help others that have not gone through the release process before. There is additional aspects to how people deal with releases such as creating a branch per release and then tagging to that branch, however, it is my feeling that all releases need to be merged to the trunk and the trunk merged to the release branch. I presently utilize a single release branch instead of multiple for the best quality and the probability of conflict resolution. If anyone would like me to elaborate further let me know as this is a far different subject than I usually post.
Edit: Included links to software mentioned.