fritz stelluto
development for digital media
berlin, london

Using Jenkins to replicate WordPress sitesWeekly Challenge

The task: setting Jenkins up to recreate a WordPress site from data stores in a repository.

About the challenge

In the previous weekly challenge I installed the tools needed to set up a continuos integration system for myself. Here I will start using it.

Some artefacts are available on GitHub.

Feature

Feature: setting up CI for WordPress In order to maintain my blog As a developer I need to create CI jobs in apache Ant for my WordPress blog

Requirements for a CI system for WordPress

At this stage I am going to setup Jenkins so that it queries the state of the system (code, assets, and data for a couple of WordPress sites) and then decides what to do with it. I could add hooks to various WP actions, so that so that things happen automatically when the system changes, but I want a generic solution that works for any project.

Here are the kind of jobs I need covered:

  1. I check out the sources on a new machine and have a copy of the current production environment up and running
  2. I make changes to my theme / plugins on a workstation
  3. I upgrade WP itself or a plugin on a workstation
  4. I create new content on a workstation
  5. I edit content on the production server
  6. I update my local version with the latest comments
  7. I roll back changes if things go wrong
  8. I work on a workstation and want to carry on working on another, without the temporary code being deployed
  9. any of these can happen at the same time - e.g. I could start changing some code in my workstation, then make a quick amend to the content directly on the live site while out and about, then carry on working on the code change expecting the content amend not to be overwritten, and so on

2 and 3 are simple subversion jobs - in both cases I push code into svn at one end (a workstation), and pull it out and deploy at the other (the server). 4 and 5 involve db dumps and assets synchronisation in both direction. 6 is a pure db synchronisation job, and 7 is both. 8 and 9 are not really jobs, more a non-functional requirement (i.e., establish a branching strategy). And the first one is basically all of the above in one big job.

So in the end there are only two type of jobs: synching files and dbs with svn, and deploying using ant. That's the theory at least.

Run a copy of the production code from scratch with Jenkins

Scenario: Run a copy of production code from scratch with Jenkins Given that source code and all the tools I need are in subversion And I have created config settings manually as per instructions When I click on a button in Jenkins Then the source code and assets should be checked out And the source code should be copied to a server root of my choice And the database should be created and filled with data from the repository And any previous version with the same parameters should be overwritten And the http server should be started And Jenkins should check that pages are served
This pretty much covers the whole CI flow - all the other scenarios are just subsets of this. Time to create some Jenkins jobs. The Ant and Jenkins files are available on GitHub.

There are two things to bear in mind - Jenkins concepts of jobs and projects are a bit muddled - there is only 'jobs' really. And jobs names don't map to folder names - they are the folder names. What that means is that it makes sense to have a naming convention, such as [PROJECT]-[TYPE OF JOB]-[ENVIRONMENT]-[ETC] to group jobs by project and avoid folder names with spaces. So on the local Jenkins dashboard I select "new job" and call it MY_PROJ-deploy-local-fromScratch, and make it of type "Build a free-style software project". I save it without ticking on anything, then build it once. Now a folder is created at /Users/Shared/Jenkins/Home/workspace/MY_PROJ-deploy-local-fromScratch. That's where I will create the build.xml file for my Ant jobs, and where Svn will checkout the source.

Checking out the sources with Jenkins

To get things going, I connect the Jenkins job to the Svn repository.

Moving sources with Ant from Jenkins

Backing up and restoring the database

In order to restore a database, I need something to restore it from. This is where it gets tricky. WordPress uses MySQL, where backups are better performed using replication, but setting that up is too involved for my current purposes. Right now I want eerything to be saved to, and recreated from, text files. Incremental backups are also not MySQL's forte - restoring from the Binary Log on the production server is not the most efficient approach. That leaves only two tools, mysqldump and mysqlhotcopy. The latter is best practice for MyISAM tables, which is what WordPress uses at the time of writing, while the former is more generic and will work with InnoDB too. For that reason I decided to use mysqldump, so that I can reuse the Ant jobs on all my MySQL based projects.

Backing up the database with mysqldump

On the server, I manually create the inital dump and compress it to save space in the repository mysqldump --user=USER --password --hex-blob --dump-date --single-transaction --opt --order-by-primary --databases DB1 DB2 | gzip > /path/to/my/sql/sources/MY_PROJ-all.sql.gz svn add /path/to/my/sql/sources/MY_PROJ-all.sql.gz svn commit /path/to/my/sql/sources/MY_PROJ-all.sql.gz -m "initial sql dump on `date "+%Y-%m-%d %H:%M:%S"`"

mysqldump
calls the mysqldump utility
--user=USER --password
credentials. Note that I don't use --password=PASSWORD as that would leave PASSWORD in the command history. Using just --password will make mysqldump prompt me for one.
--hex-blob
saves binary data as hex (I don't think WP has any, but still)
--dump-date
to have a comment at the end with the date, just in case I need it for trouble shooting
--single-transaction
useless in this case; it is a reminder should I reuse this on another project, as it only works for InnoDB tables
--opt
(optimized) should be on by default anyway, it is a shortcut for a bunch of best practice options: --add-drop-table --add-locks --create-options --disable-keys --extended-insert --lock-tables --quick --set-charset
--order-by-primary
because it is more efficient to restore database if the rows' primary keys are in order
--databases DB1 DB2
pick the two databases I need
| gzip
send the dump directly to gzip, a data compression utility
> MY_PROJ-all.sql.gz
save the compressed sql dump to a file
svn add MY_PROJ-all.sql.gz
make svn aware of it
svn commit MY_PROJ-all.sql.gz -m "initial sql dump on `date "+%Y-%m-%d %H:%M:%S"`"
add it to the svn repository

Restoring the database from mysqldump with Ant

At the other end, my local machine, I add an Ant target for unzipping the sql and creating the database from it

Tokenizing the database dump with sed

That's not quite it though. WordPress puts absolute paths and URLs all over the database, meaning it won't work on machines with a different setup. There isn't a good workaround for it except going through the sql dump file and substituting some strings with others. Thank heavens for sed, then.

Rebooting Apache and checking whether it restarted correctly

Putting config data under Subversion

One of the requirements in the original feature was "And I have created config settings manually as per instructions". I have put these in local.properties so far. I wasn't sure what to do with it, I was considering using a paramterized build, but that doesn't really make anything easier. Instead:

The build and some config files are available on GitHub.

Challenge 100% complete

This is only one step. It was very involved but hopefully a lot of the groundwork will pay off. In part 3 I shall deal with rolling back and deployment strategies.

Possible future expansions

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strong>