Verification: a143cc29221c9be0

Nginx php fpm mysql настройка

Nginx php fpm mysql настройка

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

Одна из проблем веб-разработки заключается в том, что всё быстро меняется. Лучшие практики 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 значительно упрощает процесс разработки веб-сайта, потому что все самодостаточно.

Подготовка

Прежде чем продолжить изучение этого руководства, убедитесь, что выполнены следующие предварительные условия:

  • Укажите доменное имя, указывающее на общедоступный IP-адрес вашего сервера. В этом руководстве мы будем использовать example.com .
  • Вы вошли в систему как пользователь с привилегиями sudo .
  • Nginx устанавливается, следуя этим инструкциям .
  • У вас установлен сертификат SSL для вашего домена. Вы можете сгенерировать бесплатный SSL-сертификат Let's Encrypt, следуя этим инструкциям .

Создание базы данных MySQL

WordPress хранит свои данные и конфигурацию в базе данных MySQL. Первым шагом является создание базы данных MySQL, учетной записи пользователя MySQL и предоставление доступа к базе данных .

Если на вашем сервере Ubuntu еще не установлены MySQL или MariaDB, вы можете установить его, следуя одной из следующих инструкций:

  • Установите MySQL на CentOS 7 .
  • Установите MariaDB на CentOS 7 .

Войдите в оболочку MySQL, выполнив следующую команду:

mysql -u root -p

Из оболочки MySQL выполните следующие операторы SQL, чтобы создать базу данных с именем wordpress , пользователем с именем wordpressuser и предоставить пользователю все необходимые разрешения:

CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;GRANT ALL ON wordpress.* TO 'wordpressuser'@'localhost' IDENTIFIED BY 'change-with-strong-password';FLUSH PRIVILEGES;EXIT;

Установка PHP 7.2

CentOS 7 поставляется с PHP версии 5.4. Рекомендуемая версия PHP для WordPress — PHP 7.2.

Чтобы установить PHP и все необходимые расширения PHP, выполните следующие команды:

sudo yum install epel-release yum-utilssudo yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpmsudo yum-config-manager --enable remi-php72sudo yum install php-cli php-fpm php-mysql php-json php-opcache php-mbstring php-xml php-gd php-curl

Мы установили PHP FPM, потому что мы будем использовать Nginx в качестве веб-сервера.

По умолчанию PHP FPM запускается как пользовательский apache на порту 9000. Мы изменим пользователя на nginx и переключимся с сокета TCP на сокет Unix. Для этого откройте файл /etc/php-fpm.d/www.conf отредактируйте строки, выделенные желтым:

/etc/php-fpm.d/www.conf

...
user = nginx
...
group = nginx
...
listen = /run/php-fpm/www.sock
...
listen.owner = nginx
listen.group = nginx

Убедитесь, что каталог /var/lib/php имеет правильного владельца, используя следующую команду chown :

sudo chown -R root:nginx /var/lib/php

После внесения изменений включите и запустите службу PHP FPM:

sudo systemctl enable php-fpmsudo systemctl start php-fpm

Скачивание WordPress

Перед загрузкой архива WordPress сначала создайте каталог, в который мы поместим файлы WordPress:

sudo mkdir -p /var/www/html/example.com

Следующим шагом будет загрузка последней версии WordPress со страницы загрузки WordPress с помощью следующей команды wget :

cd /tmpwget https://wordpress.org/latest.tar.gz

Когда загрузка будет завершена, извлеките архив WordPress и переместите файлы в корневой каталог документов домена:

tar xf latest.tar.gzsudo mv /tmp/wordpress/* /var/www/html/example.com/

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

sudo chown -R nginx: /var/www/html/example.com

Настройка Nginx

К настоящему времени у вас уже должен быть установлен Nginx с сертификатом SSL в вашей системе, если нет, проверьте предварительные требования для этого руководства.

Чтобы создать новый серверный блок для нашего экземпляра WordPress, мы будем использовать рецепт Nginx с официального сайта Nginx.

Откройте текстовый редактор и создайте новый серверный блок nginx :

sudo nano /etc/nginx/conf.d/example.com.conf

Добавьте следующие строки:

/etc/nginx/conf.d/example.com.conf

# Redirect HTTP -> HTTPS
server {
    listen 80;
    server_name www.example.com example.com;

    include snippets/letsencrypt.conf;
    return 301 https://example.com$request_uri;
}

# Redirect WWW -> NON WWW
server {
    listen 443 ssl http2;
    server_name www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    include snippets/ssl.conf;

    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    root /var/www/html/example.com;
    index index.php;

    # SSL parameters
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    include snippets/ssl.conf;
    include snippets/letsencrypt.conf;

    # log files
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

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

    location ~ .php$ {
        try_files $uri =404;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index   index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires max;
        log_not_found off;
    }

}

Перед перезапуском сервиса Nginx проверьте конфигурацию, чтобы убедиться в отсутствии синтаксических ошибок:

sudo nginx -t

Если ошибок нет, результат должен выглядеть так:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

и вы можете перезапустить Nginx , набрав:

sudo systemctl restart nginx

Завершение установки WordPress

Теперь, когда WordPress загружен и настройка сервера завершена, вы можете завершить установку через веб-интерфейс.

Откройте браузер, введите свой домен, и появится экран, подобный следующему:

Выберите язык, который вы хотите использовать, и нажмите кнопку « Continue .

Затем вы увидите следующую информационную страницу, нажмите Let's go! кнопка.

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

Запустите установку WordPress, нажав кнопку « Run the Installation .

На следующем шаге вам нужно будет ввести имя для вашего сайта WordPress и выбрать имя пользователя (в целях безопасности не используйте «admin»).

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

Введите свой адрес электронной почты и выберите, хотите ли вы, чтобы поисковые системы не индексировали сайт (не рекомендуется).

Щелкните Install WordPress и после завершения установки вы попадете на страницу, информирующую вас о том, что WordPress установлен.

Чтобы получить доступ к странице входа в WordPress, нажмите кнопку « Log in .

Введите ваше имя пользователя и пароль.

Вы будете перенаправлены на панель администрирования WordPress.

Отсюда вы можете приступить к настройке вашей установки WordPress, установив новые темы и плагины.

NGINX + PHP + PHP-FPM

Рекомендуется каждый микросервис помещать в свой отдельный контейнер, но мы (для отдельного примера) веб-сервер с интерпретатором PHP поместим в один и тот же имидж, на основе которого будут создаваться контейнеры.

Создание образа

Создадим каталог, в котором будут находиться файлы для сборки образа веб-сервера:

mkdir -p /opt/docker/web-server

Переходим в созданный каталог:

cd /opt/docker/web-server/

Создаем докер-файл:

vi Dockerfile

  1. FROM centos:8
  2.  
  3. MAINTAINER Dmitriy Mosk
  4.  
  5. ENV TZ=Europe/Moscow
  6.  
  7. RUN dnf update -y
  8. RUN dnf install -y nginx php php-fpm php-mysqli
  9. RUN dnf clean all
  10. RUN echo "daemon off;" >> /etc/nginx/nginx.conf
  11. RUN mkdir /run/php-fpm
  12.  
  13. COPY ./html/ /usr/share/nginx/html/
  14.  
  15. CMD php-fpm -D ; nginx
  16.  
  17. EXPOSE 80

* где:
1) указываем, какой берем базовый образ. В нашем случае, CentOS 8.
3) задаем для информации того, кто создал образ. Указываем свое имя и адрес электронной почты.
5) создаем переменную окружения TZ с указанием временной зоны (в нашем примере, московское время).
7) запускаем обновление системы.
8) устанавливаем пакеты: веб-сервер nginx, интерпретатор php, сервис php-fpm для обработки скриптов, модуль php-mysqli для работы php с СУБД MySQL/MariaDB.
9) удаляем скачанные пакеты и временные файлы, образовавшиеся во время установки.
10) добавляем в конфигурационный файл nginx строку daemon off, которая запретит веб-серверу автоматически запуститься в качестве демона.
11) создаем каталог /run/php-fpm — без него не сможет запуститься php-fpm.
13) копируем содержимое каталога html, который находится в том же каталоге, что и dockerfile, в каталог /usr/share/nginx/html/ внутри контейнера. В данной папке должен быть наше веб-приложение.
15) запускаем php-fpm и nginx. Команда CMD в dockerfile может быть только одна.
17) открываем порт 80 для работы веб-сервера.

В рабочем каталоге создаем папку html:

mkdir html

... а в ней — файл index.php: 

vi html/index.php

* мы создали скрипт, который будет выводить информацию о php в браузере для примера. По идее, в данную папку мы должны положить сайт (веб-приложение).

Создаем первый билд для нашего образа:

docker build -t dmosk/webapp:v1 .

Новый образ должен появиться в системе:

docker images

При желании, его можно отправить на Docker Hub следующими командами:

docker login --username dmosk

docker tag dmosk/webapp:v1 dmosk/web:nginx_php7

docker push dmosk/web:nginx_php7

* первой командой мы прошли аутентификацию на портале докер-хаба (в качестве id/login мы используем dmosk — это учетная запись, которую мы зарегистрировали в Docker Hub). Вторая команда создает тег для нашего образа, где dmosk — учетная запись на dockerhub; web — имя репозитория; nginx_php7 — сам тег. Последняя команда заливает образ в репозиторий.
* подробнее про загрузку образа в репозиторий докера.

Запуск контейнера и проверка работы

Запускаем веб-сервер из созданного образа:

docker run --name web_server -d -p 80:80 dmosk/webapp:v1

Открываем браузер и переходим по адресу http:// — откроется страница phpinfo:

Информация о PHP

Наш веб-сервер из Docker работает.

MariaDB

Для запуска СУБД мы будем использовать готовый образ mariadb. Так как после остановки контейнера, все данные внутри него удаляются, мы должны подключить внешний том, на котором будут храниться наши базы.

Сначала создаем том для докера:

docker volume create --name mariadb

* в данном примере мы создали том с именем mariadb. Будет создан каталог /var/lib/docker/volumes/mariadb/_data/ на хостовом сервере, куда будут размещаться наши файлы базы.

Выполним первый запуск нашего контейнера с mariadb:

docker run --rm --name maria_db -d -e MYSQL_ROOT_PASSWORD=password -v mariadb:/var/lib/mysql mariadb

* где:

  • --rm — удалить контейнер после остановки. Это первый запуск для инициализации базы, после параметры запуска контейнера будут другими.
  • --name maria_db — задаем имя контейнеру, по которому будем к нему обращаться.
  • -e MYSQL_ROOT_PASSWORD=password — создаем системную переменную, содержащую пароль для пользователя root базы данных. Оставляем его таким, как в данной инструкции, так как следующим шагом мы его будем менять.
  • -v mariadb:/var/lib/mysql — говорим, что для контейнера мы хотим использовать том mariadb, который будет примонтирован внутри контейнера по пути /var/lib/mysql.
  • mariadb — в самом конце мы указываем имя образа, который нужно использовать для запуска контейнера. Это образ, который при первом запуске будет скачан с DockerHub.

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

ls /var/lib/docker/volumes/mariadb/_data/

Теперь подключаемся к командной строке внутри контейнера с сервером базы данных:

docker exec -it maria_db /bin/bash

Подключаемся к mariadb:

:/# mysql -ppassword

Меняем пароль для учетной записи root:

> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('New_Password');

Выходим из командной строки СУБД:

> quit

Выходим из контейнера:

:/# exit

Останавливаем сам контейнер — он нам больше не нужен с данными параметрами запуска:

docker stop maria_db

И запускаем его по новой, но уже без системной переменной с паролем и необходимостью его удаления после остановки:

docker run --name maria_db -d -v mariadb:/var/lib/mysql mariadb

Сервер баз данных готов к работе.

Подключение к базе из веб-сервера

По отдельности, наши серверы готовы к работе. Теперь настроим их таким образом, чтобы из веб-сервера можно было подключиться к СУБД.

Зайдем в контейнер с базой данных:

docker exec -it maria_db /bin/bash

Подключимся к mariadb:

:/# mysql -p

Создадим базу данных, если таковой еще нет:

> CREATE DATABASE docker_db DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;

* в данном примере мы создаем базу docker_db.

Создаем пользователя для доступа к нашей базе данных:

> GRANT ALL PRIVILEGES ON docker_db.* TO 'docker_db_user'@'%' IDENTIFIED BY 'docker_db_password';

* и так, мы дали полные права на базу docker_db пользователю docker_db_user, который может подключаться от любого хоста (%). Пароль для данного пользователя — docker_db_password.

Отключаемся от СУБД:

> quit

Выходим из контейнера:

:/# exit

Теперь перезапустим наши контейнеры с новым параметром, который будет объединять наши контейнеры по внутренней сети.

Останавливаем работающие контейнеры и удаляем их:

docker stop maria_db web_server

docker rm maria_db web_server

Создаем docker-сеть:

docker network create net1

* мы создали сеть net1.

Создаем новые контейнеры из наших образов и добавляем опцию --net, которая указывает, какую сеть будет использовать контейнер:

docker run --name maria_db --net net1 -d -v mariadb:/var/lib/mysql mariadb

docker run --name web_server --net net1 -d -p 80:80 dmosk/webapp:v1

* указав опцию --net, наши контейнеры начинают видеть друг друга по своим именам, которые мы задаем опцией --name.

Готово. Для проверки соединения с базой данных в php мы можем использовать такой скрипт:

ini_set("display_startup_errors", 1);
ini_set("display_errors", 1);
ini_set("html_errors", 1);
ini_set("log_errors", 1);
error_reporting(E_ERROR | E_PARSE | E_WARNING);

$con = mysqli_connect('maria_db', 'docker_db_user', 'docker_db_password', 'docker_db');

?>

* в данном примере мы подключаемся к базе docker_db на сервере maria_db с использованием учетной записи docker_db_user и паролем docker_db_password.

После его запуска, мы увидим либо пустой вывод (если подключение выполнено успешно), либо ошибку.

Использование docker-compose

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

И так, автоматизируем запуск наших контейнеров с использованием docker-compose. Необходимо, чтобы он был установлен в системе.

Сначала удалим контейнеры, которые создали на предыдущих этапах:

docker rm -f web_server maria_db

Переходим в каталог для наших сборок:

cd /opt/docker/

Создаем yml-файл с инструкциями сборки контейнеров через docker-compose:

vi docker-compose.yml

---

version: "3.8"

services:

  web_server:
    build:
      context: ./web-server/
      args:
        buildno: 1
    container_name: web_server
    restart: always
    ports:
      - 80:80

  maria_db:
    image: mariadb
    container_name: maria_db
    restart: always
    volumes:
      - /var/lib/docker/volumes/mariadb/_data/:/var/lib/mysql

* в формате yml очень важное значение имеют отступы. Если сделать лишний пробел, то мы получим ошибку.
* где:

  • version — версия файла yml. На странице docs.docker.com представлена таблица, позволяющая понять, какую версию лучше использовать, в зависимости от версии docker (docker -v).
  • services — docker-compose оперирует сервисами, где для каждого создается свой блок описания. Все эти блоки входят в раздел services.
  • build — опции сборки. В нашем примере для веб-сервера мы должны собрать имидж.
  • context — указываем путь до Dockerfile.
  • args — позволяет задать аргументы, которые доступны только в процессе сборки. В данном примере мы используем только аргумент с указанием номера сборки.
  • container_name — задаем имя, которое будет задано контейнеру после его запуска.
  • restart — режим перезапуска. В нашем случае всегда, таким образом, после перезагрузки сервера, наши контейнеры запустятся.
  • ports — при необходимости, указываем порт, который будет наш сервер пробрасывать запрос внутрь контейнера.
  • volumes — позволяет внутрь контейнера прокинуть каталог сервера. Таким образом, важные данные не будут являться частью контейнера и не будут удалены после его остановки.

Запускаем сборку наших контейнеров с помощью docker-compose:

docker-compose build

Запускаем контейнеры в режиме демона:

docker-compose up -d

Проверяем, какие контейнеры запущены:

docker ps

Настройка 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, заданный в файле конфигурации пула работает:

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