Verification: a143cc29221c9be0

Nginx php fpm for windows

Nginx php fpm for windows

Немного предыстории

Одна из проблем веб-разработки заключается в том, что всё быстро меняется. Лучшие практики CSS меняются по мере добавления в спецификацию новых свойств. (Как мы вообще обходились без CSS Grid ?) Сейчас PHP находится в версии 8, и даже инструменты, которые мы используем для выполнения скриптов PHP, со временем совершенствуются. В результате многие учебные пособия довольно быстро устаревают.

Ещё пару лет назад я отправлял всех, кого учил, к прекрасной статье Бруно Скворца » Повторное знакомство с Vagrant: правильный способ начать с PHP«. В то время это было фантастическое введение в (на тот момент) лучший способ создания локальной среды разработки.

Эта статья только за 2015 год, но пять или шесть лет — это целая вечность в постоянно меняющихся временных рамках веб-разработки. С тех пор «правильный путь» продвинулся довольно значительно.

Я быстро напомню, как всё изменилось за эти годы.

1. Установка PHP, MySQL и Apache вручную

Если вы, как и я, достаточно взрослые, чтобы заниматься разработкой веб-сайтов в 90-е годы, вы вспомните, насколько неприятным был этот опыт. В то время, если вы были в меньшинстве, кто не разрабатывал только на реальном веб-сервере (да, мы действительно это сделали, да, это была ужасная идея), вы бы вручную установили Apache, PHP и MySQL на свою машину разработки.

Для настройки среды разработки требовался значительный опыт. Вам нужно было знать, как настроить веб-сервер, как настроить PHP, и вы должны были пройти процесс ручной установки и настройки всего программного обеспечения, которое вы использовали. Для начинающих разработчиков это было трудоёмкой и сложной задачей.

2. Предварительно настроенные пакеты, такие как XAMPP.

К началу и середине 2000-х люди начали собирать всё необходимое программное обеспечение в один пакет, который устанавливал и настраивал всё необходимое программное обеспечение. Это были такие пакеты, как XAMPP и WAMP, и одним нажатием кнопки они давали вам удобную среду разработки.

Если вы будете болтаться по различным группам PHP в Facebook, вы обнаружите, что значительная часть новых разработчиков всё ещё следуют руководствам той эпохи, а большое количество существующих разработчиков никогда не уходили, поэтому XAMPP по-прежнему используется довольно широко. Если это описывает вас, пора двигаться дальше.

Использование XAMPP упростило настройку и запуск среды веб-разработки на вашем компьютере. В статье Бруно описаны проблемы этого подхода, но основная проблема возникает, когда вы хотите разместить свой сайт в Интернете. Версии PHP, MySQL и Apache (или NGINX) могут отличаться от тех, которые вы установили как часть вашего пакета XAMPP. Кроме того, между Windows и Linux есть пара незначительных, но разочаровывающих различий. Если вы разрабатываете свой сайт на машине с Windows и загружаете его на сервер Linux, часть вашего кода может вообще не работать после загрузки.

3. Виртуальные машины и бродяги

В конце 2000-х — начале 2010-х годов среди разработчиков была тенденция к переходу на виртуальные машины. Идея заключалась в том, чтобы вы могли запустить копию реальной операционной системы веб-сервера со всеми установленными на нём программами — точно такую ​​же конфигурацию и настройку, как и реальный веб-сервер, на котором вы собирались в конце концов развернуть свой веб-сайт. Таким образом, когда вы запустили сайт, не было никаких шансов, что он не заработает.

Хотя многие программисты увидели преимущества такой среды, сложность и время, необходимые для её настройки, означали, что это сделали немногие. Так было до тех пор, пока не появился Vagrant (и связанные с ним инструменты, такие как Puphpet), которые избавили его от всех хлопот.

Взгляните на статью, на которую я ссылался ранее, чтобы получить отличное описание Vagrant, виртуальных машин и преимуществ такой настройки среды разработки.

4. Docker

Всё это подводит нас к сегодняшнему дню и к причине этой статьи. Если Vagrant так хорош, зачем использовать что-то другое?

Основные преимущества виртуальной среды, созданной с помощью Vagrant:

  1. Ваш компьютер разработки не привязан к определённой среде. Вы можете разместить несколько веб-сайтов: один на Apache, один на NGINX, один на PHP 7 и один на PHP 8.
  2. Когда сайт запускается, он загружается в ту же среду, в которой он был разработан.

Легко понять, зачем это нужно разработчикам. Сделав следующий шаг к Docker, мы сохраним эти преимущества, избегая при этом некоторых недостатков сред Vagrant / Virtual Machine.

Что не так с Vagrant?

Несмотря на преимущества, среда разработки на основе Vagrant вводит свой собственный набор ограничений и проблем.

  1. Системные ресурсы. Vagrant требует запуска совершенно другой операционной системы. Вам необходимо загрузить и установить операционную систему, работающую на вашем веб-сервере, и все установленные ею пакеты. При этом используется значительный объём дискового пространства и памяти. Виртуальной машине обычно требуется как минимум 512 МБ ОЗУ. Это немного для современных компьютеров, но быстро складывается. Если вы хотите разместить один веб-сайт на PHP 7 и один на PHP 8, вам необходимо установить и настроить на вашем компьютере два разных экземпляра виртуальных машин.
  2. Вы должны убедиться, что виртуальная машина и сервер синхронизированы. Всякий раз, когда вы обновляете сервер или изменяете конфигурацию сервера, вы должны не забывать обновить локальную среду разработки с такими же изменениями.
  3. Это жёстко фиксирует вас в операционной системе и конфигурации сервера. Перенести сайт с одного сервера на другой — сложная задача. Веб-сайт — это больше, чем просто сценарии PHP, изображения и CSS, из которых он состоит. Для правильной работы веб-сайта также требуется определённая конфигурация сервера (например, установленные расширения PHP и conf/ httpd.conf).
  4. Существует очень ограниченный выбор доступных пакетов. В зависимости от того, какой дистрибутив Linux работает на вашем веб-сервере, у вас может не быть выбора, какую версию PHP вы запускать. Если вы не установите пакеты из сторонних репозиториев, вы не сможете использовать самую последнюю и лучшую версию PHP. На момент написания недавно стал доступен PHP 8. Если вы используете CentOS 8 / RHEL 8, вы застряли на PHP 7.3, пока не получите новую версию операционной системы. Если вы используете Debian, последняя доступная версия — 7.3. В других дистрибутивах будут доступны другие версии.
  5. Конфигурация сервера глобальная. В PHP есть файл настроек с именем ini. При изменении этого параметра обновлённая конфигурация применяется ко всем веб-сайтам, размещённым на сервере. То же самое касается nginx.confNGINX или httpd.confApache. Экземпляр базы данных MySQL имеет базы данных для всех сайтов, размещённых на сервере. Внесение каких-либо крупномасштабных изменений конфигурации базы данных имеет далеко идущие последствия. Обновление настройки MySQL повлияет на каждый веб-сайт, использующий этот сервер MySQL!
  6. Версии пакета являются глобальными на реальном сервере. Хотя можнозапустить несколько версий PHP на одном веб-сервере, его сложно настроить и могут возникнуть странные побочные эффекты в зависимости от того, что делает ваш скрипт (например, когда у вас есть скрипт, который вы хотите запустить в модуле systemd / cronjob и забудьте, что вы должны использовать, /bin/php72а не /bin/php).

