Bu örnek Nginx, MySQL ve PHP-FPM docker container kullanarak Symfony uygulamasını çalıştırılabilir hale getirir. Tüm yapmanız gereken aşağıdaki dosyaları yaratmak ve Symfony uygulamanızı içine kopyalamaktır veya tam tersi. Bu işlemden sonra docker-compose komutu ile sistemi çalıştırabilirsiniz. Bu kadar!


Yapı


Bu yazının en sonunda alternatif bir yapı sürümüne daha var ve bakmanızı tavsiye ederim.


$ tree -a
.
├── docker
│ ├── mysql
│ │ ├── Dockerfile
│ │ ├── init.sh
│ │ └── mysqld.cnf
│ ├── nginx
│ │ ├── default.conf
│ │ ├── Dockerfile
│ │ └── nginx.conf
│ └── php
│ ├── app.sh
│ ├── Dockerfile
│ ├── init.sh
│ ├── install.sh
│ ├── php.ini
│ └── www.conf
├── docker-compose.yml
├── public # You can remove this
│ └── index.php
├── .env
└── .env.dist # Create a .env file from this

Dosyalar


.env


###> symfony ###
APP_ENV=dev
APP_SECRET=secret
APP_DB_USER=user
APP_DB_PASS=pass
###< symfony ###

###> docker ###
MYSQL_ROOT_PASSWORD=root
###< docker ###

docker-compose.yml


php servisini aşağıda gösterildiği gibi tanımlamak, size uygulama içindeki diğer yapılandırma dosyalarını container içine kopyalamanıza yardımcı olur. Örneğin app/config klasöründen bir dosya.


version: '3'

services:

mysql:
build:
context: ./docker/mysql
hostname: nginx
user: mysql
ports:
- 3306:3306
volumes:
- ./var/database:/var/lib/mysql:rw
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
APP_DB_USER: ${APP_DB_USER}
APP_DB_PASS: ${APP_DB_PASS}

php:
build:
context: ../symfony4-docker-platform
dockerfile: ./docker/php/Dockerfile
args:
APP_ENV: ${APP_ENV}
hostname: php
depends_on:
- mysql
ports:
- 9000:9000
volumes:
- .:/app:cached
working_dir: /app
environment:
APP_ENV: ${APP_ENV}
APP_SECRET: ${APP_SECRET}
APP_DB_USER: ${APP_DB_USER}
APP_DB_PASS: ${APP_DB_PASS}

nginx:
build:
context: ./docker/nginx
hostname: nginx
depends_on:
- mysql
- php
ports:
- 80:80
volumes:
- .:/app:cached

docker/mysql/Dockerfile


FROM mysql:5.7.22

COPY init.sh /docker-entrypoint-initdb.d
COPY mysqld.cnf /etc/mysql/mysql.conf.d

docker/mysql/init.sh


#!/bin/bash

printf "\n\033[0;44mPreparing the database\033[0m\n"

# Makes sure that the database is up before running database queries
echo "Checking if the database is up ..."
while ! mysqladmin ping -h"localhost" --silent; do
echo "Waiting for database to come up ..."
sleep 2
done
echo "Database is up ..."

# Create an application specific non-root user with all privileges
create="CREATE USER IF NOT EXISTS '${APP_DB_USER}'@'%' IDENTIFIED BY '${APP_DB_PASS}';"
grant="GRANT ALL PRIVILEGES ON *.* TO '${APP_DB_USER}'@'%' IDENTIFIED BY '${APP_DB_PASS}' WITH GRANT OPTION;"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "$create$grant"

docker/mysql/mysqld.cnf


