Improving our DevOps with Vagrant, Ansible, and PhpStorm
A long, long time ago we used only one tool for syncing development instances with production environments - FTP. You could copy files from a local to a remote machine and that was pretty much it. So it was very surprising to see a few people raise their hand at Smashing Conference in San Francisco earlier this year when the speaker asked who is still using FTP for deployment. It sent shivers down my spine. :)
Over the years, we at Netgen improved slowly but are still not where we want to be. The main problem is that we have many projects and clients with different infrastructure in type and size. It is very hard to consolidate the process in that situation.
Here is what we have managed so far:
- We are using SSH and authorized_keys to access remote servers. It doesn’t sound like a big deal in 2016 but it is not a trivial thing to do either. We built our own tool for deploying and revoking keys of our team members so it simplifies the management
- Several years ago we migrated completely to git (GitHub and Bitbucket). This was an important step in consolidating code management and simplifying deployment
- Using eZ Publish 5 and Symfony stack, we learned the environment specific configuration and dependency management with Composer. It got even better once legacy eZ Publish extensions were supported by Composer. This allowed us to manage packages, dependencies, and easier installation on various server environments in a better way.
When using Symfony stack and eZ Publish 5, the backend development was mostly done in PHP rather than in eZ legacy templates. This caused the switch of backend development to the local developer machines. That, in return, led to new problems regarding the different OSes and PHP versions the developers use etc. Some would work natively on Linux or Mac while Windows users had to use a VirtualBox appliance.
But this was still not ideal. We were wasting time on local installations and configurations, chasing weird bugs on production due to different PHP versions, etc.
Vagrant or Docker
A year ago we started to dig into this and we found two options that could help us out: Docker as a container tool and Vagrant as a virtual appliance provisioner. Docker was already starting to produce a buzz while Vagrant was a bit older but solid. With the help of our partner Srdjan, who had more experience with this than us, we chose Vagrant and the service level provisioner Ansible. Looking back, it still feels like we did the right choice despite the fact Docker is even more popular today.
Let me give you a quick review of our reasoning:
- First of all, we wanted to change our operations, how we do things, but not to dive into a new technology just because it is new. This change is an ongoing process and it takes time, so we wanted a simple tool that is adequate to our needs: booting a dev environment on any developer machine in our company as well as our partners’ and clients’
- As we were building on top of a complex stack, the configuration of the environment needed to be simple
- Since we intended for this to be in use not just by our company but far wider, we needed it to be usable on Linux, Mac, and Windows.
- Working from the IDEs should have been made possible from the host machine
At that time, Docker seemed more complex to manage and a bit too young, with lots of changes happening all the time. A big advantage of Docker was that it ran natively on Linux, but since we needed to support Mac and Windows too, this advantage was not as important to us as Vagrant provisioning a VirtualBox machine that basically works everywhere.
Therefore, we chose Vagrant with Ansible provisioning the services like Apache, MySQL, PHP, Solr, etc. We managed to configure the NFS mounting of the vhost folder so that the host machine mounted the folder from the virtual machine. We experienced difficulties with file system speed on some OSes in some cases, but other mounting options proved to be much worse.
The good thing was that we were able to boot a similar environment for all developers and it worked out well. Whenever we need to work locally we save time by running Vagrant provisioning and then working in PhpStorm installed on the host machine.
Most importantly, we simplified local development and changed and improved our developer operations. In the future, if we figure out Docker would be a better option, it will not be that hard to switch.
We open sourced our setup
You can find this setup on our GitHub account: github.com/netgen/vagrant-ansible-ezpublish
The repo is intentionally set up to be used independently of a specific project. That way we don’t need to update the Vagrant configuration on the projects every time we want to change something, which facilitated things for us because we have a lot of small projects. Of course, if necessary, the configuration can be copied to the project repo and customized further.
Our Vagrant configuration actually has two versions depending on the type of mount used for project folder. I will explain this in the next section of this post.
There are several options you can switch between in provisioning/vagrant.yml file, depending on your needs:
- PHP version 5.5 or 5.6 (hopefully 7 soon)
- PHP-FPM or standard
- Install and activate Xdebug or not
Anyway, it has everything needed to run a standard eZ Publish 5 or eZ Platform installation.
One of the most problematic things regarding virtual appliances is how to handle the files. Vagrant offers more options in this area but all of them have performance issues.
Our first approach was to mount the working folder from the host in the provisioned appliance (VirtualBox instance) automatically. We tested with several mounting options and choose NFS as the fastest one. It worked OK with SSD storage but not as well on the traditional hard drives. The native VirtualBox FS proved even worse.
The strength of this approach is that the work can be done on the host in PhpStorm, for instance. The weakness is that eZ Publish and Symfony, the main technologies we use, write a lot of files, especially in dev mode, so it has quite an impact on the performance. The impact varies on the host OS - it proved to work well on Mac and Linux but not for Windows.
At some point, we introduced the reverse NFS option, is also covered in the similar Mugo’s post. The idea was to mount the folder in the appliance from the host. This option gave different performance results, better in some cases but completely unusable on Windows host. It also exposed one very dangerous use case: as the files are not on the host but are mounted, there is a possibility of losing or changing them by simply closing the lid of the laptop.
The result is that we now support 2 options with 2 separated configuration files. Use the one that suits you by copying it to Vagrantfile:
Before we started using eZ Publish 5 and Symfony, we had been doing the majority of the work in eZ legacy templates and used various editors to do the job, mostly Sublime Text. However, with the new eZ stack and Symfony more work needs to be done in PHP. The best environment for that purpose, in our opinion, is PhpStorm which we have been using the last few years.
There are many good traits of PhpStorm, I will mention only a few important to this context.
- Symfony integration is well known and used
- A plugin for eZ Platform and eZ Publish 5 was developed by our friend Henning
- There has also been a Vagrant integration for a while now
- It can be used on different OSes: Mac, Linux, Windows
Once a Vagrant box is running the application, PhpStorm can be installed on the host machine so you can work with your project locally. For debugging, we have the xDebug module available, but not activated by default.
All this makes PhpStorm a perfect companion for our DevOps needs. You can do everything you need without ever leaving the PhpStorm window.
Summer Camp experiences
As we started to use Vagrant internally on many projects, the idea soon emerged to also use it for the Summer Camp virtual machine we prepare every year for the participants. Before this, we had used VirtualBox to set up the appliance and send the image to everyone before the event. It was a simple but solid way. Nevertheless, we wanted to improve the process by creating one main repo with the Vagrant configuration so that the appliance can be provisioned before or even after the event.
Here’s what we’ve done:
- The main repo for Summer Camp 2015 was created
- Vagrant + Ansible configuration added
- All workshops were added as sub modules
- We created a script that will call install script in every sub module
- Sub modules should prepare init script that will load the database, run Composer install, and anything else necessary
We did testing in-house and with speakers. At the Camp thing went mostly all right, except we underestimated the number of Windows laptops and some laptops were a bit too old to run the virtual appliance. We use Linux and Mac like most of the speakers so we didn’t test Windows adequately. Provisioning Windows was not easy since the Ansible could not be run outside of the appliance and the performance of the mounted file system was worse than on Mac or Linux, as explained above. It proved difficult to provide a great experience for all participants due to the above-mentioned difficulties.
What we have learned from this is that, for Summer Camp, we should provision as much as possible upfront and give participants fewer tasks to do to get the box running. Most importantly, we learned to communicate the prerequisites more clearly.
Still, despite the described problems, most of the Summer Camp 2015 participants had the Vagrant based appliance working and used it during workshops. Also, on the page of every workshop you can find the instructions we provided on how to provision the appliance and the video recordings - much better for the workshop replay and also improves the experience.
At Web Summer Camp 2016 we are planning to go a step further and introduce the whole development experience inside the box. We will install the PhpStorm inside the virtual appliance so that all participants have the same toolset. There will even be a workshop about the advanced use of PhpStorm on the first day.
Trying out eZ
In the meanwhile, you can play with our Vagrant setup and try out eZ Platform and/or eZ Studio.
You have two options for trying out eZ Platform and you also need to figure out the latest release tag on GitHub:
For example, we will be using the v1.4.0 tag. We recommend using the tagged releases, not dev-master, as they should be more stable and it is easier to seek help afterward.
Here are the steps for installing:
1. Clone our repo:
git clone https://github.com/netgen/vagrant-ansible-ezpublish.git && cd vagrant-ansible-ezpublish
2. Choose the version of the Vagrantfile (nfs or reverse-nfs), for example:
cp Vagrantfile-nfs Vagrantfile
3. Boot up and provision the box with:
4. Log in to the box with:
5. Remove the .gitkeep file:
6. Clone eZ Platform, clean or demo (mind the dot at the end of commands):
git clone --branch v1.4.0 https://github.com/ezsystems/ezplatform.git . git clone --branch v1.4.0+demo.v1 https://github.com/ezsystems/ezplatform-demo.git .
7. Run Composer (use default parameters at the end except for database name which should be "ezpublish"):
composer install --no-dev
8. Run installation command (for demo install use "demo" instead of "clean" option in installer):
php app/console --env=prod ezplatform:install clean
php app/console --env=prod assetic:dump
Steps for installing eZ Studio are similar to those for eZ Platform, but not the same. The trial version is available at support.ez.no/downloads.
1.-4. steps are the same.
5. Untar the package inside the Vagrant box with:
tar --strip-components=1 -xf ezstudio-dist-1.x.0-ttl.tar.gz
composer run-script post-install-cmd
php app/console --env=prod ezplatform:install demo
And that is it. :)
PhpStorm and Vagrant with Ansible simplify the development on the local machines. It is easier to bootstrap projects and manage service dependencies, to switch the PHP versions, and so on. This way, all developers have a common environment. It does produce a performance impact due to virtualization, but it doesn’t present a significant problem on the newer hardware with adequate memory.
There are more improvements to be done with our DevOps. Once Docker supports Mac and Windows in a better way, we will recheck what we can do with it and maybe replace Vagrant. Who knows, we will see. :)