Хотя точки 5 и 6 можно преодолеть на машине разработки, запустив разные виртуальные машины Vagrant, вам понадобится реальный веб-сервер, который отражает каждую используемую вами конфигурацию, чтобы веб-сайты работали, когда вы их загружаете.

Представляем Docker

Docker решает все перечисленные выше проблемы. Но что такое Docker и как он работает?

Начнём с вступления из Википедии:

Docker — это набор продуктов «платформа как услуга» (PaaS), которые используют виртуализацию на уровне ОС для доставки программного обеспечения в пакетах, называемых контейнерами. Контейнеры изолированы друг от друга и объединяют собственное программное обеспечение, библиотеки и файлы конфигурации; они могут общаться друг с другом через чётко определённые каналы.

Прежде чем вдаваться в технические подробности, практическая выгода для нас, как веб-разработчиков, заключается в том, что Docker позволяет нам упаковать всё, что нужно веб-сайту, весь код PHP вместе с исполняемым файлом PHP, сервер MySQL и сервер NGINX в дополнение к файлам конфигурации, используемым этими программы.

Весь код веб-сайта и точные версии программ, необходимых для запуска этого кода, упаковываются вместе, фактически как одно приложение. Затем всё это приложение можно запустить в любой операционной системе. Когда кто-то запускает упакованное приложение, PHP, MySQL, NGINX и все написанные вами файлы PHP встраиваются в само приложение. Более того, точные версии MySQL, NGINX и PHP являются частью пакета. Когда вы запускаете приложение, загружаются и устанавливаются точные версии этих инструментов, для которых оно было разработано.

«Разве это не то, что виртуальная машина уже делает?» Я слышал, вы спросите. Да, но есть большая разница между тем, как Vagrant и Docker обрабатывают установку программного обеспечения.

С Vagrant, работающим на виртуальной машине, полная операционная система с определённой версией PHP, версией MySQL и (обычно) конфигурацией сервера клонируется с реального веб-сервера. Когда сервер обновляется, виртуальная машина также должна быть обновлена.

Однако при использовании Docker версия PHP / MySQL / NGINX предоставляется в виде единого пакета, известного как образ, и сервер может запускать столько разных образов, сколько захотите.

Преимущество здесь в том, что и на веб-сервере, и на вашей машине разработки используется один и тот же образ. Вы просто загружаете своё изображение на веб-сервер, запускаете там всё приложение, и ваш веб-сайт готов к работе без необходимости какой-либо настройки веб-сервера.

Кроме того, каждое изображение полностью отделено от другого изображения на сервере. Каждое изображение (по одному на веб-сайт в этом упрощённом примере) отделено друг от друга. Каждый веб-сайт будет иметь свою собственную конфигурацию NGINX, php.iniсвои собственные установки PHP и MySQL. На каждом веб-сайте могут быть разные версии PHP. У вас даже может быть один веб-сайт, работающий на Apache, и один веб-сайт, работающий на NGINX, на одном компьютере одновременно. Даже когда вы запускаете два разных веб-сайта NGINX, у вас будут одновременно работать два разных процесса NGINX с собственными конфигурациями.

У этого есть небольшие накладные расходы на память, но предоставляемая им гибкость делает это очень полезным компромиссом:

  1. Весь веб-сайт с необходимыми версиями PHP / MySQL, всю конфигурацию и весь код можно легко перемещать. Для переноса веб-сайта на новый сервер необходимо просто скопировать одну папку. Вам не нужно вносить какие-либо изменения в конфигурацию PHP или NGINX на новом сервере. Вам даже не нужно устанавливать PHP или NGINX на самом сервере. Они будут автоматически установлены Docker при запуске приложения.
  2. Вы можете запустить точно такой же образна своей машине для разработки. Используя Vagrant, вы фактически запускаете копию конфигурации / установленных пакетов сервера на том же компьютере. С Docker на вашем ПК для разработки запускается тот же образ, что и на сервере.
  3. php.iniщипки, nginx.confизменения конфигурации или обновления PHP до последней версии, обрабатывают так же, как загрузка обновлён PHP кода на сервере. Вы обновляете приложение, и неважно, меняет ли это PHP-код или обновляетесь php.ini.
  4. Каждое изображение замкнуто в чём-то, что называется «контейнером». Скрипт PHP, запущенный в одном изображении, не может получить доступ к файлам, запущенным в другом. Думаю, open_basedirно гораздо строже. Контейнер похож на очень лёгкую виртуальную машину. Он действует как собственная операционная система, и код, работающий в контейнере, даже не знает, что он запущен внутри контейнера, не имея возможности видеть что-либо за пределами контейнера. Если один из ваших сценариев PHP небезопасен и даёт кому-то эффективный доступ к оболочке, они могут получить доступ только к файлам на сервере, к которому вы предоставили доступ контейнеру.
  5. В отличие от виртуальной машины, если два разных веб-сайта находятся в совершенно разных контейнерах, но используют одни и те же версии NGINX или PHP, дисковое пространство и оперативная память распределяются между двумя контейнерами.
  6. Поскольку каждое изображение является самодостаточным, переместить веб-сайт на другой сервер очень просто. Приложение не полагается на версию PHP, установленную на сервере, и ему всё равно, какие пакеты установлены на сервере. Если вы хотите переместить Dockerized-приложение на другой сервер, это так же просто, как скопировать все файлы веб-сайта и запустить приложение.
  7. Вы можете запустить на сервере столько образов Docker, сколько захотите, каждый со своей собственной версией PHP, программным обеспечением веб-сервера, базой данных и связанными файлами.

Настройка

Это теория в стороне. Теперь давайте перейдём к созданию сервера с помощью Docker.

Прежде чем мы начнём, вам необходимо скачать и установить Docker. Перейдите на сайт Docker, затем загрузите и установите его для своей операционной системы.

Если вы на Linux, вы должны установить dockerи docker-composeпакеты через менеджера пакетов вашего дистрибутива. В зависимости от вашего дистрибутива вам может потребоваться:

  1. Добавьте своего пользователя в dockerгруппу.
  2. Запустите dockerслужбу systemctl start docker.serviceи включите её с помощью systemctl enable docker.

Если вы используете Windows или macOS, установщик сделает это за вас.

Во-вторых, поскольку мы собираемся запустить веб-сервер внутри Docker и перенаправить некоторые порты, если у вас уже есть веб-сервер (Apache, NGINX, XAMPP, IIS и т.д.) Или MySQL, работающий на вашем компьютере, остановите их, прежде чем продолжить.

