From 0093369169f49892aec5997841f229a55452c4f7 Mon Sep 17 00:00:00 2001 From: Oleg Krasavin Date: Sat, 29 Dec 2018 15:55:56 +0300 Subject: [PATCH] Initial commit --- .env.dist | 21 +++++ .gitignore | 1 + LICENSE.md | 7 ++ Makefile | 84 ++++++++++++++++++++ README.md | 47 +++++++++++ docker-compose.yml | 109 ++++++++++++++++++++++++++ elk/logstash/logstash.conf | 39 ++++++++++ elk/logstash/patterns/default.conf | 85 ++++++++++++++++++++ elk/logstash/patterns/nginx.conf | 1 + elk/logstash/patterns/symfony.conf | 34 ++++++++ mysql/Dockerfile | 3 + mysql/my.cnf | 34 ++++++++ nginx/Dockerfile | 18 +++++ nginx/docker-entrypoint.sh | 6 ++ nginx/nginx.conf | 32 ++++++++ nginx/symfony.conf.template | 36 +++++++++ php-fpm/Dockerfile | 86 ++++++++++++++++++++ php-fpm/entrypoint.sh | 14 ++++ php-fpm/php-fpm.conf | 121 +++++++++++++++++++++++++++++ php-fpm/php.ini | 15 ++++ rabbitmq/Dockerfile | 3 + rabbitmq/enabled_plugins | 1 + redis/Dockerfile | 3 + 23 files changed, 800 insertions(+) create mode 100644 .env.dist create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 Makefile create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 elk/logstash/logstash.conf create mode 100644 elk/logstash/patterns/default.conf create mode 100644 elk/logstash/patterns/nginx.conf create mode 100644 elk/logstash/patterns/symfony.conf create mode 100644 mysql/Dockerfile create mode 100644 mysql/my.cnf create mode 100644 nginx/Dockerfile create mode 100644 nginx/docker-entrypoint.sh create mode 100644 nginx/nginx.conf create mode 100644 nginx/symfony.conf.template create mode 100644 php-fpm/Dockerfile create mode 100644 php-fpm/entrypoint.sh create mode 100644 php-fpm/php-fpm.conf create mode 100644 php-fpm/php.ini create mode 100644 rabbitmq/Dockerfile create mode 100644 rabbitmq/enabled_plugins create mode 100644 redis/Dockerfile diff --git a/.env.dist b/.env.dist new file mode 100644 index 0000000..52a4040 --- /dev/null +++ b/.env.dist @@ -0,0 +1,21 @@ +TIMEZONE=Europe/Moscow +APP_PROJECT_ROOT=../app +LOGS_ROOT=../logs +APP_PHPFPM_PORT=9000 +APP_NGINX_SERVER_NAME=app.localhost +NGINX_PORT=80 +DB_HOST=mysql +DB_PORT=3306 +DB_ROOT_PASSWORD=root +DB_USER=dbuser +DB_PASSWORD=somePassword +DB_DIR=/var/lib/mysql +REDIS_HOST=redis +REDIS_PORT=6379 +RABBITMQ_HOST=rabbitmq +RABBITMQ_PORT=5672 +RABBITMQ_MANAGEMENT_PORT=15672 +RABBITMQ_USER=rabbitmq +RABBITMQ_PASSWORD=rabbitmq +RABBITMQ_ERLANG_COOKIE=4e15a2412b6fa28647396c2a81e0fb21 +ELK_PORT=81 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..fc91a96 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,7 @@ +## 0BSD license + +Copyright (C) 2006 by Rob Landley + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e94a1b0 --- /dev/null +++ b/Makefile @@ -0,0 +1,84 @@ +SELF_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +PHP_SERVICE := docker-compose exec webapp sh -c + +# Define a static project name that will be prepended to each service name +export COMPOSE_PROJECT_NAME := symfony + +# Create configuration files needed by the environment +SETUP_ENV := $(shell (test -f $(SELF_DIR).env || cp $(SELF_DIR).env.dist $(SELF_DIR).env)) + +# Extract environment variables needed by the environment +export DB_DIR := $(shell grep DB_DIR $(SELF_DIR).env | awk -F '=' '{print $$NF}') + + +## +## ---------------------------------------------------------------------------- +## Environment +## ---------------------------------------------------------------------------- +## + +backup: ## Backup the "db" volume + docker run --rm \ + --volumes-from $$(docker-compose ps -q db) \ + -v $(dir $(SELF_DIR))backup:/backup \ + busybox sh -c "tar cvf /backup/backup.db.tar $(DB_DIR)" + +build: ## Build the environment + docker-compose build + +cache: ## Flush the Symfony cache + $(PHP_SERVICE) "bin/console cache:clear" + +logs: ## Follow logs generated by all containers + 10 most recent entries. + docker-compose logs -f --tail=10 + +logs-full: ## Follow logs generated by all containers + 50 most recent entries. + docker-compose logs -f --tail=50 + +nginx: ## Open a terminal in the "nginx" container + docker-compose exec nginx sh + +app: ## Open a terminal in the "app" container + docker-compose exec app sh + +db: ## Open a terminal in the "db" container + docker-compose exec db sh + +redis: ## Open a terminal in the "redis" container + docker-compose exec redis sh + +rabbit: ## Open a terminal in the "rabbitmq" container + docker-compose exec rabbitmq sh + +elk: ## Open a terminal in the "elk" container + docker-compose exec elk sh + +ps: ## List all containers managed by the environment + docker-compose ps + +restore: ## Restore the "db" volume + docker run --rm \ + --volumes-from $$(docker-compose ps -q db) \ + -v $(dir $(SELF_DIR))backup:/backup \ + busybox sh -c "tar xvf /backup/backup.db.tar /var/lib/mysql" + docker-compose restart db + +start: ## Start the environment + docker-compose build + docker-compose up -d --remove-orphans + +stats: ## Print real-time statistics about containers ressources usage + docker stats $(docker ps --format={{.Names}}) + +stop: ## Stop the environment + docker-compose stop + +.PHONY: backup build cache composer logs logs-full nginx web db redis rabbit elk ps restore start stats stop + +.DEFAULT_GOAL := help +help: + @grep -E '(^[a-zA-Z_-]+:.*?##.*$$)|(^##)' $(MAKEFILE_LIST) \ + | sed -e 's/^.*Makefile://g' \ + | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' \ + | sed -e 's/\[32m##/[33m/' +.PHONY: help \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4ccdc35 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +Real Docker environment for Symfony apps +============== + +This is a complete and hightly flexible stack for running Symfony 4 (latest version: Flex) into Docker containers using docker-compose tool. + +## Features +* Flexible and easily configurable. +* (Almost) production-ready. +* Uses it's own makefile to manage the environment. + +## Installation + +* Clone the repository into `docker` folder (or wherever you wish). +* Make sure you have `make` installed on your host machine. +* Copy `.env.dist` into `.env` and configure to your liking. +* Use `make start` to build & start the env. + + +## Services +* `nginx`: [nginx:1.15-alpine](nginx/Dockerfile) custom NGINX image. +* `php-fpm`: [php:7.2-fpm-alpine](php/Dockerfile) custom image with additional extensions and Composer. +* `redis`: [redis:5.0-alpine](https://hub.docker.com/_/mysql/) official Redis image. +* `elk`: [willdurand/elk](https://hub.docker.com/r/willdurand/elk) complete ELK stack. +* `rabbitmq`: [rabbitmq:3.7-management-alpine](https://hub.docker.com/_/rabbitmq/) RabbitMQ image with admin UI. + +## Logs + +You can access Nginx and your application logs in the following directories on your host machine: + +* `logs/nginx` +* `logs/app` + +## Documentation + +> In order to make things more readable, and maintainable, the documentation has been migrated to +the [repository Wiki](https://github.com/okwinza/docker-symfony/wiki). Where you will find all details about the +installation process along the available instructions for the day-to-day work. + +## Code license + +You are free to use the code in this repository under the terms of the 0-clause BSD license. LICENSE contains a copy of this license. + +## Useful links + +This docker setup is based on following works: +* [ajardin/docker-symfony](https://github.com/ajardin/docker-symfony) +* [eko/docker-symfony](https://github.com/eko/docker-symfony) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3a33152 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,109 @@ +version: '3.7' +services: + db: + image: mysql + build: ./mysql + restart: on-failure + command: ["--default-authentication-plugin=mysql_native_password"] + ports: + - "${DB_PORT}:3306" + volumes: + - db:/var/lib/mysql + environment: + TZ: ${TIMEZONE} + MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} + MYSQL_USER: ${DB_USER} + MYSQL_PASSWORD: ${DB_PASSWORD} + tty: true + + app: + image: app + build: ./php-fpm + restart: on-failure + ports: + - "${APP_PHPFPM_PORT}:9000" + volumes: + - ${APP_PROJECT_ROOT}:/var/www/app:cached + - ${LOGS_ROOT}/app/symfony:/var/www/app/var/log:cached + - ${LOGS_ROOT}/app/php:/var/log/php:cached + environment: + TZ: ${TIMEZONE} + REDIS_HOST: redis + REDIS_PORT: ${REDIS_PORT} + RABBITMQ_HOST: rabbitmq + RABBITMQ_PORT: ${RABBITMQ_PORT} + RABBITMQ_USER: ${RABBITMQ_USER} + RABBITMQ_PASS: ${RABBITMQ_PASSWORD} + DB_HOST: db + DB_PORT: ${DB_PORT} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + links: + - db + - redis + - rabbitmq + tty: true + + nginx: + image: nginx + build: ./nginx + restart: on-failure + ports: + - "${NGINX_PORT}:80" + links: + - app + volumes: + - ${LOGS_ROOT}/nginx:/var/log/nginx:cached + - ${APP_PROJECT_ROOT}:/var/www/app:cached + environment: + TZ: ${TIMEZONE} + APP_PHPFPM_PORT: ${APP_PHPFPM_PORT} + APP_NGINX_SERVER_NAME: ${APP_NGINX_SERVER_NAME} + tty: true + + elk: + image: willdurand/elk + restart: on-failure + ports: + - "${ELK_PORT}:80" + volumes: + - ./elk/logstash:/etc/logstash:cached + - ${LOGS_ROOT}/app:/var/www/app/var/log:cached + - ${LOGS_ROOT}/nginx:/var/log/nginx:cached + environment: + TZ: ${TIMEZONE} + tty: true + + redis: + image: redis + build: ./redis + restart: on-failure + ports: + - "${REDIS_PORT}:6379" + volumes: + - redis-data:/data + environment: + TZ: ${TIMEZONE} + tty: true + + rabbitmq: + image: rabbitmq + build: ./rabbitmq + restart: on-failure + ports: + - "${RABBITMQ_PORT}:5672" + - "${RABBITMQ_MANAGEMENT_PORT}:15672" + volumes: + - "./rabbitmq/enabled_plugins:/etc/rabbitmq/enabled_plugins" + environment: + TZ: ${TIMEZONE} + RABBITMQ_ERLANG_COOKIE: ${RABBITMQ_ERLANG_COOKIE} + RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER} + RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD} + RABBITMQ_DEFAULT_VHOST: / + tty: true + +volumes: + db: + redis-data: + diff --git a/elk/logstash/logstash.conf b/elk/logstash/logstash.conf new file mode 100644 index 0000000..55da3d4 --- /dev/null +++ b/elk/logstash/logstash.conf @@ -0,0 +1,39 @@ +input { + file { + type => "nginx_access" + path => "/var/log/nginx/symfony_access.log" + start_position => beginning + } + file { + type => "app_dev" + path => "/var/www/app/var/log/dev.log" + start_position => beginning + } + file { + type => "app_prod" + path => "/var/www/app/var/log/prod.log" + start_position => beginning + } +} + +filter { + if [type] == "nginx_access" { + grok { + patterns_dir => "/etc/logstash/patterns" + match => { "message" => "%{NGINXACCESS}"} + } + } + else if [type] in ["app_dev", "app_prod"] { + grok { + patterns_dir => "/etc/logstash/patterns" + match => { "message" => "%{SYMFONY}"} + } + } +} + +output { + elasticsearch { + host => "localhost" + cluster => "logstash" + } +} \ No newline at end of file diff --git a/elk/logstash/patterns/default.conf b/elk/logstash/patterns/default.conf new file mode 100644 index 0000000..70a2900 --- /dev/null +++ b/elk/logstash/patterns/default.conf @@ -0,0 +1,85 @@ +USERNAME [a-zA-Z0-9._-]+ +USER %{USERNAME} +INT (?:[+-]?(?:[0-9]+)) +BASE10NUM (?[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))) +NUMBER (?:%{BASE10NUM}) +BASE16NUM (?(?"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``)) +UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12} +# Networking +MAC (?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC}) +CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4}) +WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2}) +COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}) +IPV6 ((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)? +IPV4 (?/(?>[\w_%!$@:.,-]+|\\.)*)+ +TTY (?:/dev/(pts|tty([pq])?)(\w+)?/?(?:[0-9]+)) +WINPATH (?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+ +URIPROTO [A-Za-z]+(\+[A-Za-z+]+)? +URIHOST %{IPORHOST}(?::%{POSINT:port})? +# uripath comes loosely from RFC1738, but mostly from what Firefox +# doesn't turn into %XX +URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\-]*)+ +#URIPARAM \?(?:[A-Za-z0-9]+(?:=(?:[^&]*))?(?:&(?:[A-Za-z0-9]+(?:=(?:[^&]*))?)?)*)? +URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]]* +URIPATHPARAM %{URIPATH}(?:%{URIPARAM})? +URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})? +# Months: January, Feb, 3, 03, 12, December +MONTH \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b +MONTHNUM (?:0?[1-9]|1[0-2]) +MONTHNUM2 (?:0[1-9]|1[0-2]) +MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) +# Days: Monday, Tue, Thu, etc... +DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?) +# Years? +YEAR (?>\d\d){1,2} +HOUR (?:2[0123]|[01]?[0-9]) +MINUTE (?:[0-5][0-9]) +# '60' is a leap second in most time standards and thus is valid. +SECOND (?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?) +TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9]) +# datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it) +DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR} +DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR} +ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE})) +ISO8601_SECOND (?:%{SECOND}|60) +TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}? +DATE %{DATE_US}|%{DATE_EU} +DATESTAMP %{DATE}[- ]%{TIME} +TZ (?:[PMCE][SD]T|UTC) +DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ} +DATESTAMP_RFC2822 %{DAY}, %{MONTHDAY} %{MONTH} %{YEAR} %{TIME} %{ISO8601_TIMEZONE} +DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR} +DATESTAMP_EVENTLOG %{YEAR}%{MONTHNUM2}%{MONTHDAY}%{HOUR}%{MINUTE}%{SECOND} +# Syslog Dates: Month Day HH:MM:SS +SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME} +PROG (?:[\w._/%-]+) +SYSLOGPROG %{PROG:program}(?:\[%{POSINT:pid}\])? +SYSLOGHOST %{IPORHOST} +SYSLOGFACILITY <%{NONNEGINT:facility}.%{NONNEGINT:priority}> +HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT} +# Shortcuts +QS %{QUOTEDSTRING} +# Log formats +SYSLOGBASE %{SYSLOGTIMESTAMP:timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}: +COMMONAPACHELOG %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-) +COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent} +# Log Levels +LOGLEVEL ([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?) \ No newline at end of file diff --git a/elk/logstash/patterns/nginx.conf b/elk/logstash/patterns/nginx.conf new file mode 100644 index 0000000..9025e08 --- /dev/null +++ b/elk/logstash/patterns/nginx.conf @@ -0,0 +1 @@ +NGINXACCESS %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{URIPATHPARAM:request}(?: HTTP/%{NUMBER:httpversion})?|-)" %{NUMBER:response} (?:%{NUMBER:bytes}|-) "(?:%{URI:referrer}|-)" %{QS:agent} %{NUMBER:request_time} %{NUMBER:upstream_response_time} %{NUMBER:gzip_ratio} (?:%{WORD:cache_hit}|-)%{GREEDYDATA} \ No newline at end of file diff --git a/elk/logstash/patterns/symfony.conf b/elk/logstash/patterns/symfony.conf new file mode 100644 index 0000000..d8d5914 --- /dev/null +++ b/elk/logstash/patterns/symfony.conf @@ -0,0 +1,34 @@ +VERYGREEDYDATA (.|\n)* + +SYMFONY_EXCEPTION [^:]* + +SYMFONY_LOG_TYPE request|security|app|profiler|doctrine|event +SYMFONY_LOG_LEVEL DEBUG|INFO|WARNING|ERROR|CRITICAL|ALERT +SYMFONY_LOG %{SYMFONY_LOG_TYPE:log_type}\.%{SYMFONY_LOG_LEVEL:log_level} + +SYMFONY_PARAMETER "[^"]*":( )?"[^"]*" +SYMFONY_PARAMETERS (%{SYMFONY_PARAMETER}(, )?)* +SYMFONY_CONTEXT {.*} +SYMFONY_REQUEST_METHOD GET|POST|PUT|DELETE|HEAD|OPTIONS|CONNECT +SYMFONY_REQUEST_PARAMETERS {"url":"%{GREEDYDATA:request_url}","ip":"%{IP:request_ip}","http_method":"%{SYMFONY_REQUEST_METHOD:request_method}"} + +SYMFONY_REQUEST_INFO Matched route "%{GREEDYDATA:route}" \(parameters: %{SYMFONY_PARAMETERS:parameters}\) +SYMFONY_REQUEST_UNCAUGHT_EXCEPTION %{SYMFONY_EXCEPTION:exception}: %{VERYGREEDYDATA:exception_message} \(uncaught exception\) at %{VERYGREEDYDATA:exception_file} line %{NUMBER:exception_file_line} +SYMFONY_REQUEST_CRITICAL Exception thrown when handling an exception \(ErrorException: %{GREEDYDATA:exception_message} in %{GREEDYDATA:exception_file} line %{NUMBER:exception_file_line}\) +SYMFONY_SECURITY_WARNING_USER_MISSING Username "%{GREEDYDATA:user}" could not be found. +SYMFONY_SECURITY_INFO_USER_AUTHENTICATED User "%{GREEDYDATA:user}" has been authenticated successfully +SYMFONY_SECURITY_INFO_AUTHENTICATION_FAILED Authentication request failed: %{GREEDYDATA:authentication_fail_reason} +SYMFONY_SECURITY_DEBUG Username "%{GREEDYDATA:user}" was reloaded from user provider. +SYMFONY_EVENT_DEBUG_NOTIFICATION Notified event "%{GREEDYDATA:event}" to listener "%{GREEDYDATA:listener}". +SYMFONY_EVENT_DEBUG_PROPAGATION_STOP Listener "%{GREEDYDATA:listener}" stopped propagation of the event "%{GREEDYDATA:event}". +SYMFONY_DOCTRINE_DEBUG (?<=doctrine.DEBUG: ).* + +SYMFONY_REQUEST %{SYMFONY_REQUEST_INFO}|%{SYMFONY_REQUEST_UNCAUGHT_EXCEPTION}|%{SYMFONY_REQUEST_CRITICAL} +SYMFONY_SECURITY %{SYMFONY_SECURITY_WARNING_USER_MISSING}|%{SYMFONY_SECURITY_INFO_USER_AUTHENTICATED}|%{SYMFONY_SECURITY_DEBUG}|%{SYMFONY_SECURITY_INFO_AUTHENTICATION_FAILED} +SYMFONY_EVENT %{SYMFONY_EVENT_DEBUG_NOTIFICATION}|%{SYMFONY_EVENT_DEBUG_PROPAGATION_STOP} +SYMFONY_DOCTRINE %{SYMFONY_DOCTRINE_DEBUG:doctrine_sql_query} +SYMFONY_VARIOUS_INFO Write SecurityContext in the session|Reloading user from user provider.|Read SecurityContext from the session|Populated SecurityContext with an anonymous Token|Access is denied (and user is neither anonymous, nor remember-me)|Unable to store the profiler information.|Remember-me cookie accepted. + +SYMFONY_LOG_MESSAGE %{SYMFONY_REQUEST}|%{SYMFONY_SECURITY}|%{SYMFONY_EVENT}|%{SYMFONY_DOCTRINE}|%{SYMFONY_VARIOUS_INFO:log_various_info}|%{VERYGREEDYDATA:log_unparsed_message} + +SYMFONY ^\[%{TIMESTAMP_ISO8601:date}\] %{SYMFONY_LOG}: %{SYMFONY_LOG_MESSAGE:log_message} (\[\]|%{SYMFONY_CONTEXT:log_context}) (\[\]|%{SYMFONY_REQUEST_PARAMETERS:log_request}) \ No newline at end of file diff --git a/mysql/Dockerfile b/mysql/Dockerfile new file mode 100644 index 0000000..ff9c8d3 --- /dev/null +++ b/mysql/Dockerfile @@ -0,0 +1,3 @@ +FROM mysql:latest +COPY my.cnf /etc/mysql/my.cnf +RUN echo "USE mysql;" > /docker-entrypoint-initdb.d/timezones.sql && mysql_tzinfo_to_sql /usr/share/zoneinfo >> /docker-entrypoint-initdb.d/timezones.sql \ No newline at end of file diff --git a/mysql/my.cnf b/mysql/my.cnf new file mode 100644 index 0000000..189a509 --- /dev/null +++ b/mysql/my.cnf @@ -0,0 +1,34 @@ +# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# +# The MySQL Server configuration file. +# +# For explanations see +# http://dev.mysql.com/doc/mysql/en/server-system-variables.html + +[mysqld] +pid-file = /var/run/mysqld/mysqld.pid +socket = /var/run/mysqld/mysqld.sock +datadir = /var/lib/mysql +secure-file-priv= NULL +# Disabling symbolic-links is recommended to prevent assorted security risks +symbolic-links=0 + +# Fix timezone in logs +log_timestamps = SYSTEM + +# Custom config should go here +!includedir /etc/mysql/conf.d/ diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 0000000..7ba6401 --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,18 @@ +FROM alpine:3.8 + +MAINTAINER Vincent Composieux + +RUN apk add --no-cache tzdata + +RUN apk add --update nginx gettext +RUN rm -rf /var/cache/apk/* && rm -rf /tmp/* + +COPY nginx.conf /etc/nginx/ +COPY symfony.conf.template /etc/nginx/conf.d/symfony.conf.template + +RUN adduser -D -g '' -G www-data www-data + +COPY docker-entrypoint.sh / +RUN dos2unix -u /docker-entrypoint.sh +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["nginx"] diff --git a/nginx/docker-entrypoint.sh b/nginx/docker-entrypoint.sh new file mode 100644 index 0000000..44af2fb --- /dev/null +++ b/nginx/docker-entrypoint.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh +set -eu + +envsubst '${APP_PHPFPM_PORT} ${APP_NGINX_SERVER_NAME}' < /etc/nginx/conf.d/symfony.conf.template > /etc/nginx/conf.d/symfony.conf + +exec "$@" \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..9514032 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,32 @@ +user www-data; +worker_processes 4; +pid /run/nginx.pid; + +events { + worker_connections 2048; + multi_accept on; + use epoll; +} + +http { + server_tokens off; + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 15; + types_hash_max_size 2048; + include /etc/nginx/mime.types; + default_type application/octet-stream; + access_log off; + error_log off; + gzip on; + gzip_disable "msie6"; + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; + open_file_cache max=100; + client_body_temp_path /tmp 1 2; + client_body_buffer_size 256k; + client_body_in_file_only off; +} + +daemon off; diff --git a/nginx/symfony.conf.template b/nginx/symfony.conf.template new file mode 100644 index 0000000..dfc371f --- /dev/null +++ b/nginx/symfony.conf.template @@ -0,0 +1,36 @@ +server { + server_name ${APP_NGINX_SERVER_NAME}; + root /var/www/app/public; + + location / { + try_files $uri /index.php$is_args$args; + } + + location ~ \.php$ { + fastcgi_pass app:${APP_PHPFPM_PORT}; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + fastcgi_param REMOTE_ADDR $remote_addr; + + # When you are using symlinks to link the document root to the + # current version of your application, you should pass the real + # application path instead of the path to the symlink to PHP + # FPM. + # Otherwise, PHP's OPcache may not properly detect changes to + # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126 + # for more information). + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + # Prevents URIs that include the front controller. This will 404: + # http://domain.tld/index.php/some-path + # Remove the internal directive to allow URIs like this + internal; + } + + location ~ \.php$ { + return 404; + } + + error_log /var/log/nginx/symfony_error.log; + access_log /var/log/nginx/symfony_access.log; +} diff --git a/php-fpm/Dockerfile b/php-fpm/Dockerfile new file mode 100644 index 0000000..c33b697 --- /dev/null +++ b/php-fpm/Dockerfile @@ -0,0 +1,86 @@ +FROM php:7.2-fpm-alpine + +LABEL maintainer="Oleg Krasavin " + +ENV IGBINARY_VERSION=2.0.8 \ + PHP_MEMCACHED_VERSION=3.1.2 \ + PHPREDIS_VERSION=4.2.0 \ + PHP_AMQP_VERSION=1.9.3 + +RUN apk upgrade --update --no-cache && \ + apk add --update --no-cache \ + ca-certificates \ + curl \ + bash + +RUN apk add --no-cache tzdata + +RUN apk add --update --no-cache \ + php7-apcu \ + php7-ctype \ + php7-curl \ + php7-dom \ + php7-gd \ + php7-iconv \ + php7-imagick \ + php7-json \ + php7-intl \ + php7-mcrypt \ + php7-fileinfo \ + php7-mbstring \ + php7-opcache \ + php7-openssl \ + php7-pdo \ + php7-pdo_mysql \ + php7-mysqli \ + php7-xml \ + php7-xsl \ + php7-xmlwriter \ + php7-xmlreader \ + php7-soap \ + php7-imap \ + php7-zlib \ + php7-phar \ + php7-tokenizer \ + php7-session \ + php7-simplexml \ + php7-zip \ + php7-ftp + +RUN apk add --update --no-cache libmemcached rabbitmq-c + +RUN apk add --update --no-cache --virtual .build-deps git file re2c autoconf make g++ php7-dev libmemcached-dev cyrus-sasl-dev zlib-dev musl rabbitmq-c-dev pcre-dev && \ + \ + git clone --depth=1 -b ${IGBINARY_VERSION} https://github.com/igbinary/igbinary.git /tmp/php-igbinary && \ + cd /tmp/php-igbinary && \ + phpize && ./configure CFLAGS="-O2 -g" --enable-igbinary && make && make install && \ + cd .. && rm -rf /tmp/php-igbinary/ && \ + echo 'extension=igbinary.so' >> /usr/local/etc/php/conf.d/igbinary.ini && \ + \ + git clone --depth=1 -b v${PHP_MEMCACHED_VERSION} https://github.com/php-memcached-dev/php-memcached.git /tmp/php-memcached && \ + cd /tmp/php-memcached && \ + phpize && ./configure --disable-memcached-sasl && make && make install && \ + cd .. && rm -rf /tmp/php-memcached/ && \ + echo 'extension=memcached.so' >> /usr/local/etc/php/conf.d/memcached.ini && \ + \ + git clone --depth=1 -b ${PHPREDIS_VERSION} https://github.com/phpredis/phpredis.git /tmp/php-redis && \ + cd /tmp/php-redis && \ + phpize && ./configure --enable-redis-igbinary && make && make install && \ + cd .. && rm -rf /tmp/php-redis/ && \ + echo 'extension=redis.so' >> /usr/local/etc/php/conf.d/redis.ini && \ + \ + git clone --depth=1 -b v${PHP_AMQP_VERSION} https://github.com/pdezwart/php-amqp.git /tmp/php-amqp && \ + cd /tmp/php-amqp && \ + phpize && ./configure && make && make install && \ + cd .. && rm -rf /tmp/php-amqp/ && \ + echo 'extension=amqp.so' >> /usr/local/etc/php/conf.d/amqp.ini && \ + \ + apk del .build-deps + +RUN rm -rf /var/cache/apk/* && rm -rf /tmp/* && \ + curl --insecure https://getcomposer.org/composer.phar -o /usr/bin/composer && chmod +x /usr/bin/composer + +COPY php.ini /usr/local/etc/php/php.ini +COPY php-fpm.conf /usr/local/etc/php-fpm.conf + +WORKDIR /var/www/app diff --git a/php-fpm/entrypoint.sh b/php-fpm/entrypoint.sh new file mode 100644 index 0000000..e69c9ad --- /dev/null +++ b/php-fpm/entrypoint.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh +set -euo pipefail + +# Allow the Symfony application to write inside volumes +mkdir -p /var/www/app/var/ && chown -R www-data /var/www/app/var/ + +mkdir -p /var/log/php +touch /var/log/php/php.log +touch /var/log/php/php-slow.log +touch /var/log/php/php-fpm.log + +chown -R www-data /var/log/php + +exec "$@" \ No newline at end of file diff --git a/php-fpm/php-fpm.conf b/php-fpm/php-fpm.conf new file mode 100644 index 0000000..b293484 --- /dev/null +++ b/php-fpm/php-fpm.conf @@ -0,0 +1,121 @@ +;;;;;;;;;;;;;;;;;;;;; +; FPM Configuration ; +;;;;;;;;;;;;;;;;;;;;; + +[global] + +error_log = /var/log/php/php-fpm.log + +; Pid file +; Note: the default prefix is /usr/local/var +; Default Value: none +pid = run/php-fpm.pid + +; Error log file +; If it's set to "syslog", log is sent to syslogd instead of being written +; into a local file. +; Note: the default prefix is /usr/local/var +; Default Value: log/php-fpm.log + + +; syslog_facility is used to specify what type of program is logging the +; message. This lets syslogd specify that messages from different facilities +; will be handled differently. +; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) +; Default Value: daemon +;syslog.facility = daemon + +; syslog_ident is prepended to every message. If you have multiple FPM +; instances running on the same server, you can change the default value +; which must suit common needs. +; Default Value: php-fpm +syslog.ident = php-fpm + +; Log level +; Possible Values: alert, error, warning, notice, debug +; Default Value: notice +log_level = notice + +; If this number of child processes exit with SIGSEGV or SIGBUS within the time +; interval set by emergency_restart_interval then FPM will restart. A value +; of '0' means 'Off'. +; Default Value: 0 +;emergency_restart_threshold = 0 + +; Interval of time used by emergency_restart_interval to determine when +; a graceful restart will be initiated. This can be useful to work around +; accidental corruptions in an accelerator's shared memory. +; Available Units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +;emergency_restart_interval = 0 + +; Time limit for child processes to wait for a reaction on signals from master. +; Available units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +;process_control_timeout = 0 + +; The maximum number of processes FPM will fork. This has been designed to control +; the global number of processes when using dynamic PM within a lot of pools. +; Use it with caution. +; Note: A value of 0 indicates no limit +; Default Value: 0 +; process.max = 128 + +; Specify the nice(2) priority to apply to the master process (only if set) +; The value can vary from -19 (highest priority) to 20 (lowest priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool process will inherit the master process priority +; unless specified otherwise +; Default Value: no set +; process.priority = -19 + +; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. +; Default Value: yes +daemonize = no + +; Set open file descriptor rlimit for the master process. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit for the master process. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Specify the event mechanism FPM will use. The following is available: +; - select (any POSIX os) +; - poll (any POSIX os) +; - epoll (linux >= 2.5.44) +; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) +; - /dev/poll (Solaris >= 7) +; - port (Solaris >= 10) +; Default Value: not set (auto detection) +events.mechanism = epoll + +; When FPM is built with systemd integration, specify the interval, +; in seconds, between health report notification to systemd. +; Set to 0 to disable. +; Available Units: s(econds), m(inutes), h(ours) +; Default Unit: seconds +; Default value: 10 +;systemd_interval = 10 + +;;;;;;;;;;;;;;;;;;;; +; Pool Definitions ; +;;;;;;;;;;;;;;;;;;;; + +[webapp] +user = www-data +group = www-data +listen = 0.0.0.0:9000 +pm = dynamic +pm.max_children = 15 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 4 +pm.max_requests = 1000 +catch_workers_output = yes +slowlog = /var/log/php/slow.log +request_slowlog_timeout = 10s \ No newline at end of file diff --git a/php-fpm/php.ini b/php-fpm/php.ini new file mode 100644 index 0000000..62328f2 --- /dev/null +++ b/php-fpm/php.ini @@ -0,0 +1,15 @@ +date.timezone = Europe/Moscow + +memory_limit=2G +post_max_size=128M +upload_max_filesize=128M + +realpath_cache_size=4096K +realpath_cache_ttl=60 +opcache.validate_timestamps=0 +opcache.memory_consumption=256 +opcache.max_accelerated_files=20000 + +log_errors = On +error_reporting = E_ALL +error_log = /var/log/php/php.log \ No newline at end of file diff --git a/rabbitmq/Dockerfile b/rabbitmq/Dockerfile new file mode 100644 index 0000000..36a3ef0 --- /dev/null +++ b/rabbitmq/Dockerfile @@ -0,0 +1,3 @@ +FROM rabbitmq:3.7-management-alpine + +RUN apk add --no-cache tzdata \ No newline at end of file diff --git a/rabbitmq/enabled_plugins b/rabbitmq/enabled_plugins new file mode 100644 index 0000000..90fdaa3 --- /dev/null +++ b/rabbitmq/enabled_plugins @@ -0,0 +1 @@ +[rabbitmq_management]. \ No newline at end of file diff --git a/redis/Dockerfile b/redis/Dockerfile new file mode 100644 index 0000000..bad4a50 --- /dev/null +++ b/redis/Dockerfile @@ -0,0 +1,3 @@ +FROM redis:5.0-alpine + +RUN apk add --no-cache tzdata \ No newline at end of file