Over the Christmas holidays, among the ski trips, family get-togethers, drinking and overeating, I’ve finally had a few spare hours to devote to learning web dev stuff. Putting into practice my recently-acquired knowledge of Vagrant and virtualization was the first thing I did. Here was my goal:
- Set up a private online Git repository
- Set up a Vagrant/Chef -built dev project / environment on my laptop
- Push the project to my online repo
- Clone the repo to my iMac
- Spin up the fully functional virtual dev environment on my iMac
- Make some changes on the iMac
- Push the changes back to the online repo
- Pull the project back to my laptop, see the changes
- Celebrate with a beer
1. Set up a private online Git repo
- I’m currently a team of 1 (but hope to eventually share some projects)
- I don’t have any projects worth sharing with the world right now
Bitbucket got the nod because their pricing model makes it free to host unlimited private repos for up to 5 users. I’m also very familiar with Atlassian’s product suite, as we use Jira and Confluence extensively at the office.
Getting set up was pretty quick. I then followed the nicely-written Bitbucket 101 Tutorial, a great way to learn Git basics and the tool.
2. Set Up a Dev Project / Environment on my Laptop
I took a few detours here because I wanted to really understand the provisioning part of Vagrant’s capabilities. I started the Chef tutorials, which require signing up for a Chef Enterprise demo and then realized that the free Chef-Solo tool, natively supported by Vagrant, is all I really needed for my modest purposes. After all, I’m not managing a server farm here; I just need to keep provisioning (i.e. server configurations) to be kept consistent across development environments until I’m ready to deploy something. The Chef Ruby blocks (provisioning instructions), written into the Vagrantfile environment definition, travel with the project and are under source code version control. So when I make an environment change in the Vagrantfile and push it to the master on Bitbucket, I (and eventually other developers) can automatically update their environments with:
But getting Chef initially set up is a bit tricky for a novice, particularly one who has no Ruby experience. There are a bunch of community-managed chef “cookbooks” for popular server setups like MySQL, PHP, and the like. It’s basically a case of ensuring your project has access to the right cookbooks so that Vagrant can use the Vagrantfile instructions to provision your environment (e.g. install MySQL and set the root password, enable Apache features, etc.) But figuring out which cookbooks are needed to handle dependencies between cookbooks, as well as properly forming the JSON parameters wasn’t trivial.
I continued googling and came upon a couple of interesting ways of making this easier. First, I looked at Puphpet, which provides “A simple GUI to set up virtual machines for PHP Web development.” I really like this tool. It makes it possible to establish many different environment configurations with a few clicks. Trouble was, it was based on Puppet and not Chef. I did a quick search on Puppet vs. Chef. Popular opinion seemed to point to Chef being the more flexible “devops” tool from a developer’s perspective. Vagrant supports both of them.
Because I had already invested so much time figuring out Chef, I tried to find a Chef-based equivalent to Puphpet and found rove.io. At the time of this writing, Rove doesn’t seem as robust or feature-rich as Puphpet, but I gave it a try anyway. Rove generates a file that assumes you’re using librarian-chef, prompting yet another educational detour for me. Librarian provides dependency management for Chef cookbooks; in other words, instead of putting all the Chef cookbooks directly into your project, it grabs the correct version for your project from wherever they’re managed and hosted, like Composer does for PHP, and Bundler does for Ruby. A good idea, particularly when you’re using community-managed cookbooks.
I had rove.io generate a Vagrantfile and a Cheffile (librarian-chef’s config) and was feeling good about this new, easy way to set up an environment. But I ran into trouble with the librarian-chef install step, which was throwing a very verbose Ruby error. Googling this, I traced it back to a known, recently-surfaced defect in Librarian that apparently wouldn’t get fixed until the developers came back from holidays.
Oh well. Time for a new tack. I’ll check back on rove.io, librarian-chef and probably also on Puphpet eventually.
In the meantime, I went back to the demo environment that I had cloned from github writing my last post. It includes the full stack I need on my projects: Apache, MySQL, PHP and Composer (the latter with an config file entry for Slim). This empty project contains a lot of Chef cookbooks, and I’m assuming they’re all necessary, though I don’t know that for sure. This was why I was hoping to start from a clean slate instead of repurposing a demo. Nevertheless, I just made some basic customizations for my purposes, including making the “project” directory, to which Apache is pointing in the VM, a directory shared to my host machine so I can point my OS X-based dev tools at it. I wrote a simple “hello world” index.php to verify everything worked.
Great success! Onto the next steps.
Steps 3 through 9
The rest of the environment setup exercise went pretty quickly. I referred back to the Bitbucket docs to refresh my memory on basic Git usage and getting Git and public keys set up properly on the iMac (I had been working on the laptop to this point.) I cleared the .git directory from the project and initiated a new one which I pushed to the repo I set up on Bitbucket. The one wrinkle I encountered was when I forgot to commit locally before pushing, which resulted in a somewhat misleading error message.
Once the project was in my private hosted repo, I cloned it to the iMac and ran
…and my virtual environment with the full stack was now running (identically) on my desktop machine.
I made a few a changes, including running
from within the VM, which downloaded the Slim dependencies into the project folder. When I did a Git dry run add, I noted that these were now under source control, which seemed funny to me, since Composer is handling the versioning of these dependencies. Sure enough, the Composer docs confirm that it’s a best practice to not commit the Composer-managed dependencies to my repo. To accomplish this, I added Composer’s vendor directory to a .gitignore rule. Note that the composer.lock file should remain under source control so that everyone on the project is using the same versions of the PHP dependencies.
I added the changes, committed them locally, then pushed them back to the master. No problems.
To finish, I did a git pull from the online repo to my laptop and verified the changes there. Everything worked as expected!
And all of a sudden, it was beer o’clock.