Веб-сервер обычно состоит из нескольких различных программ, таких как NGINX, PHP и MySQL. В терминологии Docker каждая программа, которую вы хотите установить, является службой.

В Docker есть несколько способов создания этих сервисов. Я расскажу о самом удобном для пользователя. Docker поддерживает создание файла конфигурации с использованием YAML (ещё один язык разметки).

Хотя вы можете ввести все параметры в командной строке, я рекомендую использовать файл конфигурации YAML по нескольким причинам:

  1. Это намного легче читать / понимать.
  2. Вам не нужно повторно вводить несколько длинных команд каждый раз, когда вы хотите запустить сервер.
  3. Вы можете отслеживать изменения в файле с помощью Git.

docker-compose.yml для NGINX

Docker предоставляет инструмент под названием, docker-composeкоторый принимает файл конфигурации с именем docker-compose.ymlи запускает перечисленные в нём службы. Начнём с добавления веб-сервера NGINX.

Во-первых, создайте где-нибудь на вашем компьютере папку, в которой будет храниться ваш сайт. Вам нужно будет регулярно возвращаться в эту папку, поэтому помните, где она находится. Создайте docker-compose.ymlсо следующим содержимым:

version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"

Давайте посмотрим на конфигурацию по очереди:

version: '3'

Это указывает, docker-composeкакую версию спецификации YAML использовать. 3является последним, и разные версии имеют немного разные спецификации, ключевые слова и структуру.

За следующей строкой services:,, будет список всех служб, которые вы хотите запустить.

В нашем примере до сих пор webвызывается только одна служба (вы можете называть её как угодно) с использованием официального образа NGINX nginx:latest. Обратите внимание, что отступ с использованием пробелов (не табуляции!) Имеет значение. YAML полагается на уровень вложенности для определения структуры файла.

Если вы хотите указать другую версию NGINX, вы можете указать это здесь так:

version: '3'
services:
    web:
        image: nginx:1.18.0
        ports:
            - "80:80"

Я рекомендую использовать, latestесли у вас нет веской причины использовать более раннюю версию.

portsБлок устанавливает переадресацию портов. Он пересылает 80на локальный компьютер 80образ. Любой запрос на хост-машине http://127.0.0.1будет перенаправлен на сервер NGINX, работающий в контейнере.

Запуск службы

Чтобы запустить сервер, вам нужно открыть терминал в вашей операционной системе и указать в нём папку, содержащую ваш docker-compose.ymlфайл. В Windows 10 самый простой способ — использовать проводник (ранее известный как проводник Windows, и его не следует путать с Internet Explorer). Перейдите в папку, в которой находится ваш docker-compose.yml, затем щёлкните Файл, а затем откройте Windows Powershell. В Linux у большинства файловых менеджеров есть кнопка «Открыть терминал здесь» или аналогичная. В macOS вам сначала нужно включить эту опцию.

Как только ваш терминал будет открыт в правильном месте, введите docker-compose up. Вы должны увидеть результат, подобный изображению ниже.

Как только ваш терминал будет открыт в правильном месте

Если вы получаете сообщения об ошибках, убедитесь, что Docker установлен и работает правильно. Если вы видите вывод, подобный приведённому выше, вы можете подключиться к серверу, посетив http://127.0.0.1 в своём браузере. Если он работает, вы увидите тестовую страницу NGINX, как показано на рисунке ниже.

Если он работает, вы увидите тестовую страницу NGINX

Почему не Апач?

Прежде чем мы продолжим, вам может быть интересно, почему я здесь не использую Apache. Если вы использовали XAMPP или аналогичный пакет, то используемый вами веб-сервер — Apache. Веб-сервер — это часть сервера, которая слушает запросы веб-браузера и отправляет ему файлы.

Apache в порядке, и он работает, но он существует всегда. Когда был создан Apache, Интернет был совсем другим местом. Apache большой, и есть много разных функций, которые пришли и ушли, но которые Apache всё ещё поддерживает. Интернет сильно изменился с тех пор, как был создан Apache, и, хотя это мощный сервер и будет работать нормально, большинство веб-сайтов в наши дни, как правило, используют NGINX. Его легче настроить, он легче и лучше настроен для задач, которые используются на многих современных веб-сайтах (например, потокового видео), и поэтому его доля на рынке быстро растёт за счёт Apache.

Мой общий совет: если у вас уже есть веб-сайт, на котором запущен Apache, нет причин беспокоиться о его изменении, но если вы начинаете новый проект с нуля, используйте NGINX.

Размещение файлов на сервере

Теперь, когда сервер установлен и работает через Docker, мы можем сделать наши файлы видимыми на сервере. Если вы привыкли к Apache, вы бы поместили их в папку httpdocs, htdocsили publicгде-нибудь на вашем компьютере.

Поскольку сервер работает в контейнере, он не имеет доступа ни к одному из файлов на вашем компьютере. Однако Docker позволяет указать том — файл или папку на вашем компьютере, которые используются совместно с контейнером. Вам понадобятся два тома: nginx.confфайл конфигурации (который мы ещё не создали) и папка, в которой будут храниться файлы вашего сайта. Измените свой, docker-compose.ymlвключив два volumes:

version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"
        volumes:
            - ./nginx.conf:/etc/nginx/conf.d/nginx.conf
            - ./app:/app

Это делает файл nginx.confи appкаталог из той же папки, что и ваши, docker-compose.ymlдоступными в контейнере. Любые изменения, которые вы вносите в файлы в томах, немедленно изменяются в контейнере, и файлы становятся общими для них.

nginx.confФайл с хоста помещается в /etc/nginx/conf.d/nginx.confвнутри контейнера. Это папка, из которой NGINX читает файлы конфигурации. appПапка создаётся в корне контейнера /appи где вы будете размещать всё ваш сайт PHP скрипты, изображения и файлы JavaScript.

Перед перезапуском сервера создайте файл nginx.confв том же каталоге, что и ваш, docker-compose.ymlсо следующим содержимым:

server {
    listen 80 default_server;
    root /app/public;
} 

Это сообщает NGINX, что это конфигурация, которую он должен использовать для сервера по умолчанию, и что он должен обслуживать файлы из каталога /app/public. Мы могли бы просто обслуживать файлы из /appкаталога, но рекомендуется держать большинство файлов PHP вне общедоступного каталога. Поскольку скрипты PHP должны будут загружать файлы../, мы поместим наш общедоступный каталог на один уровень ниже.

Чтобы проверить его работу, создайте страницу «Hello, World» на app/public/index.html, создавая каталоги по мере продвижения. Содержимое может быть таким:

h1>Hello, World!h1>

Перезагрузите сервер, вернувшись в терминал и нажав, ctrl-cчтобы остановить сервер, затем docker-compose upснова запустите команду, чтобы перезапустить его. (Вы можете нажать стрелку вверх, а затем Enterвместо того, чтобы вводить её повторно.)