[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
symbolic-links = 0

character_set_server=utf8
collation_server=utf8_unicode_ci

explicit_defaults_for_timestamp = 1

docker/nginx/Dockerfile


FROM nginx:1.13.8

COPY default.conf /etc/nginx/conf.d
COPY nginx.conf /etc/nginx

docker/nginx/default.conf


server {
listen 80 default_server;

server_name localhost; # OR app.com www.app.com

root /app/public;

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

location ~ ^/index\.php(/|$) {
fastcgi_pass 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;
internal;
}

location ~ \.php$ {
return 404;
}

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

docker/nginx/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;
}

docker/php/Dockerfile


FROM php:7.2-fpm

ARG APP_ENV

COPY ./docker/php/init.sh /tmp
RUN chmod +x /tmp/init.sh
RUN /tmp/init.sh

COPY ./docker/php/install.sh /tmp
RUN chmod +x /tmp/install.sh
RUN /tmp/install.sh

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

COPY ./docker/php/app.sh /
RUN chmod +x /app.sh
RUN /app.sh

ENV LANG en_GB.UTF-8
ENV LANGUAGE en_GB:en
ENV LC_ALL en_GB.UTF-8

RUN apt-get autoremove --purge \
&& apt-get -y clean \
&& rm -rf /var/lib/apt/lists/*

docker/php/php.ini


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

[opcache]
; http://symfony.com/doc/current/performance.html
opcache.enable_cli = 1
opcache.memory_consumption = 256
opcache.max_accelerated_files = 20000
realpath_cache_size = 4096K
realpath_cache_ttl = 600

docker/php/www.conf


[www]

user = www-data
group = www-data

listen = 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

docker/php/init.sh


#!/bin/bash

printf "\n\033[0;44mChecking the existence of 'APP_ENV' variable\033[0m\n"

if [[ -z "${APP_ENV}" ]]
then
printf "\033[0;31mVariable does not exist.\033[0m\n\n"
exit 1;
fi

printf "\033[0;32mVariable exists.\033[0m\n\n"

docker/php/install.sh


#!/bin/bash

printf "\n\033[0;44mInstalling system packages for the \"${APP_ENV}\" environment\033[0m\n"

apt-get update
apt-get install -y --no-install-recommends zip unzip nano tree locales

sed -i 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/g' /etc/locale.gen
ln -s /etc/locale.alias /usr/share/locale/locale.alias
locale-gen en_GB.UTF-8

ln -snf /usr/share/zoneinfo/Europe/London /etc/localtime
echo Europe/London > /etc/timezone

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

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

if [ "${APP_ENV}" == "dev" ] || [ "${APP_ENV}" == "test" ]
then
pecl install xdebug
docker-php-ext-enable xdebug
fi

docker/php/app.sh


#!/bin/bash

printf "\n\033[0;44mPreparing the application for the \"${APP_ENV}\" environment\033[0m\n"

if [ "${APP_ENV}" == "dev" ] || [ "${APP_ENV}" == "test" ]
then
echo "Run symfony commands for \"dev\" or \"test\" environments"
# composer install --no-interaction
else
echo "Run symfony commands for \"prod\" or \"stag\" environments"
# composer install --no-interaction --no-dev --optimize-autoloader
fi

echo "Run symfony commands for all environments"

# bin/console doctrine:migrations:migrate --no-interaction
# ...

printf "\n\033[0;44mBringing the \"${APP_ENV}\" environment up\033[0m\n"

Kurulum


$ docker-compose up -d --build

Test


Önce IP adresini almak için aşağıdaki komutu çalıştırın.


$ echo $(docker network inspect {your-network-name-goes-here} | grep Gateway | grep -o -E '[0-9\.]+')
172.18.0.1

$ curl 172.18.0.1 # Or localhost
# You should get a nice response

Alternatif versiyon


Yapı


.
├── app # Symfony application goes in here
│ └── public
│ └── index.php
├── docker
│ ├── mysql
│ │ ├── Dockerfile
│ │ ├── init.sh
│ │ └── mysqld.cnf
│ ├── nginx
│ │ ├── default.conf
│ │ ├── Dockerfile
│ │ └── nginx.conf
│ └── php
│ ├── Dockerfile
│ ├── init.sh
│ ├── install.sh
│ ├── php.ini
│ └── www.conf
├── .env
├── .env.dist # Create a .env file from this
└── docker-compose.yml

docker-compose.yml


version: '3'

services:

mysql:
build:
context: ./docker/mysql
hostname: nginx
user: mysql
ports:
- 3306:3306
volumes:
- ./data/database:/var/lib/mysql:rw
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
APP_DB_USER: ${APP_DB_USER}
APP_DB_PASS: ${APP_DB_PASS}

php:
build:
context: ../api-doc
dockerfile: ./docker/php/Dockerfile
args:
APP_ENV: ${APP_ENV}
hostname: php
ports:
- 9000:9000
depends_on:
- mysql
volumes:
- ./app:/app:cached
working_dir: /app
environment:
APP_ENV: ${APP_ENV}
APP_DB_USER: ${APP_DB_USER}
APP_DB_PASS: ${APP_DB_PASS}

nginx:
build:
context: ./docker/nginx
hostname: nginx
ports:
- 80:80
depends_on:
- mysql
- php
volumes:
- ./app:/app:cached