Migrating our PHP applications to Docker without sacrificing performance

At We Make Waves, we’re continuously improving our cloud-based infrastructure and development workspaces. Most recently, we’ve migrated all of our projects from running on bare metal to Docker. Our motivation for doing so was to take advantage of:

  • Isolation: We can run multiple applications with different dependencies on the same machine. E.g. Run different versions of Node/PHP per application. Applications won’t interact with each other, also allowing us to parallelise our integration tests on the same machine.
  • Security: Applications run in their own isolated environment, and so a vulnerability in one won’t affect others. Docker also encourages you to only run and expose necessary programs.
  • Reproducibility: We compile versions of our applications as images, meaning we can identically reproduce what would run in production anywhere else before.
  • Service-orientation: Our applications could be split into smaller, horizontally scalable micro-services that interact with each other for better resource efficiency.
  • Rapid Deployment: A container orchestrator starts and stops Docker containers on instances, instead of waiting for new instances to start. Speeding up rolling deployments from 15 minutes to less than 60 seconds (dependent on health-checks).
  • Standardisation: Allows us to run officially maintained versions of common services such as MySQL, Redis, RabbitMQ easily.

Maintaining performance

All benchmarks have been run on a machine with the following specification:

  • Ubuntu Linux 17.10 x64
  • php-fpm 7.2
  • nginx 1.12.2
  • Intel Core i7–7567U @ 3.5Ghz CPU
  • 16GB DDR4 RAM
  • Samsung 850 EVO M.2 256GB

We’ve used a skeleton Symfony 4 application with the lucky numbers route added as the target benchmark.

Running this on bare metal with PHP-FPM + NGINX gives us the following results:

Docker solutions

Solution 1: Official PHP-FPM + NGINX

From a service-oriented viewpoint, we’d expect to have one container per purpose. A small Symfony app or WordPress CMS should only require one container to run the app, and a separate database container where necessary. Keeping the database container separate allows us to use external database services such as Amazon’s RDS in deployment and local docker databases in development.

Solution 2: PHP w/ Apache

Solution 3: Custom PHP-FPM w/ NGINX

Results

From the results, it’s clear that our custom Docker PHP-FPM w/ NGINX container greatly outperformed the official PHP images by ~6x, with close performance to our current bare metal setup. We use images like this in all of our PHP Docker deployments as the small performance loss from bare metal is within a small enough tolerance for us to be happy and is offset by the advantages listed at the start of this post.

We make digital products that deliver impact for entrepreneurs, startups and forward thinking organisations. Let’s Make Waves! wemakewaves.digital