Перезагрузите http://127.0.0.1 в своём браузере, и вы увидите сообщение Hello, World! тестовая страница. Теперь у вас есть рабочий веб-сервер, файлы которого обслуживаются по адресу http://127.0.0.1 из вашего app/publicкаталога.

PHP

Если вы хотите запускать сценарии PHP, вам необходимо добавить ещё одну службу для PHP в свой docker-compose.ymlи связать её с nginx:

version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"
        volumes:
            - ./nginx.conf:/etc/nginx/conf.d/nginx.conf
            - ./app:/app
    php:
        image: php:fpm
        volumes:
            - ./app:/app

Есть новый сервис php, использующий изображение php:fpm-latest. Для NGINX, вам необходимо использовать fpmпакет (FastCGI Process Manager), но вы можете выбрать любой PHP версии вам нравится — такие, как php:7.4-fpm, php:7.3-fpm, php:8.0-fpm. Если вы не укажете версию и используете только php:fpmее, будет использоваться последняя версия, которая на момент написания была 8.0.

Поскольку PHP потребуется доступ к вашим.phpфайлам из /appкаталога, вам необходимо смонтировать том в образе PHP так же, как вы это сделали для образа NGINX. PHP не требует доступа к nginx.confфайлу конфигурации, поэтому нет необходимости предоставлять ему доступ к нему.

appПапка теперь доступна на хост — машине, а в nginxи phpконтейнерах.

Перед перезапуском сервера docker-compose upнам необходимо настроить NGINX для запуска.phpфайлов через службу PHP. Откройте свой nginx.confи измените его на следующее:

server {
    listen 80 default_server;
    root /app/public;

    index index.php index.html index.htm;

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;     
    }
} 

indexСтрока сообщает серверу искать index.phpвместо index.htmlкак страницу по умолчанию. locationБлок инструктирует NGINX запустить любой файл с.phpрасширением через службу PHP ( fastcgi_pass php:9000, где phpэто имя службы, сконфигурированной в docker-compose.yml).

Создайте phpinfoфайл по адресу app/public/index.php:

phpinfo();

Перезагрузите сервер, нажав ctrl-cна своем терминале, и повторно запустите docker-compose upкоманду. Если все настроено правильно, при посещении http://127.0.0.1 вы должны увидеть phpinfo()вывод:

вы должны увидеть phpinfo()вывод

Предполагая, что ваш веб-сайт использует MySQL, если вы просмотрите phpinfo()страницу, вы заметите, что драйвер PHP MySQL не установлен. Мы хотим установить пакет PDO на PHP.

Это немного сложнее, так как нам нужно установить пакеты в образе. К счастью, официальный образ PHP содержит сценарий для этого.

Мы возьмем php:fpmза основу официальный образ и установим в него драйвер PDO MySQL. Это требует создания собственного имиджа, но это не так сложно, как кажется.

Во-первых, внесите изменения, docker-compose.ymlчтобы указать ему, что он должен создавать образ для PHP, а не использовать существующий php:fpmобраз:

version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"
        volumes:
            - ./nginx.conf:/etc/nginx/conf.d/nginx.conf
            - ./app:/app
    php:
        build:
            context: .
            dockerfile: PHP.Dockerfile
        volumes:
            - ./app:/app

Вместо imageзаписи, теперь buildвнизу есть строка php. contextДиректива является папка, файл конфигурации находится, что в нашем случае., текущий каталог (в той же папке в качестве нашего docker-compose.yml) и dockerfileэто имя файла, который мы будем использовать, чтобы построить свой имидж.

Создайте PHP.Dockerfileв той же папке, что и ваша, docker-compose.ymlи добавьте следующее:

FROM php:fpm

RUN docker-php-ext-install pdo pdo_mysql

Это установит pdo_mysqlрасширение для PHP. FROMДиректива говорит докер, что он должен использовать в php:fpmкачестве базового изображения и RUNдиректива используется для выполнения команд внутри изображения. Здесь вы можете запустить любую команду Linux. В этом случае мы запускаем docker-php-ext-installсценарий, который удобно предоставляется как часть официального пакета PHP и позволяет нам устанавливать расширения PHP.

Если вы хотите использовать библиотеку MySQLi ( хотя, вероятно, вам следует использовать PDO ), вы можете установить ее вместо или вместе с PDO:

FROM php:fpm

RUN docker-php-ext-install mysqli

Перезагрузите сервер с помощью docker-compose upкоманды. На этот раз вы увидите намного больше результатов, когда он построит изображение. Это произойдет только при первом запуске docker-compose up. Однако, если PHP.Dockerfileв будущем вы внесете какие-либо изменения, вам придется вручную перестроить его, выполнив команду docker-compose build.

Вы можете убедиться, что pdo_mysqlрасширение установлено, просмотрев phpinfo()вывод на http://127.0.0.1.

Пока мы устанавливаем расширения, давайте добавим xdebugрасширение для более удобных сообщений об ошибках на нашем сервере разработки:

FROM php:fpm

RUN docker-php-ext-install pdo pdo_mysql

RUN pecl install xdebug && docker-php-ext-enable xdebug

xdebugустанавливается через pecl, который предоставляется как часть официального образа PHP. Восстановите образ с помощью docker-compose build, затем перезапустите сервер с помощью docker-compose up. Вывод phpinfo()должен показать, что оба pdo_mysqlи xdebugустановлены.

MySQL

Теперь мы готовы установить MySQL. Еще раз, мы добавим его как службу в docker-compose.yml. Однако вместо установки официального образа MySQL мы будем использовать MariaDB, замену с потенциально лучшими будущими условиями лицензирования теперь, когда MySQL принадлежит Oracle. Если вы раньше использовали MySQL, MariaDB будет работать точно так же:

version: '3'
services:
    web:
        image: nginx:latest
        ports:
            - "80:80"
        volumes:
            - ./nginx.conf:/etc/nginx/conf.d/nginx.conf
            - ./app:/app
    php:
        build:
            context: .
            dockerfile: PHP.Dockerfile
        volumes:
            - ./app:/app
    mysql:
        image: mariadb:latest
        environment:
            MYSQL_ROOT_PASSWORD: 'secret'
            MYSQL_USER: 'tutorial'
            MYSQL_PASSWORD: 'secret'
            MYSQL_DATABASE: 'tutorial'
        volumes:
            - mysqldata:/var/lib/mysql
        ports:
            - 3306:3306
volumes:
    mysqldata: {}

Мы используем изображение mariadb:latest. Как и в случае с NGINX и PHP, при желании вы можете указать здесь конкретную версию MariaDB.

