First steps: A Symfony 4 PHP app in Docker
I’m currently learning Docker, and finding out how to develop a (new) Symfony 4 (PHP 7) application locally on my Mac and run it within a Docker container, instead of hosting it in a Linux VM in VMware Fusion as I used to do. Docker Desktop and the PhpStorm IDE are already installed.
Docker setup
I want to use official, current Docker images from the Docker Hub. A colleague convinced me (better scalability?) to use Nginx instead of my trusty old Apache Web server. So I need the nginx:latest and php:fpm images.
While I can use the Nginx image as-is, I need to create my own image on top of the PHP standard one since I will want to add PHP extensions as needed, and to run Composer in the container. I ended up with this Dockerfile
:
FROM php:fpm
# git and unzip for composer installs
RUN apt-get update && apt-get install -y \
git unzip \
--no-install-recommends && rm -r /var/lib/apt/lists/*
# zip for composer installs
RUN apt-get update && apt-get install -y \
libzip-dev \
&& docker-php-ext-install zip
ENV COMPOSER_HOME /tmp
ENV COMPOSER_VERSION 1.8.5
# "chmod 0777 /tmp/cache" for non-root composer installs
RUN curl --silent --fail --location --retry 3 --output /tmp/installer.php \
--url https://raw.githubusercontent.com/composer/getcomposer.org/cb19…/web/installer \
&& php -r " \
\$signature = '48e3…'; \
\$hash = hash('sha384', file_get_contents('/tmp/installer.php')); \
if (!hash_equals(\$signature, \$hash)) { \
unlink('/tmp/installer.php'); \
echo 'Integrity check failed, installer is either corrupt or worse.' . PHP_EOL; \
exit(1); \
}" \
&& php /tmp/installer.php --no-ansi --install-dir=/usr/bin --filename=composer \
--version=${COMPOSER_VERSION} \
&& composer --ansi --version --no-interaction \
&& rm -f /tmp/installer.php \
&& chmod 0777 /tmp/cache
This docker-compose.yml
file defines my Nginx and PHP Docker setup:
version: '3'
services:
php:
build:
context: ./docker/php
volumes:
- ./app:/opt/app
- ./docker/php/zz-log.conf:/usr/local/etc/php-fpm.d/zz-log.conf
web:
image: nginx:latest
depends_on:
- php
ports:
- "8080:80"
volumes:
- ./app:/opt/app
- ./docker/web/default.conf:/etc/nginx/conf.d/default.conf
The context: ./docker/php
line refers to the directory where I put the Dockerfile shown above.
My Symfony application source files reside in a local app
directory on my Mac, which is empty for now, and mapped via volumes
into both containers as /opt/app
.
See my Github repo for the two configuration files – a tiny zz-log.conf
file that configures PHP log_errors
and display_errors
settings, and the Nginx default.conf
file which contains configuration for Symfony, and hands over PHP requests to the PHP-FPM image.
Nginx listens on port 80 inside the container; on my Mac, I can reach it at localhost:8080.
Thanks to the fantastic PhpStorm Docker support, I can simply click the green “docker-compose up” arrows that show up in docker-compose.yml
in the IDE to start the Docker containers (downloading and building images when run for the first time):
Creating a Symfony application
PhpStorm lets me “Exec” commands within a Docker container, but I prefer my Mac’s Terminal application. To discover the current container IDs (changing after a restart), I use docker ps
:
$ docker ps
CONTAINER ID IMAGE COMMAND
0b83693cc0ff nginx:latest "nginx -g 'daemon of…" …
9fade34cfdb7 symfony-in-docker-example_php "docker-php-entrypoi…" …
Now I run composer create-project
(as per the Symfony documentation) in the PHP container to create a Symfony application in the local app
directory:
$ docker exec --workdir /opt --user daemon:daemon -it 9fade34cfdb7 \
composer create-project symfony/skeleton app
Installing symfony/skeleton (v4.3.1.1)
- Installing symfony/skeleton (v4.3.1.1): Downloading (100%)
[…]
And with that command, my Symfony application is up and running at http://localhost:8080/
:
I can add more required packages via Composer (I usually add Monolog):
$ docker exec --workdir /opt/app --user daemon:daemon -it 9fade34cfdb7 \
composer require symfony/monolog-bundle
And use the Symfony console
command:
$ docker exec --workdir /opt/app --user daemon:daemon -it 9fade34cfdb7 \
bin/console about
-------------------- ---------------------------------
Symfony
-------------------- ---------------------------------
Version 4.3.1
[…]
-------------------- ---------------------------------
PHP
-------------------- ---------------------------------
Version 7.3.5
[…]
-------------------- ---------------------------------
To see Symfony log output on the Docker console output (STDOUT), I change app/config/packages/dev/monolog.yaml
to contain path: "php://stdout"
.
The next step is creating your first page in Symfony!
Thanks
Thanks to the bloggers that helped me figure all this out – Making your dockerised PHP application even better by the Geeky Platypus, My Simple Approach to using Docker and PHP by Paul Redmond, and Structuring the Docker setup for PHP Projects by Pascal Landau.