For the past year, instead of working with my customary set of development tools, I’ve been working in the LAMP (Linux, Apache – Nginx, technically –, PHP, and MySQL/MariaDB) technology stack. This world is not new to me. I’ve spent many (many, many) hours developing software with these tools. I was going to be doing all of this development on a Windows-based machine, and I had the checklist committed to memory:
- Install XAMPP
- Install PuTTY for ssh
- Install WinSCP for file transfers
- Suffer through PHPMyAdmin for DB tasks
- Install Nodejs
- Install Yarn
Once I had a dev environment set up, configured, and running, I then needed to transfer this knowledge to team members who hadn’t experienced this ritual before. Hours later, we had a few engineers with (mostly) consistent development environments. This planted in my mind the idea that there had to be a better way.
After a few iterations of development, some roster changes, and environment changes (namely swapping out Apache for Nginx and switching to PHP-FPM), we were feeling some real pain. At this point I started digging into Docker.
I don’t want to understate how much work it required. There was a lot of research, a lot of trial and error, and a lot of failure. However, it was all worth it. We ended up in a really good place. Our entire development environment is defined in a docker-compose.yml that looks like this:
After that, we just imported a .dump file into MySQL, and a developer is given a working instance of our production site. I have personally rebuilt my own environment from scratch in about an hour with this approach. I’m incredibly excited to work with containerized .NET core someday.
We briefly explored containerizing our production environment as well. However, our current continuous integration (CI) and deployment story is pretty good. The benefits of moving to a container-based deployment just weren’t enough to justify the disruption.
Our path to Docker was very iterative. It took a lot of hours to refine that Docker-compose file. Likewise, arriving at our current tool-chain was also a gradual process. We spent a lot of time in the command line for this project. Daily, we use Composer, Artisan (Laravel), Yarn, Git, and MySQL. PowerShell technically works for most of these tasks.
However, if we run into any issues and need to search for a solution, what environment are most solutions posted for? Bash, probably on Ubuntu. Luckily, Windows now has one of those.
The Windows Subsystem for Linux (WSL) is a young, rough, constantly-improving, and beautiful thing. You can download several different flavors from the Microsoft store: Ubuntu, openSUSE, and Fedora. It takes a little tweaking to get everything playing nicely between the WSL shell, the host Windows OS, and our Docker containers, but now I spend my entire workday using a bash shell, and native installations of all our dev tools.
I’ll close with a concrete example of why WSL has been such an advantage.
We had several legacy database tables that were encoded with Latin1. We would occasionally get exceptions when a customer tried to enter Unicode characters in a field that saved to one of these tables. We are not the first team to run into this issue. In fact, a Google search for “convert mysql dump file from latin1 to UTF-8” returns dozens of quality answers and guidance. Dozens of examples of Bash scripts. Scripts utilizing mysqldump, sed, grep, piping, etc. But most of these resources are not applicable for those who are attempting to fix this issue in a pure Windows environment.
Could we have fixed this issue using PowerShell? Sure, but how much extra time would that take? I believe our time is better spent solving this issue in an environment where we could rely on decades of experience from the community that created these tools in the first place. And this is just one example. There are other benefits we have realized, and I fully expect to see more as time goes by.
If you’re running LAMP in Windows using Docker and WSL and get stumped by an issue, leave a comment below. I’m happy to help.