На этот раз есть environmentблок, который используется для передачи некоторых переменных в контейнер при его создании. Они используются для настройки базы данных со следующими параметрами. Задайте свои собственные значения для следующих переменных:

  • MYSQL_ROOT_PASSWORD: пароль root для базы данных. Вы можете использовать это для входа в систему rootи управления базой данных.
  • MYSQL_USERи MYSQL_PASSWORD: имя и пароль для пользователя MySQL, который создаётся с ограниченными правами. Вы захотите использовать это из своих сценариев PHP.
  • MYSQL_DATABASE: имя автоматически создаваемой схемы, к которой указанный выше пользователь имеет доступ.

В приведённом выше примере создаётся база данных с именем tutorial, доступ к которой можно получить с помощью пользователя tutorialи пароля secret.

Вы также заметите, что volumesвнизу есть запись. Это создаёт специальный тип тома, который не отображается в локальной файловой системе. Здесь будут храниться данные для MySQL — все ваши таблицы, записи и т.д.

Причина, по которой мы не хотим использовать папку в локальной файловой системе, заключается в том, что когда приложение загружается на реальный веб-сервер, вы не хотите перезаписывать реальную базу данных тестовой. Здесь будут храниться все ваши записи среды тестирования / разработки. Это позволяет вам иметь разные базы данных на реальном сервере и сервере разработки, когда вы загружаете свой веб-сайт.

Наконец, portsблок предоставляет порт 3306, чтобы мы могли подключиться к нему с помощью клиента, такого как MySQL Workbench, для управления базой данных. Я настоятельно рекомендую использовать это вместо PHPMyAdmin, если вы к этому привыкли, хотя вы можете поместить PHPMyAdmin в app/publicпапку и запустить его оттуда, если хотите.

Перезагрузите ваш сервер. На загрузку и настройку MariaDB в первый раз потребуется минута или две. Затем в сценарии PHP попробуйте подключиться к MySQL с PDO и выбранным вами именем пользователя, паролем и именем базы данных:

$pdo = new PDO('mysql:dbname=tutorial;host=mysql', 'tutorial', 'secret', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);

$query = $pdo->query('SHOW VARIABLES like "version"');

$row = $query->fetch();

echo 'MySQL version:' . $row['Value'];

Запустите этот сценарий на сервере. Если вы видите версию MySQL и сообщений об ошибках нет, вы подключены к серверу MySQL и все настроено правильно.

Выполнено!

Как вы только что обнаружили, Docker требует небольшой настройки, если вы делаете это самостоятельно. Если вы используете существующий docker-compose.ymlи конфигурационный файлы, это может быть всего пара команд.

Когда вы сделаете свой сайт жить, вы будете просто загрузить весь проект, в том числе docker-compose.yml, nginx.confи PHP.Dockerfileзапустите docker-compose up -dна сервере ( -dфлаг запускает его в качестве службы в фоновом режиме), и он будет работать точно такой же сайт, что вы видите на вашем машина разработки! Вам не нужно вручную настраивать и устанавливать PHP, MariaDB и NGINX на веб-сервере.

Как только вы освоите это, вы никогда не оглянетесь назад. Docker значительно упрощает процесс разработки веб-сайта, потому что все самодостаточно.

Результаты исследования Рика Страла

Рик Страл в своей статье занимался тестирование ASP.NET Core-кода на Windows — в Kestrel и в IIS (в режимах InProcess и OutOfProcess). Его интересовало количество запросов в секунду, обрабатываемых системой. В результате он пришёл к выводу о том, что первое место по производительности получает использование IIS в режиме InProcess, второе — Kestrel, третье — IIS в режиме OutOfProcess.

Обзор эксперимента

Рик не провёл испытания, позволяющие выявить различия в выполнении ASP.NET Core-кода на Windows- и на Linux-серверах. А вопрос о том, что в 2021 году лучше выбрать для проектов, основанных на ASP.NET Core 5.0, интересует многих из тех, кого я знаю. Поэтому я решил, используя подход к тестированию, похожий на тот, которым пользовался Рик, узнать о том, сколько запросов в секунду может обработать ASP.NET Core 5.0-приложение на Windows и на Linux.

Тестовое окружение

Так как Windows 10, Ubuntu Desktop и другие настольные операционные системы не в полной мере отражают особенности сопоставимых с ними серверных дистрибутивов, я решил выбрать для тестов серверные версии соответствующих ОС. Это были свежеустановленные копии систем с последними патчами, перед выполнением тестов они были один раз перезагружены.

▍Windows-сервер:


  • Провайдер: Microsoft Azure East Asia Region.
  • ОС: Windows Server 2019 Data Center.
  • Характеристики системы: B2S / 2 vCPU, 4GB RAM, Premium SSD.
  • Окружение: IIS с поддержкой статического и динамического сжатия контента, отсутствие интеграции с ASP.NET 3.5 или 4.x, на сервере установлена платформа ASP.NET Core 5.0.2 Runtime.

Сведения о Windows-сервере

▍Linux-сервер


  • Провайдер: Microsoft Azure East Asia Region.
  • ОС: Ubuntu Server 20.04 LTS.
  • Характеристики системы: B2S / 2 vCPU, 4GB RAM, Premium SSD.
  • Окружение: включено использование BBR, установлены Nginx, Caddy и ASP.NET Core 5.0.2 Runtime.

Сведения о Linux-сервере

▍Инструменты для проведения тестов

Рик пользовался West Wind Web Surge, но этот инструмент доступен только на платформе Windows, а это нас не устроит. Я решил воспользоваться опенсорсным кросс-платформенным инструментом bombardier, о котором однажды писали в официальном .NET-блоге Microsoft.

▍Тестовое приложение

Я создал новый проект ASP.NET Core 5.0 Web API, в котором имеется лишь один метод:

[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    [HttpGet]
    public string Get()
    {
        return $"Test {DateTime.UtcNow}";
    }
}

Для того чтобы не усложнять проект, я не проверял JSON-сериализацию и другие механизмы. Вы, если вам это интересно, вполне можете исследовать их самостоятельно.

Проект скомпилирован с применением конфигурации Release и опубликован с использованием FDD. Настройки логирования оставлены в стандартном состоянии:

"LogLevel": {
  "Default": "Information",
  "Microsoft": "Warning",
  "Microsoft.Hosting.Lifetime": "Information"
}

▍Методика тестирования

Я запускал проект, используя следующие конфигурации:

  • Kestrel.
  • IIS в режиме InProcess.
  • IIS в режиме OutOfProcess.
  • Обратный прокси Nginx.
  • Обратный прокси Caddy.

Затем я применял bombardier. В течение 10 секунд, по 2 соединениям, велась работа с конечной точкой, доступной на localhost. После «прогревочного» раунда испытаний я, друг за другом, проводил ещё 3 раунда и на основе полученных данных вычислял показатель количества запросов, обработанных исследуемой системой за секунду (Request per Second, RPS).

Пожалуйста, обратите внимание на то, что в идеальном случае лучше не использовать инструмент для исследования производительности, обращаясь с его помощью к локальным адресам. Дело в том, что при таком подходе операционная система вынуждена будет делить сетевые ресурсы между инструментом для тестирования и исследуемой программой. Но, так как сети в облачных окружениях не так стабильны, как localhost-подключение, я решил использовать в тестах именно локальное подключение. Это позволило исключить воздействие особенностей сети на результаты.

