From bbf3877959f391fbd8ae29dc80672d06288d0e6c Mon Sep 17 00:00:00 2001 From: fatihalp Date: Sun, 30 Apr 2023 20:40:35 +0300 Subject: [PATCH] Docker with Nginx and OPCache (Draft) --- .env-sail | 4 +- Dockerfile | 48 +++++++ composer.json | 1 - docker-compose.yml | 127 +++++++----------- docker/entrypoint.sh | 31 +++++ docker/nginx/nginx.conf | 45 +++++++ docker/nginx/site.conf | 25 ++++ docker/php/php-fpm.conf | 279 ++++++++++++++++++++++++++++++++++++++++ docker/php/php.ini | 6 + 9 files changed, 485 insertions(+), 81 deletions(-) create mode 100644 Dockerfile create mode 100644 docker/entrypoint.sh create mode 100644 docker/nginx/nginx.conf create mode 100644 docker/nginx/site.conf create mode 100644 docker/php/php-fpm.conf create mode 100644 docker/php/php.ini diff --git a/.env-sail b/.env-sail index 8762d0ffa..8a047b79a 100644 --- a/.env-sail +++ b/.env-sail @@ -1,10 +1,12 @@ +APP_NAME=Laravel APP_ENV=local INSTALLED="false" APP_KEY=DYKEBxfEHK1PP4mUbP3gWPtsPZgXh0qX APP_DEBUG=true DEBUG_BAR=false DB_CONNECTION=mysql -DB_HOST=mysql +#DB_HOST=mysql +DB_HOST=hostdocker.internal DB_DATABASE=oopenclassify DB_USERNAME=root DB_PASSWORD= diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..75e923131 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +#docker compose build --no-cache && docker compose up --force-recreate -d + +FROM php:7.4-fpm as php + +ENV PHP_OPCACHE_ENABLE=1 +ENV PHP_OPCACHE_ENABLE_CLI=1 +ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS=1 +ENV PHP_OPCACHE_REVALIDATE_FREQ=1 + + + +RUN usermod -u 1000 www-data + +RUN apt-get update -y +RUN apt-get install -y unzip libpq-dev libcurl4-gnutls-dev nginx +RUN docker-php-ext-install pdo pdo_mysql bcmath + +#RUN pecl install -o -f redis \ +# && rm -rf /tmp/pear \ +# && docker-php-ext-enable redis + +WORKDIR /var/www +COPY --chown=www-data . . + +COPY ./docker/php/php.ini /usr/local/etc/php/php.ini +COPY ./docker/php/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf + +COPY ./docker/nginx/nginx.conf /etc/nginx/nginx.conf + + +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +ENV PORT=8000 +ENTRYPOINT [ "docker/entrypoint.sh" ] + +# ============================================================================== +# node +# FROM node:14-alpine as node + +# WORKDIR /var/www + + +# COPY . . + +#RUN npm install --global cross-env +#RUN npm install + +#VOLUME /var/www/node_modules diff --git a/composer.json b/composer.json index 0238b80bc..87c90f6b9 100644 --- a/composer.json +++ b/composer.json @@ -74,7 +74,6 @@ "visiosoft/integer-field_type": "~2.1.0", "visiosoft/list-field_type": "*", "visiosoft/addblock-extension": "^1.1", - "maatwebsite/excel": "*", "google/recaptcha": "1.2.*", "sentry/sentry-laravel": "2.3.1", "composer/composer": "2.*", diff --git a/docker-compose.yml b/docker-compose.yml index b94e54e5a..d1a464b3f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,82 +1,51 @@ -# For more information: https://laravel.com/docs/sail version: '3' -services: - laravel.test: - build: - context: ./docker/7.4 - dockerfile: Dockerfile - args: - WWWGROUP: '${WWWGROUP}' - image: sail-7.4/openclassify - extra_hosts: - - 'host.docker.internal:host-gateway' - ports: - - '${APP_PORT:-80}:80' - - '${HMR_PORT:-8080}:8080' - environment: - WWWUSER: '${WWWUSER}' - LARAVEL_SAIL: 1 - XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' - XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' - volumes: - - '.:/var/www/html' - networks: - - sail - phpmyadmin: - image: 'phpmyadmin:latest' - ports: - - 8888:80 - environment: - MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' - links: - - "mysql:db" - depends_on: - - mysql - networks: - - sail - mysql: - image: 'mysql/mysql-server:8.0' - ports: - - '${FORWARD_DB_PORT:-3306}:3306' - environment: - MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' - MYSQL_ROOT_HOST: "%" - MYSQL_DATABASE: '${DB_DATABASE}' - MYSQL_USER: '${DB_USERNAME}' - MYSQL_PASSWORD: '${DB_PASSWORD}' - MYSQL_ALLOW_EMPTY_PASSWORD: 1 - volumes: - - 'sail-mysql:/var/lib/mysql' - - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh' - networks: - - sail - healthcheck: - test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"] - retries: 3 - timeout: 5s - redis: - image: 'redis:alpine' - ports: - - '${FORWARD_REDIS_PORT:-6379}:6379' - volumes: - - 'sail-redis:/data' - networks: - - sail - healthcheck: - test: ["CMD", "redis-cli", "ping"] - retries: 3 - timeout: 5s - memcached: - image: 'memcached:alpine' - ports: - - '11211:11211' - networks: - - sail + networks: - sail: - driver: bridge + webapp: + +services: + nginx: + image: nginx:stable-alpine + container_name: ${APP_NAME}_nginx + ports: + - "8000:80" + links: + - php + volumes: + - ./:/var/www/html + - ./docker/nginx/site.conf:/etc/nginx/conf.d/default.conf:rw + - ./docker/logs/nginx:/var/logs/nginx:rw + depends_on: + - php + - database + networks: + - webapp + php: + build: + context: . + dockerfile: Dockerfile + container_name: ${APP_NAME}_php + environment: + - CONTAINER_ROLE=app + volumes: + - ./:/var/www/html + ports: + - "9001:9000" + networks: + - webapp + # Database Server + database: + image: mysql:8.0 + ports: + - 3306:3306 + command: --max_allowed_packet=32505856 # Set max_allowed_packet to 256M (or any other value) + environment: + - MYSQL_DATABASE=oc + - MYSQL_USER=oc + - MYSQL_PASSWORD=oc + - MYSQL_ROOT_PASSWORD=oc + volumes: + - db-data:/var/lib/mysql + volumes: - sail-mysql: - driver: local - sail-redis: - driver: local + db-data: ~ \ No newline at end of file diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 000000000..5363547e3 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +if [ ! -f "vendor/autoload.php" ]; then + composer install --no-progress --no-interaction +fi + +if [ ! -f ".env" ]; then + echo "Creating env file for env $APP_ENV" + cp .env-sail .env +else + echo "env file exists." +fi + +# TODO make role based @fatihalp +role=${CONTAINER_ROLE:-app} + +if [ "$role" = "app" ]; then + php artisan install --ready + php artisan key:generate + php artisan cache:clear + php artisan config:clear + php artisan route:clear + exec docker-php-entrypoint "$@" +elif [ "$role" = "queue" ]; then + echo "Running the queue ... " + php /var/www/artisan queue:work --verbose --tries=3 --timeout=180 +elif [ "$role" = "websocket" ]; then + echo "Running the websocket server ... " + php artisan websockets:serve +fi + diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf new file mode 100644 index 000000000..9521b16aa --- /dev/null +++ b/docker/nginx/nginx.conf @@ -0,0 +1,45 @@ +user www-data; + +events { + worker_connections 2048; +} + +http { + keepalive_timeout 500; + keepalive_requests 5000; + + client_max_body_size 32m; + client_body_buffer_size 32m; + + sendfile on; + server_tokens off; + + upstream php-fpm { + server php:9000; + } + + server { + listen 8000; + server_name example.com; + + root /var/www/public; + index index.php; + + error_log /var/log/nginx/error.log; + access_log /var/log/nginx/access.log; + + include /etc/nginx/mime.types; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location ~ \.php$ { + fastcgi_pass php-fpm; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param SCRIPT_NAME $fastcgi_script_name; + include fastcgi_params; + } + } +} \ No newline at end of file diff --git a/docker/nginx/site.conf b/docker/nginx/site.conf new file mode 100644 index 000000000..5000f032f --- /dev/null +++ b/docker/nginx/site.conf @@ -0,0 +1,25 @@ +server { + listen 80; + index index.php index.html; + server_name localhost; + error_log /var/log/nginx/error.log; + access_log /var/log/nginx/access.log; + root /var/www/html/public; + + client_max_body_size 100M; + fastcgi_read_timeout 1800; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + fastcgi_pass php:9000; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + } +} \ No newline at end of file diff --git a/docker/php/php-fpm.conf b/docker/php/php-fpm.conf new file mode 100644 index 000000000..fad4176da --- /dev/null +++ b/docker/php/php-fpm.conf @@ -0,0 +1,279 @@ +[www] +; 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 + +; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. +; Default Value: yes +;daemonize = yes + +;;;;;;;;;;;;;;;;;;;; +; Pool Definitions ; +;;;;;;;;;;;;;;;;;;;; + +; Multiple pools of child processes may be started with different listening +; ports and different management options. The name of the pool will be +; used in logs and stats. There is no limitation on the number of pools which +; FPM can handle. Your system will tell you anyway :) + +; Start a new pool named 'www'. +; the variable $pool can we used in any directive and will be replaced by the +; pool name ('www' here) +[www] + +; Per pool prefix +; It only applies on the following directives: +; - 'slowlog' +; - 'listen' (unixsocket) +; - 'chroot' +; - 'chdir' +; - 'php_values' +; - 'php_admin_values' +; When not set, the global prefix (or /etc) applies instead. +; Note: This directive can also be relative to the global prefix. +; Default Value: none +;prefix = /path/to/pools/$pool + +; The address on which to accept FastCGI requests. +; Valid syntaxes are: +; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on +; a specific port; +; 'port' - to listen on a TCP socket to all addresses on a +; specific port; +; '/path/to/unix/socket' - to listen on a unix socket. +; Note: This value is mandatory. +listen = 127.0.0.1:8000 + +; Set listen(2) backlog. A value of '-1' means unlimited. +; Default Value: 128 (-1 on FreeBSD and OpenBSD) +;listen.backlog = -1 + +; List of ipv4 addresses of FastCGI clients which are allowed to connect. +; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original +; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address +; must be separated by a comma. If this value is left blank, connections will be +; accepted from any ip address. +; Default Value: any +;listen.allowed_clients = 127.0.0.1 + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. Many +; BSD-derived systems allow connections regardless of permissions. +; Default Values: user and group are set as the running user +; mode is set to 0666 +;listen.owner = nginx +;listen.group = nginx +;listen.mode = 0660 + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +user = www-data +group = www-data + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives: +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; Note: This value is mandatory. +pm = dynamic + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes to be created when pm is set to 'dynamic'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. +; Note: Used when pm is set to either 'static' or 'dynamic' +; Note: This value is mandatory. +pm.max_children = 50 + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = 2 + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = 1 + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = 3 + +; The number of requests each child process should execute before respawning. +; This can be useful to work around memory leaks in 3rd party libraries. For +; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. +; Default Value: 0 +pm.max_requests = 5000 + +; The URI to view the FPM status page. If this value is not set, no URI will be +; recognized as a status page. By default, the status page shows the following +; information: +; accepted conn - the number of request accepted by the pool; +; pool - the name of the pool; +; process manager - static or dynamic; +; idle processes - the number of idle processes; +; active processes - the number of active processes; +; total processes - the number of idle + active processes. +; max children reached - number of times, the process limit has been reached, +; when pm tries to start more children (works only for +; pm 'dynamic') +; The values of 'idle processes', 'active processes' and 'total processes' are +; updated each second. The value of 'accepted conn' is updated in real time. +; Example output: +; accepted conn: 12073 +; pool: www +; process manager: static +; idle processes: 35 +; active processes: 65 +; total processes: 100 +; max children reached: 1 +; By default the status page output is formatted as text/plain. Passing either +; 'html' or 'json' as a query string will return the corresponding output +; syntax. Example: +; http://www.foo.bar/status +; http://www.foo.bar/status?json +; http://www.foo.bar/status?html +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +pm.status_path = /phpstatus + +; The ping URI to call the monitoring page of FPM. If this value is not set, no +; URI will be recognized as a ping page. This could be used to test from outside +; that FPM is alive and responding, or to +; - create a graph of FPM availability (rrd or such); +; - remove a server from a group if it is not responding (load balancing); +; - trigger alerts for the operating team (24/7). +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +ping.path = /phpping + +; This directive may be used to customize the response of a ping request. The +; response is formatted as text/plain with a 200 response code. +; Default Value: pong +ping.response = pong + +; The timeout for serving a single request after which the worker process will +; be killed. This option should be used when the 'max_execution_time' ini option +; does not stop script execution for some reason. A value of '0' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_terminate_timeout = 0 + +; The timeout for serving a single request after which a PHP backtrace will be +; dumped to the 'slowlog' file. A value of '0s' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_slowlog_timeout = 0 + +; The log file for slow requests +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +;slowlog = log/$pool.log.slow + +; Set open file descriptor rlimit. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Chroot to this directory at the start. This value must be defined as an +; absolute path. When this value is not set, chroot is not used. +; Note: you can prefix with '$prefix' to chroot to the pool prefix or one +; of its subdirectories. If the pool prefix is not set, the global prefix +; will be used instead. +; Note: chrooting is a great security feature and should be used whenever +; possible. However, all PHP paths will be relative to the chroot +; (error_log, sessions.save_path, ...). +; Default Value: not set +;chroot = + +; Chdir to this directory at the start. +; Note: relative path can be used. +; Default Value: current directory or / when chroot +;chdir = /var/www + +; Redirect worker stdout and stderr into main error log. If not set, stdout and +; stderr will be redirected to /dev/null according to FastCGI specs. +; Note: on highloaded environement, this can cause some delay in the page +; process time (several ms). +; Default Value: no +;catch_workers_output = yes + +; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from +; the current environment. +; Default Value: clean env +;env[HOSTNAME] = $HOSTNAME +;env[PATH] = /usr/local/bin:/usr/bin:/bin +;env[TMP] = /tmp +;env[TMPDIR] = /tmp +;env[TEMP] = /tmp + +; Additional php.ini defines, specific to this pool of workers. These settings +; overwrite the values previously defined in the php.ini. The directives are the +; same as the PHP SAPI: +; php_value/php_flag - you can set classic ini defines which can +; be overwritten from PHP call 'ini_set'. +; php_admin_value/php_admin_flag - these directives won't be overwritten by +; PHP call 'ini_set' +; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. + +; Defining 'extension' will load the corresponding shared extension from +; extension_dir. Defining 'disable_functions' or 'disable_classes' will not +; overwrite previously defined php.ini values, but will append the new value +; instead. + +; Note: path INI options can be relative and will be expanded with the prefix +; (pool, global or /etc) + +; Default Value: nothing is defined by default except the values in php.ini and +; specified at startup with the -d argument +;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com +;php_flag[display_errors] = off +;php_admin_value[error_log] = /var/log/fpm-php.www.log +;php_admin_flag[log_errors] = on +;php_admin_value[memory_limit] = 32M +php_admin_value[disable_functions] = shell_exec \ No newline at end of file diff --git a/docker/php/php.ini b/docker/php/php.ini new file mode 100644 index 000000000..626b13ca6 --- /dev/null +++ b/docker/php/php.ini @@ -0,0 +1,6 @@ +zend_extension=opcache.so + +opcache.enable=${PHP_OPCACHE_ENABLE} +opcache.enable_cli=${PHP_OPCACHE_ENABLE_CLI} +opcache.validate_timestamp=${PHP_OPCACHE_VALIDATE_TIMESTAMPS} +opcache.revalidate_freq=${PHP_OPCACHE_REVALIDATE_FREQ} \ No newline at end of file