Run a Symfony application using Docker and docker-compose

Why boot a full virtual machine when you can only run Docker containers of what you need to develop your Symfony applications ? This is one question asked by Jeremy Derusse at his Docker dans le développement l'intégration continue talk during Symfony Live Paris 2015. Those slides are really interesting, I invite you to take a look. They demonstrate the power of Docker and docker-compose but are waiting for practice in order to well understand. So I enjoyed a rainy week-end for further study!

Which containers do we need for a simple Symfony application?

Schéma des conteneurs

  • Nginx: A web server,
  • PHP-FPM: A PHP-FPM instance which will be used by Nginx,
  • MySQL: A database, which will be used by PHP-FPM,
  • Symfony application: Our application code, which will be read (and also write) by Nginx & PHP-FPM.

If we now link containers together, here is what the docker-compose.yml file will look like:

application:
    image: symfony/code
    volumes:
        - symfony:/var/www/symfony
        - logs/symfony:/var/www/symfony/app/logs
    tty: true
db:
    image: mysql
    ports:
        - 3306:3306
    environment:
        MYSQL_ROOT_PASSWORD: root
        MYSQL_DATABASE: symfony
        MYSQL_USER: root
        MYSQL_PASSWORD: root
php:
    image: symfony/php-fpm
    expose:
        - 9000:9000
    volumes_from:
        - application
    links:
        - db
nginx:
    image: symfony/nginx
    ports:
        - 80:80
    links:
        - php
    volumes_from:
        - application
    volumes:
        - logs/nginx/:/var/log/nginx

As you can see, each containers use a particular image (symfony/code, symfony/php-fpm et symfony/nginx). We have to construct and build them.

Some of those images import configuration files, all of them are available on the following Github repository I've created: https://github.com/eko/docker-symfony.

Define the symfony/code image

This is the most simple because this image will only be a container which wrap our application code in order to let it available by other containers. The Dockerfile is really simple here:

FROM debian:jessie

VOLUME /var/www/symfony

Define the symfony/php-fpm image

We will install the PHP packages (CLI & FPM) needed by our Symfony application and specify the configuration files we want to use. We also define the user identifier to 1000 for "www-data" in order that he can write data correctly. Finally, we start our PHP-FPM instance and expose the port 9000.

FROM debian:jessie

RUN apt-get update && apt-get install -y php5-common php5-cli php5-fpm php5-mcrypt php5-mysql php5-apcu php5-gd php5-imagick php5-curl php5-intl

ADD symfony.ini /etc/php5/fpm/conf.d/
ADD symfony.ini /etc/php5/cli/conf.d/

ADD symfony.pool.conf /etc/php5/fpm/pool.d/

RUN usermod -u 1000 www-data

CMD ["php5-fpm", "-F"]

EXPOSE 9000

Define the symfony/nginx image

Here, we install the Nginx web server and define the virtual host called for our Symfony application and location/rewrite rules. We run the web server and expose ports 80 and 443.

FROM debian:jessie

RUN apt-get update && apt-get install -y nginx

ADD nginx.conf /etc/nginx/
ADD symfony.conf /etc/nginx/sites-available/

RUN ln -s /etc/nginx/sites-available/symfony.conf /etc/nginx/sites-enabled/symfony
RUN rm /etc/nginx/sites-enabled/default

RUN echo "upstream php-upstream { server php:9000; }" > /etc/nginx/conf.d/upstream.conf

RUN usermod -u 1000 www-data

CMD ["nginx"]

EXPOSE 80
EXPOSE 443

Let's build containers

Our containers definitions are ready to be built! We can build them by running the following commands:

$ docker build -t symfony/code code
$ docker build -t symfony/php-fpm php-fpm
$ docker build -t symfony/nginx nginx

This will result in the following created images:

$ docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
symfony/nginx       latest              84b3420ddc51        7 hours ago         196.4 MB
symfony/php-fpm     latest              cc73fd15858f        7 hours ago         341.1 MB
symfony/code        latest              29780cb0ca24        8 hours ago         125.1 MB
debian              jessie              61e9c91c4f08        4 days ago          125.1 MB

Here we go, you can now run your containers (separately, if you want). The only thing needed now is to run the docker-compose orchestration by typing:

$ docker-compose up

You're done, you now have a full infrastructure running under Docker containers and your application is available on port 80.

Some useful commands

You can display the memory and CPU use of all your containers by typing the following command:

$ docker stats $(docker ps -q)

CONTAINER           CPU %               MEM USAGE/LIMIT       MEM %               NET I/O
0c338e365f18        0.00%               516 KiB/1.961 GiB     0.03%               2.795 KiB/648 B
f3990e53e003        0.00%               12.74 MiB/1.961 GiB   0.63%               1.715 KiB/648 B
f7c8dd163afb        0.00%               455.9 MiB/1.961 GiB   22.70%              2.455 KiB/648 B
fdd84bfe972f        0.00%               5.109 MiB/1.961 GiB   0.25%               1.043 KiB/648 B

You can also remove all your containers and images by typing a single command:

$ docker rm $(docker ps -a -q)
$ docker rmi $(docker images -q)