Результаты тестов


▍Windows + Kestrel

Средний RPS: 18808

Windows + Kestrel

▍Windows + IIS в режиме InProcess

Средний RPS: 10089

Windows + IIS в режиме InProcess

▍Windows + IIS в режиме OutOfProcess

Средний RPS: 2820

Windows + IIS в режиме OutOfProcess

▍Linux + Kestrel

Средний RPS: 10667

Linux + Kestrel

▍Linux + Nginx

Средний RPS: 3509

Linux + Nginx

▍Linux + Caddy

Средний RPS: 3485

Linux + Caddy

Итоги

Вот как выглядят результаты тестирования (от самой быстрой комбинации ОС и серверного ПО — до самой медленной):

  • Windows + Kestrel (18808)
  • Linux + Kestrel (10667)
  • Windows + IIS в режиме InProcess (10089)
  • Linux + Nginx (3509)
  • Linux + Caddy (3485)
  • Windows + IIS в режиме OutOfProcess (2820)

Мои результаты отличаются от тех, что получил Рик, тестируя ASP.NET Core 2.2-проект. В его тестах производительность IIS в режиме InProcess оказывалась выше, чем производительность Kestrel. Но сейчас Kestrel оказывается быстрее IIS в режиме InProcess, и это кажется вполне логичным и ожидаемым.

А вот неожиданностью для меня стало то, что производительность Windows-серверов c Kestrel оказалась выше производительности аналогичных Linux-серверов. Это меня удивило.

В режиме обратного прокси-сервера Nginx и Caddy, в общем-то, показывают одинаковую производительность. И та и другая конфигурации обходят IIS в режиме OutOfProcess.

Конечно, мой простой тест, в ходе которого сервер возвращает обычную строку, не позволяет проверить все нюансы производительности ASP.NET Core 5.0 и исследовать возможности каждого сервера. В реальных проектах присутствует множество факторов, которые воздействуют на производительность. План моего эксперимента не перекрывает все возможные сценарии использования ASP.NET Core 5.0, в нём, наверное, имеются какие-то недочёты. Если вы что-то такое заметите — дайте мне знать.

Для начала немного истории

Я очень долгое время жил в мире Ubuntu — писать на PHP, NodeJS, GoLang сразу на той же системе, на которой все будет запускаться, крайне приятно. Но, к сожалению, наличие руководящей должности приводит к тому, что приходится пользоваться большим количеством софта, который работает только на Windows.

Очень долгое время я просто жил "через SSH". На моем ноутбуке просто стоял PhpStorm, в котором я через ssh правил файлы на Ubuntu сервере — просто и работает.

Виртуалки сразу отбросил — ноут не очень радовался соседям внутри:) Докер поджирал заметно ресурсы и без того перегруженного 100500 вкладками и копиями запущенных Phpstorm небольшой ноутбук dell e7390:) Докер крутится у нас в бою и как раз на дев серверах, куда я хожу через sftp.

Но прошло время и стало возможным легко и просто запустить у себя на винде WSL2 (http://habr.com/ru/news/t/516054) и я решил все же сделать удобное окружение для своей работы.


Теперь к делу


Базовая установка системы

Как установить WSL на Windows есть множество инструкций. Я все сделал по официальному мануалу с сайта Microsoft

После успешной установки в PowerShell нужно написать команду wsl и мы погружаемся внутрь Linux, который внутри Windows

Далее идет череда стандартных команд для настройки веб сервера на Ubuntu:


sudo apt update
sudo apt upgrade
sudo apt install apache2
sudo apt install php libapache2-mod-php php-mysql php-xml php-curl
sudo a2enmod rewrite

Все файлы моих проектов было доступы через /mnt/d/work/projects/и_так_далее. Да, я в курсе, что стоит копировать файлы напрямую в файловую систему Linux, чтобы работало быстрее. Но зачастую такого варианта по скорости достаточно, но если чувствуете тормоза ФС, то стоит использовать сетевой диск.


По поводу сетевого диска

Теория гласит (да и здравый смысл тоже), что файлы, с которыми оперирует php должны быть в самой системе Linux, а не в виде подмонтированного NTFS винды. Если нужно чтобы файлы были полностью нативно в системе можно сделать следующее.


  1. Создать папку под WSL проект. Например /home/user/projects
  2. Склонировать копию проекта туда же (уже внутренним GIT). Например будет /home/user/projects/test
  3. Подключить сетевой диск на директорию \\wsl$\Ubuntu где "Ubuntu" — название вашего дистрибутива. Определить верное название можно путем перехода в папку \\wsl$ в проводнике
  4. Добавляем папку в сетевом диске в PhpStorm
  5. Настроить маппинг директорий для отладки (чтобы шторм понимал какому файлу соответствует файл, который прислал нам xdebug)
  6. Включить Automatic upload
  7. Теперь все изменения будут отправляться сразу же в WSL через сетевой диск и можно заниматься отладкой

Но в данном способе есть один неприятный минус — надо синхронизировать файлы. Например вы перешли на другую ветку в винде = надо в линуксе тоже переходить в эту ветку. Двойная работа. Подумываю над каким нибудь хитрым скриптом, который с rsync будет все это делать сам, но пока не придумал. Если придумаете, пишите — буду очень благодарен:)

Также не забывайте настройку Apache, чтобы он ходил в нужные директории. Если что, конечно, можно сделать связку из php-fpm и nginx — тут уже на ваш вкус.


Настройка xdebug на сервере

Далее настраиваем xdebug стандартным путем по любому мануалу из интернета. Я опишу кратко порядок действий.


  1. Устанавливаем xdebug через sudo apt-get install php-xdebug


  2. Открываем sudo nano /etc/php/7.2/mods-available/xdebug.ini и приводим к такому содержимому


    zend_extension=xdebug.so
    xdebug.remote_enable=true
    xdebug.remote_host=wsl.host
    xdebug.remote_port=9002
    xdebug.profiler_enable=1
    xdebug.profiler_output_dir=/tmp
    xdebug.remote_autostart=on
    xdebug.idekey=PHPSTORM
    xdebug.remote_log=/tmp/xdebug.log

  3. Перезапускаем apache sudo service apache2 restart



Костыль для обратной связи

На этом настройки конкретно xdebug на сервере заканчиваются. Но чтобы данный конфиг заработал нам необходимо в /etc/hosts указать что такое wsl.host. На самом деле мы ожидаем там увидеть IP адрес головной системы на нашем ПК, а именно windows.

Изначально во всех инструкциях, которые я нашел, указывается что нужно писать xdebug.remote_host=127.0.0.1, но сеть в WSL устроена таким образом, что 127.0.0.1 внутри linux будет указывать именно на linux, а не windows. То есть дебаггер, ожидающий подключения в PhpStorm не дождется этих подключений:)

В поисках решения этой проблемы я наткнулся на пост в интернете, откуда решил взять gif-ку что наглядности.


Небольшая гифка-пояснение

Автор поста предлагает свой github репозиторий с C# приложением, которое надо добавить в планировщик Windows чтобы команда выполнялась при каждом запуске ПК. У меня сходу этот скрипт не сработал, да и проводить какие-то кастомизации в Windows не хотелось.

Ценой нескольких часов я собрал "костыльный" bash скрипт, который прописывает автоматически IP адрес хостовой системы в /etc/hosts внутри linux при каждом входе в WSL — инструкцию и скрипт выложил на github.

Но этот скрипт нужно запускать при первом запуске системы. Руками такое делать "не красиво", а стандартный systemd и rc.local через wsl не работают. Поэтому пришлось использовать костыльное и небезопасное, но рабочее решение.


  1. Создаем файл в корне системы /startup.sh с таким содержимым, даем ему права на запуск chmod +x /startup.sh
  2. Даем права на запуск этого скрипта с sudo без пароля (иначе доступа на запись в /etc/hosts нет)
  3. Добавляем строчку sudo /startup.sh в /etc/profile

При каждом входе в wsl запускается скрипт, который прописывает все что нужно в /etc/hosts и по адресу wsl.host наш linux будет видеть windows. Если кто-то знает как это можно достичь более правильным путем, буду благодарен если отпишите способ в комментариях или можно лично.

После входа в wsl стоит проверить, что хост прописался — пишем команду cat /etc/hosts и на последнем месте должно быть что-то вроде этого:
172.26.64.1 wsl.host


Настройка xdebug в PhpStorm на Windows

После завершения всех работ внутри WSL можно перейти к настройке дебаггера в PhpStorm


  1. File->Settings->Languages & Framework->PHP
    Открываем выбор интерпретаторов

    Первый вариант "From Docker, Vagrant, VM, WSL, Remote"

    Выбираем установленный WSL

    Убеждаемся, что xdebug активирован


  2. File->Settings->Languages & Framework->PHP->Debug
    Активируем прослушивание дебаггера и указываем порт, который ранее указали в WSL (у меня это 9002, а изначально он 9000)

    В итоге должно выглядеть примерно так

    Убираем галочку в advanced напротив пункта "Pass required configuration options.."


Если ее не снять, то дебаггер будет передавать свои параметры по умолчанию и они будут перезатираться — в итоге наш wsl.host будет заменен на 127.0.0.1 и ничего работать не будет.

Причем эта проблема проявляется только при отладке через консоль, т.к. при отладке HTTP сервера никакие конфиги не пробрасываются и забираются из ini файлов.

На этом все — можно проверять работает ли дебаггер.


Проверка результата


  1. Ставим breakpoint в index.php на любой строчке в коде
  2. Переходим в браузере на этот файл и видимо, что дебаггер заработал

  3. Для отладки консольного скрипта необходимо добавить конфигурацию запуска скрипта

    Добавляем конфигурацию Php Script


Указываем путь до скрипта и нужные аргументы

Сохраняем, закрываем и запускаем дебаггер


Установка phpMyAdmin на компьютер

Прежде чем начать установку phpMyAdmin, убедитесь, что у вас установлены и настроены сервер Apache, PHP и базы данных MySQL. Еще нужно соединение с сервером по защищенному туннелю SSH. Этот способ скорее можно назвать ручным.

Сперва советуем скачать архив приложения с официального русскоязычного сайта. Выбираем любую удобную версию и жмем по ссылке для начала загрузки.

Скачивание архива phpMyAdmin с сайта

Как только процесс загрузки завершится, распакуем архив. Затем переходим в папку htdocs, расположенную на системном диске в директории «Apache». Сюда вставляем папку из архива, потом переименовываем ее в phpmyadmin.

Теперь открываем папку «PHP» и находим в ней файл «php.ini-production». Переименовываем его в php.ini, а потом открываем с помощью «Блокнота». Находим в тексте строчки «extension=php_mysqli.dll» и «extension=php_mbstring.dll» и удаляем в них символ точки с запятой. Сохраняем изменения, выходим из блокнота.

Если все сделано правильно, то после введения в адресной строке браузера запроса http://localhost будет открываться страница авторизации phpMyAdmin.

Настройка PHP-FPM

Менеджер процессов PHP-FPM может запускать несколько процессов обработчиков. Обычно для каждого отдельного сайта принято использовать отдельный обработчик, это позволяет распределить нагрузку и отслеживать статистику по каждому сайту. Поэтому есть общий конфигурационный файл php-fpm и конфигурационный файл для каждого обработчика, который обычно называется конфигурационным файлом пула. Обработчик принято называть пулом потому что на самом деле обработкой занимается не один процесс, а целая группа процессов, у каждого из которых есть несколько потоков. Всё это обеспечивает быстрое выполнение скриптов.

1. Установка компонентов

Сервис php-fpm поставляется вместе с интерпретатором php. Установка php-fpm Ubuntu выполняется такой командой:

sudo apt install php-fpm

Кроме того нам понадобится веб-сервер Nginx, потому что php-fpm чаще всего используется вместе с этим веб-сервером:

sudo apt install nginx

2. Конфигурационные файлы

В этой инструкции мы будем рассматривать настройку PHP-FPM на примере Ubuntu. Основной конфигурационный файл находится в такому пути:

ls /etc/php/7.4/fpm/php-fpm.conf

Обратите внимание, что это не php.ini файл, а файл настройки именно FPM процессов. Файл php.ini находится в этой же папке:

ls /etc/php/7.4/fpm/php.ini

А вот файлы конфигурации пулов находятся в каталоге /etc/php/7.4/fpm/pool.d/. По умолчанию там находится файл пула по умолчанию www.conf:

ls /etc/php/7.4/fpm/pool.d/

Вы можете использовать его в своей конфигурации или копировать для создания новых пулов.

3. Создание пула

Скопируйте файл пула, например losst.conf в папке /etc/php/7.4/fpm/pool.d/ скопируйте в него содержимое файла www.conf. В конце статьи я приведу полностью рабочий конфигурационный файл, но лучше всё же использовать конфигурацию вашей версии PHP:

cp /etc/php/7.4/fpm/pool.d/www.conf /etc/php/7.4/fpm/pool.d/losst.conf

Теперь откройте этот файл в текстовом редакторе, например в vim:

sudo vi /etc/php/7.4/fpm/pool.d/losst.conf

Первым делом вам нужно выбрать имя пула в квадратных скобках в самой верхней части файла, например, losst, это имя можно использовать в конфигурации с помощью переменной $pool, а ещё оно будет отображаться в менеджере процессов:

Далее надо изменить группу и пользователя, от имени которых будут запускаться процессы пула. Это важно, поскольку у процесса должен быть доступ к файлам PHP, которые надо выполнить. Обычно в Ubuntu для таких целей используется пользователь и группа www-data. От имени этого же пользователя обычно запускается веб-сервер:

