Docker is a great way to emulate live server environment. Sure, you don't have the same hardware, but you can have the same infrastructure stack like multiple web, PHP-FPM, Database, CDN server and so on. Another reason why to use Docker for PHP development is, that it's faster than Vagrant and needs much fewer resources as Virtual Box machines. But it's also possible to use Docker in a Vagrant Box.

Looking for an extended german version? There are also slides from my PHP Usergroup Dresden talk available.

PHP webserver stack

A typical PHP webserver stack contains nginx, PHP-FPM and a MySQL database like MariaDB. How much time do you need to setup such a system? What if I would say, you need only 20 lines of configuration, Docker and some minutes? I'm curious, no! ;-) We at prooph software have some Docker images for development, which fits this webserver stack and we have a cool example app which uses this webserver stack and some other cool features like CQRS, Service Bus and Event Sourcing with Snapshots.

If you not have already installed and optimized Docker, take a look at using Docker with OverlayFS on Ubuntu. Here is the Docker Compose YAML configuration which setups the PHP webserver stack with nginx, PHP-FPM and MariaDB. Save this configuration to an empty directory or an example project with name docker-compose.yml.

If you destroy the container, the data of the database will be lost in this example!

nginx:
  image: prooph/nginx:www
  ports:
      - "8080:80"
      - "443:443"
      # these ports are for Zend Z-Ray
      - "10081:10081"
      - "10082:10082"
  links:
    - php:php
  volumes_from:
    - dataphp

php:
  image: prooph/php:7.0-fpm
  links:
    - mariadb:mariadb
  volumes_from:
    - dataphp

dataphp:
  image: debian:jessie
  volumes:
    - .:/var/www

mariadb:
  image: mariadb
  ports:
    - 3306:3306
  environment:
    - MYSQL_ROOT_PASSWORD=dev
    - MYSQL_USER=dev
    - MYSQL_PASSWORD=dev
    - MYSQL_DATABASE=proophessor

The nginx vHost is configured for the folder public. Create an index.php file with <?php echo 'Hello World!'; if it doesn't exists. Now start the Docker containers with docker-compose up -d and open the browser at http://localhost:8080. nginx is configured with HTTP/2 and SSL. Check this with https://localhost.

Use a database data container

To avoid losing database data if you destroy the container you need a Docker data container for the database. The MariaDB Docker image has a volume /var/lib/mysql defined, so you can mount a Docker data container at this location. You don't want that the database data is available in your PHP Docker container. It's necessary to change the mounted paths of the PHP Docker data container with a list of needed folders for the webserver. This is an exercise for you.

What's about PHP debugging

With Docker you are free to switch your environment in seconds. If you want to use Xdebug, simply change the line 15 with prooph/5.6-php-fpm-xdebug and rebuild your server stack with docker-compose stop && docker-compose rm -f && docker-compose up -d. Now you can debug your application. Ensure that your IDE is listen to port 10000, becaue port 9000 is used by PHP-FPM. If you need help, please check my blog post about remote PHP debugging.

Do you need a PHP Profiler? No problem, change line 2 with prooph/nginx:zray and line 15 prooph/php:5.6-fpm-zray to use Zend Z-Ray Profiler. You have to configure the Zend Z-Ray URL. This is why the ports 10081 and 10082 are exposed in the example above. Don't know which PHP profiler you should use? Read more about PHP Profiler Z-Ray, Blackfire and Tideways.

Production best practice

There were some questions how to use PHP Docker container in production. Well, put the PHP source code into the PHP Docker image. Your logs should be logged to stdout or you use another Docker log driver. Product images or user generated content should be mounted into the container, so you can use a CDN and another Docker volume plugin driver like flocker to support more than one server.

You don't need Ansible, Puppet or Chef. Settings like DB credentials should be defined as environment variables. This is really cool, because this image with your version of the source code runs on production, staging, testing and development without changing the configuration. No more environment checks or switches in your application.

It's easy to deploy a new version. Spin up the new container and stop the old container. Switching back to the old version is also easy. You don't have to maintenance your server host system, if you use a Docker hosting provider. Simply build a new image and ship it.

The nginx image doesn't know anything of your PHP application. The mount of the PHP data to the nginx Container in the example above is used for the application assets (CSS, JS, images). So it's easier to start, but it's not mandatory, especially when you use a CDN.

Conclusion

With Docker it's so easy to build infrastructure for development like a production environment. You can also override your production Docker images with an extended development environment where you have running a PHP profiler. And last but not least, you can check how your application works on scale with less ressources as with virtual machines.