Let’s Containerize!

To run the dummy project we need the following services:

MySQL as a database. It’s not the best idea to use database container for production environment, but it’s a good option for development and testing.

Nginx as a web server.

PHP-FPM to process PHP code.

MySQL Image

Here is the complete Dockerfile for MySQL image:

The argument VERSION allows us to build images with different MySQL versions using a single Dockerfile.

The init folder in the context directory, contains files, that will be executed on container startup. Let’s create products.sql in this folder, to initialize products table for our application:

Nginx Image

When building production ready images, try to:

Use alpine images as a basis, they are lightweight.

images as a basis, they are lightweight. Avoid mounted volumes for production, make complete images.

Use stages if your dev image differs slightly from production one. When you build an image, you can specify a target, that represents a stage from your Dockerfile. The final image will include all the steps up to the target.

Keeping everything above in mind, we can make a Dockerfile for Nginx:

You could notice, that we only copy assets in production, but not in development stage. We did it on purpose: for development we will mount a volume in the container. This will allow us to see file changes real time, without a need to rebuild the image every time.

The server config, that we copy to the image, almost repeats the one, provided by Symfony tutorial. The only changes are the document root and FastCGI url, that refers to PHP-FPM service:

PHP-FPM Image

The PHP-FPM Docker file is more complex, than the previous ones:

Let’s go though it step by step.

System Dependencies

When installing system dependencies, try to:

Use --no-cache flag. In this case the package manager doesn’t keep downloaded files in cache, that reduces the image size.

flag. In this case the package manager doesn’t keep downloaded files in cache, that reduces the image size. Use --virtual for dependencies, that you want to remove at some point.

We don’t need git (required by Composer) or autoconf gcc g++ make (required for XDebug) in production. We are going to remove these dependencies, that’s why we marked them as dev-deps.

PHP Extensions

Docker comes with useful helpers, that simplify installation and configuration of PHP extensions. Let’s use them to install MySQL PDO driver for database connection and XDebug for code coverage:

PHP Configuration

You can change PHP settings by copying ini files to the image conf.d folder:

In the default.ini file we change memory limit and reporting level of the application:

Composer

I recommend to install hirak/prestissimo package along with Composer. It will dramatically reduce building time:

We will mount project files in PHP-FPM dev container, that’s why we don’t copy source files and don’t execute composer install in dev stage.

Test Stage

It’s better to incapsulate application code and its dependencies inside the image, which will be used for testing:

And change the project files owner to default PHP-FPM user:

Prod Stage

We don’t need dev dependencies in production image:

Neither we need XDebug:

Nor dev utils: