From ca7781fb0f30ef372d7d797ec86f54bb7a293189 Mon Sep 17 00:00:00 2001 From: Antonio Spinelli Date: Mon, 31 May 2021 00:19:29 -0300 Subject: [PATCH 1/2] Speed up PHP-fpm container on MacOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many MacOS users may be facing slow responses from Shop or Admin when running the sylius application in the container. The main reason is how docker was build in the MacOS architecture. The PHP application has thousands of files to be loaded in memory (vendor directory mainly). So, to decrease the page response time, the vendor directory is not synced into the container. It will be ignored by docker-composer.yml using the named volume. Also, was added a health check for the PHP-fpm container to know when it is ready. If you want to check healthiness, just run the command `docker-compose ps` to see the container State. The HEALTHCHECK instruction tells Docker how to test a container to check that it is still working. This can detect cases such as a web server stuck in an infinite loop and unable to handle new connections, even though the server process is still running. The PHP and PHP-FPM configurations received some adjustments to get better support development environment experience using containers. I did pick up these updates from two other contributors that I co-authored in this commit. Co-authored-by: Kévin Dunglas Co-authored-by: arti0090 --- .env | 3 +- Dockerfile | 23 ++++++++++++--- README.md | 48 ++++++++++++++++++++++++++++++++ docker-compose.yml | 39 ++++++++++---------------- docker/php/docker-entrypoint.sh | 20 +++++-------- docker/php/docker-healthcheck.sh | 12 ++++++++ docker/php/php-cli.ini | 12 +++++--- docker/php/php.ini | 11 ++++++-- docker/php/sylius.conf | 28 +++++++++++++++++++ 9 files changed, 148 insertions(+), 48 deletions(-) create mode 100644 docker/php/docker-healthcheck.sh create mode 100644 docker/php/sylius.conf diff --git a/.env b/.env index 00581e5952..1eaf2d1f14 100644 --- a/.env +++ b/.env @@ -6,13 +6,14 @@ APP_ENV=dev APP_DEBUG=1 APP_SECRET=EDITME +PHP_DATE_TIMEZONE=UTC ###< symfony/framework-bundle ### ###> doctrine/doctrine-bundle ### # Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url # For a sqlite database, use: "sqlite:///%kernel.project_dir%/var/data.db" # Set "serverVersion" to your server version to avoid edge-case exceptions and extra database calls -DATABASE_URL=mysql://root@127.0.0.1/sylius_%kernel.environment% +DATABASE_URL=mysql://root:nopassword@mysql/sylius_${APP_ENV} ###< doctrine/doctrine-bundle ### ###> symfony/swiftmailer-bundle ### diff --git a/Dockerfile b/Dockerfile index 7648fba49c..4922ae8bef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,20 +3,21 @@ ARG PHP_VERSION=7.4 ARG NODE_VERSION=10 -ARG NGINX_VERSION=1.16 +ARG NGINX_VERSION=1.17 FROM php:${PHP_VERSION}-fpm-alpine AS sylius_php # persistent / runtime deps RUN apk add --no-cache \ acl \ + fcgi \ file \ gettext \ git \ mariadb-client \ ; -ARG APCU_VERSION=5.1.17 +ARG APCU_VERSION=5.1.18 RUN set -eux; \ apk add --no-cache --virtual .build-deps \ $PHPIZE_DEPS \ @@ -33,6 +34,7 @@ RUN set -eux; \ ; \ \ docker-php-ext-configure gd --with-jpeg=/usr/include/ --with-webp=/usr/include --with-freetype=/usr/include/; \ + docker-php-ext-configure zip; \ docker-php-ext-install -j$(nproc) \ exif \ gd \ @@ -59,12 +61,18 @@ RUN set -eux; \ \ apk del .build-deps COPY --from=composer:latest /usr/bin/composer /usr/bin/composer -COPY docker/php/php.ini /usr/local/etc/php/php.ini -COPY docker/php/php-cli.ini /usr/local/etc/php/php-cli.ini +COPY docker/php/php.ini /usr/local/etc/php/php.tmp +COPY docker/php/php-cli.ini /usr/local/etc/php/php-cli.tmp + +ARG PHP_DATE_TIMEZONE=UTC +RUN sh -c "envsubst < /usr/local/etc/php/php.tmp > /usr/local/etc/php/php.ini" +RUN sh -c "envsubst < /usr/local/etc/php/php-cli.tmp > /usr/local/etc/php/php-cli.ini" # https://getcomposer.org/doc/03-cli.md#composer-allow-superuser ENV COMPOSER_ALLOW_SUPERUSER=1 +# install Symfony Flex globally to speed up download of Composer packages (parallelized prefetching) RUN set -eux; \ + composer global require "symfony/flex" --prefer-dist --no-progress --classmap-authoritative; \ composer clear-cache ENV PATH="${PATH}:/root/.composer/vendor/bin" @@ -93,6 +101,7 @@ RUN set -eux; \ composer dump-autoload --classmap-authoritative; \ APP_SECRET='' composer run-script post-install-cmd; \ chmod +x bin/console; sync; \ + bin/console assets:install --no-interaction; \ bin/console sylius:install:assets; \ bin/console sylius:theme:assets:install public @@ -100,6 +109,12 @@ VOLUME /srv/sylius/var VOLUME /srv/sylius/public/media +COPY docker/php/docker-healthcheck.sh /usr/local/bin/docker-healthcheck +RUN chmod +x /usr/local/bin/docker-healthcheck + +HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD ["docker-healthcheck"] + +COPY docker/php/sylius.conf /usr/local/etc/php-fpm.d/zzz-sylius.conf COPY docker/php/docker-entrypoint.sh /usr/local/bin/docker-entrypoint RUN chmod +x /usr/local/bin/docker-entrypoint diff --git a/README.md b/README.md index 2d97995530..d4a8196857 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,54 @@ $ php bin/console server:start $ open http://localhost:8000/ ``` +### For Docker installation + +Running the local environment with containers: + +```bash +$ docker-compose up -d +``` + +> You may check if php-fpm is ready executing the command: +> `docker-composer ps`. When it is ready, the State will be +> **Up (healthy)** + +Before open the sylius webpage, you should install and configure your +Shop. + +``` +$ docker-compose run php php bin/console sylius:install +``` + +> follow the installation instructions to setup the application +> database. Also you may add sample data. + +Write the command on terminal or just click on [localhost](http://localhost) +to open the Sylius Shop +``` +$ open http://localhost/ +``` + +or [localhost/admin](http://localhost/admin) to open the Sylius Backoffice +``` +$ open http://localhost/admin +``` + +If the pages not load the assets, just run the below commands: + +```bash +$ docker-compose run nodejs yarn install +$ docker-compose run nodejs yarn build +``` + +If you want to see any php information or run any command from +`bin/console`, you can run one of below commands: +```bash +$ docker-compose run php php -i +$ docker-compose run php php-fpm -tt +$ docker-compose run php php bin/console +``` + Troubleshooting --------------- diff --git a/docker-compose.yml b/docker-compose.yml index 980c582384..f02787390b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,21 +5,16 @@ services: build: context: . target: sylius_php - # Quay does not work, should be replaced in future with f.e. ghcr.io - # cache_from: - # - quay.io/sylius/php:latest - # - quay.io/sylius/nodejs:latest - # - quay.io/sylius/nginx:latest image: php:latest + healthcheck: + interval: 10s + timeout: 3s + retries: 3 + start_period: 30s depends_on: - mysql - environment: - - APP_ENV=dev - - APP_DEBUG=1 - - APP_SECRET=EDITME - - DATABASE_URL=mysql://sylius:nopassword@mysql/sylius - - MAILER_URL=smtp://mailhog:1025 - - PHP_DATE_TIMEZONE=${PHP_DATE_TIMEZONE:-UTC} + env_file: + - .env volumes: - .:/srv/sylius:rw,cached # if you develop on Linux, you may use a bind-mounted host directory instead @@ -28,13 +23,15 @@ services: # if you develop on Linux, you may use a bind-mounted host directory instead # - ./public/media:/srv/sylius/public/media:rw - public-media:/srv/sylius/public/media:rw + - sylius-vendor:/srv/sylius/vendor + - sylius-node_modules:/srv/sylius/node_modules mysql: image: percona:5.7 environment: - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-nopassword} - - MYSQL_DATABASE=sylius - - MYSQL_USER=sylius + - MYSQL_DATABASE=sylius_${APP_ENV} + - MYSQL_USER=${MYSQL_USER:-sylius} - MYSQL_PASSWORD=${MYSQL_PASSWORD:-nopassword} volumes: - mysql-data:/var/lib/mysql:rw @@ -47,11 +44,6 @@ services: build: context: . target: sylius_node - # Quay does not work, should be replaced in future with f.e. ghcr.io - # cache_from: - # - quay.io/sylius/php:latest - # - quay.io/sylius/nodejs:latest - # - quay.io/sylius/nginx:latest image: node:latest depends_on: - php @@ -62,6 +54,8 @@ services: volumes: - .:/srv/sylius:rw,cached - ./public:/srv/sylius/public:rw,delegated + - sylius-vendor:/srv/sylius/vendor + - sylius-node_modules:/srv/sylius/node_modules ports: - "35729:35729" @@ -70,11 +64,6 @@ services: context: . target: sylius_nginx image: nginx:latest - # Quay does not work, should be replaced in future with f.e. ghcr.io - # cache_from: - # - quay.io/sylius/php:latest - # - quay.io/sylius/nodejs:latest - # - quay.io/sylius/nginx:latest depends_on: - php - node # to ensure correct build order @@ -99,3 +88,5 @@ services: volumes: mysql-data: public-media: + sylius-vendor: + sylius-node_modules: diff --git a/docker/php/docker-entrypoint.sh b/docker/php/docker-entrypoint.sh index 5fa0e75316..7134c82f9e 100755 --- a/docker/php/docker-entrypoint.sh +++ b/docker/php/docker-entrypoint.sh @@ -7,20 +7,14 @@ if [ "${1#-}" != "$1" ]; then fi if [ "$1" = 'php-fpm' ] || [ "$1" = 'bin/console' ]; then - mkdir -p var/cache var/log public/media - setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var public/media - setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var public/media + mkdir -p var/cache var/log public/media + setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var public/media + setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var public/media - if [ "$APP_ENV" != 'prod' ]; then - composer install --prefer-dist --no-progress --no-suggest --no-interaction - bin/console assets:install --no-interaction - bin/console sylius:theme:assets:install public --no-interaction - fi - - until bin/console doctrine:query:sql "select 1" >/dev/null 2>&1; do - (>&2 echo "Waiting for MySQL to be ready...") - sleep 1 - done + until bin/console doctrine:query:sql "select 1" >/dev/null 2>&1; do + (>&2 echo "Waiting for MySQL to be ready...") + sleep 1 + done bin/console doctrine:migrations:migrate --no-interaction fi diff --git a/docker/php/docker-healthcheck.sh b/docker/php/docker-healthcheck.sh new file mode 100644 index 0000000000..f121eda8e9 --- /dev/null +++ b/docker/php/docker-healthcheck.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +export SCRIPT_NAME=/ping +export SCRIPT_FILENAME=/ping +export REQUEST_METHOD=GET + +if cgi-fcgi -bind -connect 127.0.0.1:9000; then + exit 0 +fi + +exit 1 diff --git a/docker/php/php-cli.ini b/docker/php/php-cli.ini index ef77c7330a..bf5735e6de 100644 --- a/docker/php/php-cli.ini +++ b/docker/php/php-cli.ini @@ -1,15 +1,19 @@ apc.enable_cli = 1 date.timezone = ${PHP_DATE_TIMEZONE} -opcache.enable_cli = 1 session.auto_start = Off short_open_tag = Off # http://symfony.com/doc/current/performance.html +opcache.enable=1 +opcache.enable_cli = 1 +opcache.fast_shutdown=1 opcache.interned_strings_buffer = 16 -opcache.max_accelerated_files = 20000 +opcache.max_accelerated_files = 524521 opcache.memory_consumption = 256 -realpath_cache_size = 4096K -realpath_cache_ttl = 600 +opcache.revalidate_freq=0 +opcache.validate_timestamps=0 +opcache.enable_file_override=0 +opcache.error_log=/proc/self/fd/2 memory_limit = 2G post_max_size = 6M diff --git a/docker/php/php.ini b/docker/php/php.ini index dd08e3bda0..d4e07025a6 100644 --- a/docker/php/php.ini +++ b/docker/php/php.ini @@ -1,13 +1,20 @@ apc.enable_cli = 1 date.timezone = ${PHP_DATE_TIMEZONE} -opcache.enable_cli = 1 session.auto_start = Off short_open_tag = Off # http://symfony.com/doc/current/performance.html +opcache.enable=1 +opcache.enable_cli = 1 +opcache.enable_file_override=0 +opcache.error_log=/proc/self/fd/2 +opcache.fast_shutdown=1 opcache.interned_strings_buffer = 16 -opcache.max_accelerated_files = 20000 +opcache.max_accelerated_files = 524521 opcache.memory_consumption = 256 +opcache.revalidate_freq=0 +opcache.validate_timestamps=0 + realpath_cache_size = 4096K realpath_cache_ttl = 600 diff --git a/docker/php/sylius.conf b/docker/php/sylius.conf new file mode 100644 index 0000000000..dc8007f734 --- /dev/null +++ b/docker/php/sylius.conf @@ -0,0 +1,28 @@ +[global] +error_log = /proc/self/fd/2 +log_buffering = yes +log_level = notice + +[www] +user = www-data +group = www-data +listen = 9000 +; check how to tuning you php-fpm +; https://tideways.com/profiler/blog/an-introduction-to-php-fpm-tuning +; +; | Setting | Value | +; | max_children | (Total RAM – Memory used for Linux, DB, etc.) / process size | +; | start_servers | Number of CPU cores x 4 | +; | min_spare_servers | Number of CPU cores x 2 | +; | max_spare_servers | Same as start_servers | + +pm = dynamic +pm.max_children = 16 +pm.start_servers = 16 +pm.min_spare_servers = 8 +pm.max_spare_servers = 16 +pm.max_requests = 200 +pm.status_path = /status + +ping.path = /ping +ping.response = pong From f7df4a03f48dcaad64ef0bec0c89fb0652823346 Mon Sep 17 00:00:00 2001 From: Antonio Spinelli Date: Thu, 3 Jun 2021 15:18:45 -0300 Subject: [PATCH 2/2] Isolate all containers configuration --- .env | 32 +++- Dockerfile | 6 +- README.md | 20 +-- docker-compose.yml | 163 +++++++++--------- docker/assets/Dockerfile | 40 +++++ docker/assets/container-entrypoint.sh | 18 ++ docker/docker-compose.deploy.yml | 30 ++++ docker/docker-compose.prod.yml | 27 +++ docker/docker-compose.setup.yml | 12 ++ docker/nginx/Dockerfile | 10 ++ docker/nginx/conf.d/default.conf | 12 +- docker/node/docker-entrypoint.sh | 18 -- docker/sylius/Dockerfile | 138 +++++++++++++++ docker/sylius/conf.d/custom.ini.tmp | 6 + docker/sylius/conf.d/date.ini.tmp | 1 + .../php.ini => sylius/conf.d/opcache.ini.tmp} | 15 +- .../container-entrypoint.sh} | 11 +- .../container-healthcheck.sh} | 0 .../php-cli.ini => sylius/php-cli.ini.tmp} | 0 .../php-fpm.d/zzz-sylius.conf.tmp} | 19 +- 20 files changed, 427 insertions(+), 151 deletions(-) create mode 100644 docker/assets/Dockerfile create mode 100755 docker/assets/container-entrypoint.sh create mode 100644 docker/docker-compose.deploy.yml create mode 100644 docker/docker-compose.prod.yml create mode 100644 docker/docker-compose.setup.yml create mode 100644 docker/nginx/Dockerfile delete mode 100755 docker/node/docker-entrypoint.sh create mode 100644 docker/sylius/Dockerfile create mode 100644 docker/sylius/conf.d/custom.ini.tmp create mode 100644 docker/sylius/conf.d/date.ini.tmp rename docker/{php/php.ini => sylius/conf.d/opcache.ini.tmp} (55%) rename docker/{php/docker-entrypoint.sh => sylius/container-entrypoint.sh} (51%) rename docker/{php/docker-healthcheck.sh => sylius/container-healthcheck.sh} (100%) rename docker/{php/php-cli.ini => sylius/php-cli.ini.tmp} (100%) rename docker/{php/sylius.conf => sylius/php-fpm.d/zzz-sylius.conf.tmp} (60%) diff --git a/.env b/.env index 1eaf2d1f14..6773844eb3 100644 --- a/.env +++ b/.env @@ -1,12 +1,10 @@ # This file is a "template" of which env vars needs to be defined in your configuration or in an .env file # Set variables here that may be different on each deployment target of the app, e.g. development, staging, production. # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration - ###> symfony/framework-bundle ### APP_ENV=dev APP_DEBUG=1 APP_SECRET=EDITME -PHP_DATE_TIMEZONE=UTC ###< symfony/framework-bundle ### ###> doctrine/doctrine-bundle ### @@ -35,3 +33,33 @@ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem JWT_PASSPHRASE=e7c5fca1060bdf6ad23c33e4c236081f ###< lexik/jwt-authentication-bundle ### + + +###> php ### +PHP_VERSION=7.4 +PHP_DATE_TIMEZONE=UTC +PHP_POST_MAX_SIZE=6M +PHP_UPLOAD_MAX_FILESIZE=5M +PHP_OPCACHE_ENABLED=1 +PHP_OPCACHE_ENABLED_CLI=1 +###< php ### + +###> php/fpm ### +PHP_FPM_LOG_LEVEL=notice +PHP_FPM_ERROR_LOG=/srv/sylius/var/log/php-fpm-error.log +PHP_FPM_WWW_LISTEN=9000 +# check how to tuning you php-fpm +# https://tideways.com/profiler/blog/an-introduction-to-php-fpm-tuning +# +# | Setting | Value | +# | max_children | (Total RAM – Memory used for Linux, DB, etc.) / process size | +# | start_servers | Number of CPU cores x 4 | +# | min_spare_servers | Number of CPU cores x 2 | +# | max_spare_servers | Same as start_servers | +PHP_FPM_PM=dynamic +PHP_FPM_WWW_PM_MAX_CHILDREN=16 +PHP_FPM_WWW_PM_START_SERVERS=16 +PHP_FPM_WWW_PM_MIN_SPARE_SERVERS=8 +PHP_FPM_WWW_PM_MAX_SPARE_SERVERS=16 +PHP_FPM_WWW_PM_MAX_REQUESTS=200 +###< php/fpm ### diff --git a/Dockerfile b/Dockerfile index 4922ae8bef..6b05285f17 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # the different stages of this Dockerfile are meant to be built into separate images # https://docs.docker.com/compose/compose-file/#target -ARG PHP_VERSION=7.4 +ARG PHP_VERSION=${PHP_VERSION:-7.4} ARG NODE_VERSION=10 ARG NGINX_VERSION=1.17 @@ -64,7 +64,7 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer COPY docker/php/php.ini /usr/local/etc/php/php.tmp COPY docker/php/php-cli.ini /usr/local/etc/php/php-cli.tmp -ARG PHP_DATE_TIMEZONE=UTC +ARG PHP_DATE_TIMEZONE=${PHP_DATE_TIMEZONE:-UTC} RUN sh -c "envsubst < /usr/local/etc/php/php.tmp > /usr/local/etc/php/php.ini" RUN sh -c "envsubst < /usr/local/etc/php/php-cli.tmp > /usr/local/etc/php/php-cli.ini" @@ -79,7 +79,7 @@ ENV PATH="${PATH}:/root/.composer/vendor/bin" WORKDIR /srv/sylius # build for production -ARG APP_ENV=prod +ARG APP_ENV=${APP_ENV} # prevent the reinstallation of vendors at every changes in the source code COPY composer.* symfony.lock ./ diff --git a/README.md b/README.md index d4a8196857..f1890d831e 100644 --- a/README.md +++ b/README.md @@ -43,23 +43,19 @@ $ open http://localhost:8000/ Running the local environment with containers: ```bash +$ docker-compose pull +$ docker-compose build +$ docker-compose -f docker-compose.yml -f docker/docker-compose.setup.yml run setup $ docker-compose up -d ``` +> follow the installation instructions to setup the application +> database. Also you may add sample data. + > You may check if php-fpm is ready executing the command: > `docker-composer ps`. When it is ready, the State will be > **Up (healthy)** -Before open the sylius webpage, you should install and configure your -Shop. - -``` -$ docker-compose run php php bin/console sylius:install -``` - -> follow the installation instructions to setup the application -> database. Also you may add sample data. - Write the command on terminal or just click on [localhost](http://localhost) to open the Sylius Shop ``` @@ -74,8 +70,8 @@ $ open http://localhost/admin If the pages not load the assets, just run the below commands: ```bash -$ docker-compose run nodejs yarn install -$ docker-compose run nodejs yarn build +$ docker-compose run assets yarn install +$ docker-compose run assets yarn build ``` If you want to see any php information or run any command from diff --git a/docker-compose.yml b/docker-compose.yml index f02787390b..5607d5ad2e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,92 +1,89 @@ version: '3.4' services: - php: - build: - context: . - target: sylius_php - image: php:latest - healthcheck: - interval: 10s - timeout: 3s - retries: 3 - start_period: 30s - depends_on: - - mysql - env_file: - - .env - volumes: - - .:/srv/sylius:rw,cached - # if you develop on Linux, you may use a bind-mounted host directory instead - # - ./var:/srv/sylius/var:rw - - ./public:/srv/sylius/public:rw,delegated - # if you develop on Linux, you may use a bind-mounted host directory instead - # - ./public/media:/srv/sylius/public/media:rw - - public-media:/srv/sylius/public/media:rw - - sylius-vendor:/srv/sylius/vendor - - sylius-node_modules:/srv/sylius/node_modules + sylius: + build: + context: . + target: sylius_server + dockerfile: docker/sylius/Dockerfile + image: sylius/server:latest + healthcheck: + interval: 10s + timeout: 3s + retries: 3 + start_period: 30s + depends_on: + - mysql + env_file: + - .env + volumes: + - .:/srv/sylius:rw,cached + - ./public:/srv/sylius/public:rw,delegated + - public-media:/srv/sylius/public/media:rw + - sylius-vendor:/srv/sylius/vendor + - sylius-node_modules:/srv/sylius/node_modules - mysql: - image: percona:5.7 - environment: - - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-nopassword} - - MYSQL_DATABASE=sylius_${APP_ENV} - - MYSQL_USER=${MYSQL_USER:-sylius} - - MYSQL_PASSWORD=${MYSQL_PASSWORD:-nopassword} - volumes: - - mysql-data:/var/lib/mysql:rw - # you may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! - # - ./docker/mysql/data:/var/lib/mysql:rw,delegated - ports: - - "3306:3306" + assets: + build: + context: . + dockerfile: docker/assets/Dockerfile + target: sylius_assets + args: + - APP_ENV=${APP_ENV} + image: sylius/assets:latest + depends_on: + - sylius + env_file: + - .env + volumes: + - .:/srv/sylius:rw,cached + - ./public:/srv/sylius/public:rw,delegated + - public-media:/srv/sylius/public/media:rw + - sylius-node_modules:/srv/sylius/node_modules + ports: + - "35729:35729" - node: - build: - context: . - target: sylius_node - image: node:latest - depends_on: - - php - environment: - - GULP_ENV=dev - - PHP_HOST=php - - PHP_PORT=9000 - volumes: - - .:/srv/sylius:rw,cached - - ./public:/srv/sylius/public:rw,delegated - - sylius-vendor:/srv/sylius/vendor - - sylius-node_modules:/srv/sylius/node_modules - ports: - - "35729:35729" + webserver: + build: + context: . + target: sylius_nginx + dockerfile: docker/nginx/Dockerfile + image: nginx:latest + env_file: + - .env + depends_on: + - sylius + - assets + volumes: + - ./public:/srv/sylius/public:ro + - public-media:/srv/sylius/public/media:ro,delegated + ports: + - "80:80" - nginx: - build: - context: . - target: sylius_nginx - image: nginx:latest - depends_on: - - php - - node # to ensure correct build order - volumes: - - ./public:/srv/sylius/public:ro - # if you develop on Linux, you may use a bind-mounted host directory instead - # - ./public/media:/srv/sylius/public/media:ro - - public-media:/srv/sylius/public/media:ro,nocopy - ports: - - "80:80" + mysql: + image: percona:5.7 + environment: + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-nopassword} + - MYSQL_DATABASE=sylius_${APP_ENV} + - MYSQL_USER=${MYSQL_USER:-sylius} + - MYSQL_PASSWORD=${MYSQL_PASSWORD:-nopassword} + volumes: + - mysql-data:/var/lib/mysql:rw + ports: + - "3306:3306" - mailhog: - # do not use in production! - image: mailhog/mailhog:latest - environment: - - MH_STORAGE=maildir - # volumes: - # - ./docker/mailhog/maildir:/maildir:rw,delegated - ports: - - "8025:8025" + mailhog: + # do not use in production! + image: mailhog/mailhog:latest + environment: + - MH_STORAGE=maildir + # volumes: + # - ./docker/mailhog/maildir:/maildir:rw,delegated + ports: + - "8025:8025" volumes: - mysql-data: - public-media: - sylius-vendor: - sylius-node_modules: + mysql-data: + public-media: + sylius-vendor: + sylius-node_modules: diff --git a/docker/assets/Dockerfile b/docker/assets/Dockerfile new file mode 100644 index 0000000000..6f9501fae5 --- /dev/null +++ b/docker/assets/Dockerfile @@ -0,0 +1,40 @@ +ARG NODE_VERSION=10 + +FROM node:${NODE_VERSION}-alpine AS sylius_node +RUN set -eux; \ + apk add --no-cache --virtual .build-deps \ + g++ \ + gcc \ + git \ + make \ + python \ + ; + +FROM sylius_node AS sylius_assets + +ENV APP_ENV=${APP_ENV} +ENV PHP_FPM_LISTEN=${PHP_FPM_LISTEN} + +WORKDIR /srv/sylius + +# prevent the reinstallation of vendors at every changes in the source code +COPY package.json yarn.lock ./ +RUN set -eux; \ + yarn install; \ + yarn cache clean + +COPY --from=sylius/server:latest /srv/sylius/vendor/sylius/sylius/src/Sylius/Bundle/UiBundle/Resources/private vendor/sylius/sylius/src/Sylius/Bundle/UiBundle/Resources/private/ +COPY --from=sylius/server:latest /srv/sylius/vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/private vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/private/ +COPY --from=sylius/server:latest /srv/sylius/vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/private vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/private/ + +COPY --from=sylius/server:latest /srv/sylius/vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/gulpfile.babel.js vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/gulpfile.babel.js +COPY --from=sylius/server:latest /srv/sylius/vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/gulpfile.babel.js vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/gulpfile.babel.js + +COPY gulpfile.babel.js .babelrc ./ +RUN GULP_ENV=${APP_ENV} yarn build + +COPY docker/assets/container-entrypoint.sh /usr/local/bin/container-entrypoint +RUN chmod +x /usr/local/bin/container-entrypoint + +ENTRYPOINT ["container-entrypoint"] +CMD ["yarn", "watch"] diff --git a/docker/assets/container-entrypoint.sh b/docker/assets/container-entrypoint.sh new file mode 100755 index 0000000000..c3bf8f339f --- /dev/null +++ b/docker/assets/container-entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/sh +set -e + +# first arg is `-f` or `--some-option` +if [ "${1#-}" != "$1" ]; then + set -- node "$@" +fi + +if [ "$1" = 'node' ] || [ "$1" = 'yarn' ]; then + yarn install + + >&2 echo "Waiting for Sylius Server (sylius:${PHP_FPM_WWW_LISTEN}) to be ready..." + until nc -z "sylius" "${PHP_FPM_WWW_LISTEN}"; do + sleep 5 + done +fi + +exec "$@" diff --git a/docker/docker-compose.deploy.yml b/docker/docker-compose.deploy.yml new file mode 100644 index 0000000000..95c8fe7f4c --- /dev/null +++ b/docker/docker-compose.deploy.yml @@ -0,0 +1,30 @@ +version: '3.4' + +services: + sylius: + deploy: + resources: + limits: + memory: 512M + + assets: + deploy: + resources: + limits: + memory: 256M + + mysql: + deploy: + resources: + limits: + memory: 512M + + mailhog: + deploy: + resources: + limits: + memory: 512M + +volumes: + mysql-data: + public-media: diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml new file mode 100644 index 0000000000..8784273cc2 --- /dev/null +++ b/docker/docker-compose.prod.yml @@ -0,0 +1,27 @@ +version: '3.4' + +services: + sylius: + env_file: + - .env.prod + + assets: + env_file: + - .env.prod + + webserver: + # in production, we may want to use a static website hosting service + env_file: + - .env.prod + volumes: + # use a bind-mounted host directory, as we want to keep the media + - ./public/media:/srv/sylius/public/media:ro + + mysql: + env_file: + - .env.prod + volumes: + - mysql-data-prod:/var/lib/mysql:rw + +volumes: + mysql-data-prod: diff --git a/docker/docker-compose.setup.yml b/docker/docker-compose.setup.yml new file mode 100644 index 0000000000..b445b76cfa --- /dev/null +++ b/docker/docker-compose.setup.yml @@ -0,0 +1,12 @@ +version: '3.4' + +services: + setup: + image: sylius/server:latest + env_file: + - .env + depends_on: + - sylius + command: "php ./bin/console sylius:install" + volumes: + - public-media:/srv/sylius/public/media:rw diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile new file mode 100644 index 0000000000..75e8cbb31d --- /dev/null +++ b/docker/nginx/Dockerfile @@ -0,0 +1,10 @@ +ARG NGINX_VERSION=1.17 + +FROM nginx:${NGINX_VERSION}-alpine AS sylius_nginx + +COPY docker/nginx/conf.d/default.conf /etc/nginx/conf.d/ + +WORKDIR /srv/sylius + +COPY --from=sylius/server:latest /srv/sylius/public public/ +COPY --from=sylius/assets:latest /srv/sylius/public public/ diff --git a/docker/nginx/conf.d/default.conf b/docker/nginx/conf.d/default.conf index 4f772ad732..53db3c1f0f 100644 --- a/docker/nginx/conf.d/default.conf +++ b/docker/nginx/conf.d/default.conf @@ -2,20 +2,16 @@ server { root /srv/sylius/public; listen *:80; + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + location / { # try to serve file directly, fallback to index.php try_files $uri /index.php$is_args$args; } location ~ ^/index\.php(/|$) { - resolver 127.0.0.11 valid=10s ipv6=off; - set $backendfpm "php:9000"; - fastcgi_pass $backendfpm; - # Comment the next line and uncomment the next to enable dynamic resolution (incompatible with Kubernetes); - #resolver 127.0.0.11; - #set $upstream_host php; - #fastcgi_pass $upstream_host:9000; - + fastcgi_pass "sylius:9000"; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; # When you are using symlinks to link the document root to the diff --git a/docker/node/docker-entrypoint.sh b/docker/node/docker-entrypoint.sh deleted file mode 100755 index ecd73af806..0000000000 --- a/docker/node/docker-entrypoint.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -set -e - -# first arg is `-f` or `--some-option` -if [ "${1#-}" != "$1" ]; then - set -- node "$@" -fi - -if [ "$1" = 'node' ] || [ "$1" = 'yarn' ]; then - yarn install - - >&2 echo "Waiting for PHP to be ready..." - until nc -z "$PHP_HOST" "$PHP_PORT"; do - sleep 1 - done -fi - -exec "$@" diff --git a/docker/sylius/Dockerfile b/docker/sylius/Dockerfile new file mode 100644 index 0000000000..69dfdab97e --- /dev/null +++ b/docker/sylius/Dockerfile @@ -0,0 +1,138 @@ +# the different stages of this Dockerfile are meant to be built into separate images +# https://docs.docker.com/compose/compose-file/#target + +# the different stages of this Dockerfile are meant to be built into separate images +# https://docs.docker.com/compose/compose-file/#target + +ARG PHP_VERSION=${PHP_VERSION:-7.4} + +FROM php:${PHP_VERSION}-fpm-alpine AS phpfpm + +# persistent / runtime deps +RUN apk add --no-cache \ + acl \ + fcgi \ + file \ + gettext \ + git \ + mariadb-client \ + ; + +ARG PHP_EXT_APCU_VERSION=5.1.18 +RUN set -eux; \ + apk add --no-cache --virtual .build-deps \ + $PHPIZE_DEPS \ + coreutils \ + freetype-dev \ + icu-dev \ + libjpeg-turbo-dev \ + libpng-dev \ + libtool \ + libwebp-dev \ + libzip-dev \ + mariadb-dev \ + zlib-dev \ + ; \ + \ + docker-php-ext-configure gd --with-jpeg=/usr/include/ --with-webp=/usr/include --with-freetype=/usr/include/; \ + docker-php-ext-configure zip; \ + docker-php-ext-install -j$(nproc) \ + exif \ + gd \ + intl \ + pdo_mysql \ + zip \ + ; \ + pecl install \ + apcu-${PHP_EXT_APCU_VERSION} \ + ; \ + pecl clear-cache; \ + docker-php-ext-enable \ + apcu \ + opcache \ + ; \ + \ + runDeps="$( \ + scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ + | tr ',' '\n' \ + | sort -u \ + | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ + )"; \ + apk add --no-cache --virtual .sylius-phpexts-rundeps $runDeps; \ + \ + apk del .build-deps +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer +COPY docker/sylius/conf.d/* /usr/local/etc/php/conf.d +COPY docker/sylius/php-cli.ini.tmp /usr/local/etc/php/php-cli.ini.tmp +COPY docker/sylius/php-fpm.d/* /usr/local/etc/php-fpm.d + +ENV PHP_DATE_TIMEZONE=${PHP_DATE_TIMEZONE} \ + PHP_POST_MAX_SIZE=${PHP_POST_MAX_SIZE} \ + PHP_UPLOAD_MAX_FILESIZE=${PHP_UPLOAD_MAX_FILESIZE} \ + PHP_UPLOAD_MAX_FILESIZE=${PHP_UPLOAD_MAX_FILESIZE} \ + PHP_OPCACHE_ENABLED=${PHP_OPCACHE_ENABLED} \ + PHP_OPCACHE_ENABLED_CLI=${PHP_OPCACHE_ENABLED_CLI} \ + PHP_FPM_LOG_LEVEL=${PHP_FPM_LOG_LEVEL} \ + PHP_FPM_ERROR_LOG=${PHP_FPM_ERROR_LOG} \ + PHP_FPM_WWW_LISTEN=${PHP_FPM_WWW_LISTEN} \ + PHP_FPM_PM=${PHP_FPM_PM} \ + PHP_FPM_WWW_PM_MAX_CHILDREN=${PHP_FPM_WWW_PM_MAX_CHILDREN} \ + PHP_FPM_WWW_PM_START_SERVERS=${PHP_FPM_WWW_PM_START_SERVERS} \ + PHP_FPM_WWW_PM_MIN_SPARE_SERVERS=${PHP_FPM_WWW_PM_MIN_SPARE_SERVERS} \ + PHP_FPM_WWW_PM_MAX_SPARE_SERVERS=${PHP_FPM_WWW_PM_MAX_SPARE_SERVERS} \ + PHP_FPM_WWW_PM_MAX_REQUESTS=${PHP_FPM_WWW_PM_MAX_REQUESTS} + +# evaluate ENVVARS into the file +RUN sh -c "envsubst < /usr/local/etc/php-fpm.d/zzz-sylius.conf.tmp > /usr/local/etc/php-fpm.d/zzz-sylius.conf" +RUN for file in $(find /usr/local/etc/php/conf.d -regex '.*\.tmp'); do sh -c "envsubst < ${file} > ${file%.*}"; done +RUN sh -c "envsubst < /usr/local/etc/php/php-cli.ini.tmp > /usr/local/etc/php/php-cli.ini" + +# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser +ENV COMPOSER_ALLOW_SUPERUSER=1 +# install Symfony Flex globally to speed up download of Composer packages (parallelized prefetching) +RUN composer global require "symfony/flex" --prefer-dist --no-progress --classmap-authoritative; +ENV PATH="${PATH}:/root/.composer/vendor/bin" + +FROM phpfpm AS sylius_server + +WORKDIR /srv/sylius + +# build for production +ARG APP_ENV=${APP_ENV} + +# prevent the reinstallation of vendors at every changes in the source code +COPY composer.* symfony.lock ./ +RUN composer install --prefer-dist --no-autoloader --no-scripts --no-progress +RUN composer clear-cache + +# copy only specifically what we need +COPY .env .env.prod .env.test .env.test_cached ./ +COPY bin bin/ +COPY config config/ +COPY public public/ +COPY src src/ +COPY templates templates/ +COPY translations translations/ + +RUN set -eux; \ + mkdir -p var/cache var/log; \ + composer dump-autoload --classmap-authoritative; \ + APP_SECRET='' composer run-script post-install-cmd; \ + chmod +x bin/console; sync; \ + bin/console assets:install --no-interaction; \ + bin/console sylius:install:assets; \ + bin/console sylius:theme:assets:install public + +VOLUME /srv/sylius/var + +VOLUME /srv/sylius/public/media + +COPY docker/sylius/container-healthcheck.sh /usr/local/bin/container-healthcheck +RUN chmod +x /usr/local/bin/container-healthcheck +HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD ["container-healthcheck"] + +COPY docker/sylius/container-entrypoint.sh /usr/local/bin/container-entrypoint +RUN chmod +x /usr/local/bin/container-entrypoint +ENTRYPOINT ["container-entrypoint"] + +CMD ["php-fpm"] diff --git a/docker/sylius/conf.d/custom.ini.tmp b/docker/sylius/conf.d/custom.ini.tmp new file mode 100644 index 0000000000..4fde668df4 --- /dev/null +++ b/docker/sylius/conf.d/custom.ini.tmp @@ -0,0 +1,6 @@ +realpath_cache_size=4096K +realpath_cache_ttl=600 +post_max_size=${PHP_POST_MAX_SIZE} +upload_max_filesize=${PHP_UPLOAD_MAX_FILESIZE} +session.auto_start=Off +short_open_tag=Off diff --git a/docker/sylius/conf.d/date.ini.tmp b/docker/sylius/conf.d/date.ini.tmp new file mode 100644 index 0000000000..37ddef3a10 --- /dev/null +++ b/docker/sylius/conf.d/date.ini.tmp @@ -0,0 +1 @@ +date.timezone=${PHP_DATE_TIMEZONE} diff --git a/docker/php/php.ini b/docker/sylius/conf.d/opcache.ini.tmp similarity index 55% rename from docker/php/php.ini rename to docker/sylius/conf.d/opcache.ini.tmp index d4e07025a6..96f30319e2 100644 --- a/docker/php/php.ini +++ b/docker/sylius/conf.d/opcache.ini.tmp @@ -1,11 +1,6 @@ -apc.enable_cli = 1 -date.timezone = ${PHP_DATE_TIMEZONE} -session.auto_start = Off -short_open_tag = Off - # http://symfony.com/doc/current/performance.html -opcache.enable=1 -opcache.enable_cli = 1 +opcache.enable=${PHP_OPCACHE_ENABLED} +opcache.enable_cli=${PHP_OPCACHE_ENABLED_CLI} opcache.enable_file_override=0 opcache.error_log=/proc/self/fd/2 opcache.fast_shutdown=1 @@ -14,9 +9,3 @@ opcache.max_accelerated_files = 524521 opcache.memory_consumption = 256 opcache.revalidate_freq=0 opcache.validate_timestamps=0 - -realpath_cache_size = 4096K -realpath_cache_ttl = 600 - -post_max_size = 6M -upload_max_filesize = 5M diff --git a/docker/php/docker-entrypoint.sh b/docker/sylius/container-entrypoint.sh similarity index 51% rename from docker/php/docker-entrypoint.sh rename to docker/sylius/container-entrypoint.sh index 7134c82f9e..bf03ca4ac7 100755 --- a/docker/php/docker-entrypoint.sh +++ b/docker/sylius/container-entrypoint.sh @@ -1,6 +1,13 @@ #!/bin/sh set -e +sh -c "envsubst < /usr/local/etc/php-fpm.d/zzz-sylius.conf.tmp > /usr/local/etc/php-fpm.d/zzz-sylius.conf"; +sh -c "envsubst < /usr/local/etc/php/php-cli.ini.tmp > /usr/local/etc/php/php-cli.ini"; + +for file in $(find /usr/local/etc/php/conf.d -regex '.*\.tmp'); do + sh -c "envsubst < ${file} > ${file%.*}"; +done + # first arg is `-f` or `--some-option` if [ "${1#-}" != "$1" ]; then set -- php-fpm "$@" @@ -8,8 +15,8 @@ fi if [ "$1" = 'php-fpm' ] || [ "$1" = 'bin/console' ]; then mkdir -p var/cache var/log public/media - setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var public/media - setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var public/media + setfacl -R -m u:www-data:rwx -m u:"$(whoami)":rwx var public/media + setfacl -dR -m u:www-data:rwx -m u:"$(whoami)":rwx var public/media until bin/console doctrine:query:sql "select 1" >/dev/null 2>&1; do (>&2 echo "Waiting for MySQL to be ready...") diff --git a/docker/php/docker-healthcheck.sh b/docker/sylius/container-healthcheck.sh similarity index 100% rename from docker/php/docker-healthcheck.sh rename to docker/sylius/container-healthcheck.sh diff --git a/docker/php/php-cli.ini b/docker/sylius/php-cli.ini.tmp similarity index 100% rename from docker/php/php-cli.ini rename to docker/sylius/php-cli.ini.tmp diff --git a/docker/php/sylius.conf b/docker/sylius/php-fpm.d/zzz-sylius.conf.tmp similarity index 60% rename from docker/php/sylius.conf rename to docker/sylius/php-fpm.d/zzz-sylius.conf.tmp index dc8007f734..59d3936444 100644 --- a/docker/php/sylius.conf +++ b/docker/sylius/php-fpm.d/zzz-sylius.conf.tmp @@ -1,12 +1,12 @@ [global] -error_log = /proc/self/fd/2 +error_log = ${PHP_FPM_ERROR_LOG} ;/proc/self/fd/2 log_buffering = yes -log_level = notice +log_level = ${PHP_FPM_LOG_LEVEL} ; notice [www] user = www-data group = www-data -listen = 9000 +listen = ${PHP_FPM_WWW_LISTEN} ;:-9000 ; check how to tuning you php-fpm ; https://tideways.com/profiler/blog/an-introduction-to-php-fpm-tuning ; @@ -15,13 +15,12 @@ listen = 9000 ; | start_servers | Number of CPU cores x 4 | ; | min_spare_servers | Number of CPU cores x 2 | ; | max_spare_servers | Same as start_servers | - -pm = dynamic -pm.max_children = 16 -pm.start_servers = 16 -pm.min_spare_servers = 8 -pm.max_spare_servers = 16 -pm.max_requests = 200 +pm = ${PHP_FPM_PM} ;dynamic +pm.max_children = ${PHP_FPM_WWW_PM_MAX_CHILDREN} ; 16 +pm.start_servers = ${PHP_FPM_WWW_PM_START_SERVERS} ; 16 +pm.min_spare_servers = ${PHP_FPM_WWW_PM_MIN_SPARE_SERVERS} ; 8 +pm.max_spare_servers = ${PHP_FPM_WWW_PM_MAX_SPARE_SERVERS} ; 16 +pm.max_requests = ${PHP_FPM_WWW_PM_MAX_REQUESTS} ; 200 pm.status_path = /status ping.path = /ping