In this example we are going to create a dockerised Symfony application and a Makefile based build script. We will use make command to make running docker and other Symfony related commands simpler.


Structure


.
├── docker
│   └── dev
│      ├── docker-compose.yml
│      ├── Makefile
│      ├── nginx
│      │   ├── app.conf
│      │   ├── app_ssl.crt
│      │   ├── app_ssl.key
│      │   ├── Dockerfile
│      │   └── nginx.conf
│      └── php
│      ├── Dockerfile
│      ├── php.ini
│      └── www.conf
│  
├── .env
└── Other Symfony files and folders

Files


docker-compose.yml


version: "3"

services:

dsa_mysql:
image: "mysql:5.7.24"
hostname: "dsa-mysql"
command: "--default-authentication-plugin=mysql_native_password"
environment:
MYSQL_ROOT_PASSWORD: "root"
MYSQL_DATABASE: "symfony"
MYSQL_USER: "inanzzz"
MYSQL_PASSWORD: "inanzzz"
PS1: "\\u@\\h:\\w\\$$ "

dsa_php:
build:
context: "./php"
hostname: "dsa-php"
volumes:
- "../..:/app:consistent"
depends_on:
- "dsa_mysql"
environment:
PS1: "\\u@\\h:\\w\\$$ "

dsa_nginx:
build:
context: "./nginx"
hostname: "dsa-nginx"
ports:
- "3080:80"
- "3043:443"
volumes:
- "../..:/app:consistent"
depends_on:
- "dsa_mysql"
- "dsa_php"
environment:
PS1: "\\u@\\h:\\w\\$$ "

Makefile


PHP_SERVICE := dsa_php

build:
@docker-compose up -d

composer:
@docker-compose exec -T $(PHP_SERVICE) composer install

database:
@docker-compose exec -T $(PHP_SERVICE) bin/console doctrine:schema:update

test:
@docker-compose exec -T $(PHP_SERVICE) vendor/bin/php-cs-fixer fix src --rules=@PSR2 --using-cache=no --dry-run --verbose --diff
@docker-compose exec -T $(PHP_SERVICE) bin/console security:check

down:
@docker-compose down --volumes
@make -s clean

clean:
@docker system prune --volumes --force

all:
@make -s build
@make -s composer
@make -s database
@make -s test
@make -s down
@make -s clean

app.conf


server {
listen 80;

server_name localhost;

root /app/public;

listen 443 default_server ssl;
ssl_certificate /etc/ssl/certs/app_ssl.crt;
ssl_certificate_key /etc/ssl/private/app_ssl.key;

location / {
try_files $uri /index.php$is_args$args;
}

location ~ ^/index\.php(/|$) {
fastcgi_pass dsa_php:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_hide_header X-Powered-By;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param HTTP_X_REQUEST_ID $request_id;
internal;
}

location ~ \.php$ {
return 404;
}

error_log /var/log/nginx/app_error.log;
access_log /var/log/nginx/app_access.log;
}

app_ssl.crt / app_ssl.key


You can create commands below to create "self signed" SSL certificates. This is only for the "local" environment not the "production".


$ sudo openssl genrsa -out docker/dev/nginx/app_ssl.key 4096
$ sudo openssl req -new -x509 -days 365 -key docker/dev/nginx/app_ssl.key -out docker/dev/nginx/app_ssl.crt

nginx/Dockerfile


FROM nginx:1.15.8-alpine

RUN apk add --no-cache bash