Обычно, если вы получаете ошибку permission denied при интерпретации php файлов в php-fpm, означает, что процесс php-fpm запущен от имени не того пользователя или включена строгая политика SELinux.

4. Настройка сокета

Дальше нужно настроить каким образом Nginx или другой веб-сервер будет обращаться к PHP-FPM. Как я уже говорил выше, можно настроить ожидание соединений на TCP порту. Обычно используются порты 9000, 9001, 9002 и так далее. В данном случае надо передать IP адрес на котором следует слушать и порт. Лучше использовать локальный IP адрес 127.0.0.1, чтобы к сервису никто не мог подключится из интернета. Второй вариант - использовать файловый Unix сокет, тогда надо просто передать путь к файлу сокета. В данном примере используется сетевой сокет 127.0.0.1:9000. Вид сокета не имеет значения, но сетевой использовать удобнее:

Если вы используйте файловый сокет, к нему должен быть доступ у веб-сервера, поэтому надо сделать владельцами файла того пользователя и группу, от имени которых запущен веб-сервер, в данном случае www-data и дать им все права на него:

listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Если сокет сетевой, то в этом нет необходимости. Для сетевого сокета можно дополнительно указать с каких адресов можно к нему подключаться. Например, только от 127.0.0.1:

listen.allowed_clients = 127.0.0.1

5. Настройка процессов

С помощью параметра pm можно настроить сколько дочерних процессов будет запускаться для этого пула и когда. Есть три режима работы:

  • dynamic - процессы создаются в зависимости от нагрузки и настроек, если нагрузки нет, всё равно работает определённое количество процессов;
  • ondemand - процессы создаются как только возникает нагрузка;
  • static - количество процессов всегда одинаковое, указанное в настройках.

Режим static не выгоден, потому что вне зависимости от нагрузки потребляется много памяти и процессорного времени на поддержание работы процессов. Более интересны режимы ondemand и dynamic. Давайте будем использовать режим dynamic. Этот режим имеет три настройки:

  • pm.max_children - очень важный параметр, который работает для всех трёх режимов, означает максимально возможное количество дочерних процессов, если значение будет слишком маленьким, то при возрастании нагрузки, лимит исчерпается и ваш сайт начнёт тупить, если слишком большим - исчерпается оперативная память и что-то упадёт;
  • pm.start_servers - указывает сколько процессов запускать при старте сервиса;
  • pm.min_spare_servers - минимальное количество процессов в режиме ожидания (ничего не обрабатывающих), если количество процессов меньше, будет создан ещё один;
  • pm.max_spare_server - максимальное количество процессов в режиме ожидания, если количество процессов будет больше, лишние будут завершены;

Для режима static надо указать только pm.max_children. Для режима ondemand кроме pm.max_children надо указать pm.process_idle_timeout этот параметр означает через какой промежуток времени простоя процесс будет завершен.

Давайте разберемся с режимом dynamic. Запускать много дочерних процессов при старте не надо, в большинстве случаев 2-3 будет достаточно:

pm.start_servers = 3

Минимальное количество процессов в режиме ожидания тоже большое не нужно, это запас, чтобы php-fpm смог быстро обработать новые запросы не тратя время на запуск новых процессов. Однако это значение должно быть не меньше pm.start_servers, иначе ничего не заработает:

pm.min_spare_servers = 3

Максимальное количество процессов определяет как быстро процессы будут завершаться при падении нагрузки, можно оставить 10 процессов:

pm.max_spare_servers = 10

Параметр pm.max_children настройте под себя, обычно достаточно 20-30 процессов, но всё зависит от нагрузки и количества оперативной памяти, если памяти мало лучше пожертвовать производительностью и установить меньшее значение:

pm.max_children = 30

Почти готово. Но есть ещё одна проблема. Если дочерние процессы работают слишком долго, в них накапливаются утечки памяти, и рано или поздно на сервере память закончится. Чтобы этого избежать можно настроить автоматическое завершение процесса после выполнения определённого количества запросов, например, 1000:

pm.max_requests = 1000

6. Настройка статистики

Для подбора оптимального значения pm.max_children вам может понадобиться посмотреть статистику в реальном времени сколько процессов запущено, сколько из них находится в ожидании, а также какая длина очереди ожидающих выполнения запросов. Для включения вывода статистики просто добавьте такую строчку:

pm.status_path = /status

7. Настройка php.ini

Несмотря на то, что есть общий файл php.ini для всех пулов, вы можете менять настройки прямо в файле пула, для этого используются директивы php_admin_value и php_admin_flag. Первая используется для установки строковых значений, а вторая - для флагов. У директив есть альтернативы: php_value и php_flag, они отличаются только тем, что их можно перезаписать с помощью функции ini_set, а значения заданные с помощью директив с приставкой admin перезаписать нельзя.

Например:

php_admin_flag[display_errors] = off
php_admin_value[error_log] = /var/log/fpm-php.losst.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 32M

Когда все настройки завершены, не забудьте сохранить изменения и перезапустить php-fpm:

sudo systemctl restart php7.4-fpm

8. Настройка веб-сервера

Для того чтобы всё протестировать придётся настроить ещё и веб-сервер. В конфигурационный файл виртуального хоста Nginx надо добавить такие строки:

location /status {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}

Первая секция позволяет смотреть статистику работы php-fpm открыв в браузере ссылку /status, которую мы ранее указали в настройках. Вторая секция обрабатывает всё остальные файлы php. Первая строка второй секции разбивает путь к скрипту по регулярному выражению на две части: $fastcgi_script_name и $fastcgi_path. Первая переменная нам понадобится в следующей же строчке, где с помощью условия проверяется существует ли такой файл, и если нет, то возвращается 404.

Дальше надо импортировать файл fastcgi_params, в котором передаются все переменные, которые потом будут доступны в массиве $_SERVER из скрипта. В следующей строчке объявляется ещё один важный параметр, которого нет в fastcgi_params, потому что он использует переменную $fastcgi_script_name, полученную ранее. Именно по нему php-fpm определяет путь к скрипту, который надо выполнить, если его не передать, вы получите пустой экран.

Последняя директива fastcgi_pass указывает как надо передавать данные php-fpm, сюда можно передать путь к файлу сокету, на котором слушает сервис или IP адрес и порт. В данном случае используется ранее настроенный 127.0.0.1:9000. После завершения настройки перезапустите Nginx:

sudo systemctl restart nginx

Теперь вы можете открыть в браузере страницу статистики, как видите всё работает:

Можно ещё создать файл phpinfo.php с текстом в каталоге веб-сервера и посмотреть настройки php, например, memory_limit, заданный в файле конфигурации пула работает:

Настройка веб-сервера может очень сильно отличаться в зависимости от ваших требований. Здесь приведен только общий пример, чтобы проверить работоспособность и верность настройки.