RUN rm -rf /var/cache/apk/*

COPY app.conf /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/nginx.conf
COPY app_ssl.crt /etc/ssl/certs/app_ssl.crt
COPY app_ssl.key /etc/ssl/private/app_ssl.key

nginx.conf


user nginx;

# 1 worker process per CPU core.
# Check max: $ grep processor /proc/cpuinfo | wc -l
worker_processes 2;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
# Tells worker processes how many people can be served simultaneously.
# worker_process (2) * worker_connections (2048) = 4096
# Check max: $ ulimit -n
worker_connections 2048;

# Connection processing method. The epoll is efficient method used on Linux 2.6+
use epoll;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

# Used to reduce 502 and 504 HTTP errors.
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;

# The sendfile allows transfer data from a file descriptor to another directly in kernel.
# Combination of sendfile and tcp_nopush ensures that the packets are full before being sent to the client.
# This reduces network overhead and speeds the way files are sent.
# The tcp_nodelay forces the socket to send the data.
sendfile on;
tcp_nopush on;
tcp_nodelay on;

# The client connection can stay open on the server up to given seconds.
keepalive_timeout 65;

# Hides Nginx server version in headers.
server_tokens off;

# Disable content-type sniffing on some browsers.
add_header X-Content-Type-Options nosniff;

# Enables the Cross-site scripting (XSS) filter built into most recent web browsers.
# If user disables it on the browser level, this role re-enables it automatically on serve level.
add_header X-XSS-Protection '1; mode=block';

# Prevent the browser from rendering the page inside a frame/iframe to avoid clickjacking.
add_header X-Frame-Options DENY;

# Enable HSTS to prevent SSL stripping.
add_header Strict-Transport-Security 'max-age=31536000; includeSubdomains; preload';

# Prevent browser sending the referrer header when navigating from HTTPS to HTTP.
add_header 'Referrer-Policy' 'no-referrer-when-downgrade';

# Sets the maximum size of the types hash tables.
types_hash_max_size 2048;

# Compress files on the fly before transmitting.
# Compressed files are then decompressed by the browsers that support it.
gzip on;

include /etc/nginx/conf.d/*.conf;
}

php/Dockerfile


FROM php:7.2.13-fpm-alpine3.8

RUN apk update \
&& apk add --no-cache $PHPIZE_DEPS \
bash \
git \
zip \
unzip

RUN docker-php-ext-install opcache pdo_mysql
RUN docker-php-ext-enable opcache

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

RUN rm -rf /var/cache/apk/*

COPY php.ini /usr/local/etc/php/conf.d/php.override.ini
COPY www.conf /usr/local/etc/php-fpm.d/www.conf

WORKDIR /app

CMD ["php-fpm", "--nodaemonize"]

php.ini


[PHP]
date.timezone=UTC
log_errors=On
error_reporting=E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors=Off
max_execution_time=60
memory_limit=256M

[opcache]
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
realpath_cache_size=4096K
realpath_cache_ttl=600

www.conf


[global]
daemonize=no

[www]
user=www-data
group=www-data

listen=dsa_nginx:9000

; Dynamicaly chooses how the process manager will control the number of child processes.
pm=dynamic
; The maximum number of child processes to be created.
; This option sets the limit on the number of simultaneous requests that will be served.
; Availalbe RAM in MB / Average RAM used by php-fpm processes in MB=max_children
; 1500MB / 30MB=50 (minus a bit)
pm.max_children=40
; The number of child processes created on startup.
; min_spare_servers + (max_spare_servers - min_spare_servers) / 2
pm.start_servers=2
; The desired minimum number of idle server processes.
pm.min_spare_servers=2
; The desired maximum number of idle server processes.
; 2 or 4 times of the CPU core
pm.max_spare_servers=4
; The number of requests each child process should execute before respawning.
; This can be useful to work around memory leaks in 3rd party libraries.
pm.max_requests=500

.env


As you can see these match variables in "docker-compose.yml" file.


###> doctrine/doctrine-bundle ###
MYSQL_DATABASE=symfony
MYSQL_HOST=dsa_mysql
MYSQL_PORT=3306
MYSQL_USER=inanzzz
MYSQL_PASSWORD=inanzzz
###< doctrine/doctrine-bundle ###

Available commands


# You can run these individually
$ make -sC docker/dev/ build
$ make -sC docker/dev/ composer
$ make -sC docker/dev/ database
$ make -sC docker/dev/ test
$ make -sC docker/dev/ down
$ make -sC docker/dev/ clean

# This will cover all the command listed above in one go
$ make -sC docker/dev/ all

Result


The application is accessible via http://192.168.99.30:3080/ and https://192.168.99.30:3043/.


$ docker-compose -f docker/dev/docker-compose.yml ps
Name Command State Ports
------------------------------------------------------------------------------------------------------
dev_dsa_mysql_1 docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
dev_dsa_nginx_1 nginx -g daemon off; Up 0.0.0.0:3043->443/tcp, 0.0.0.0:3080->80/tcp
dev_dsa_php_1 docker-php-entrypoint php- ... Up 9000/tcp