Найти в Дзене
Ты в АйТи

Устанавливаем LEMP на Raspberry Pi используя Docker Compose

В одном из предыдущих постов мы установили Docker на Raspberry Pi OS В этой статье мы сделаем из нашей Raspberry Pi веб-сервер используя docker контейнеры. Мы установим: Docker рекомендует запускать только 1 процесс на контейнер, пользуясь этой рекомендацией мы постараемся не запускать больше одного приложения в одном контейнере. Это довольно просто. Итак, приступим. Используем Docker Compose. Docker Compose позволяет определять и запускать многоконтейнерные приложения Docker, а ведь мы собираемся установить 4 контейнера, поэтому использование docker compose значительно облегчит этот процесс. Чем же конкретно нам поможет Docker Compose: Устанавливаем Nginx, PHP, MariaDB Для этого создаем в текстовом редакторе файл docker-compose.yml следующего содержания: Ключ version в верхней части файла указывает на версию Docker Compose, которую мы собираемся использовать (3.8 — последняя версия на момент написания статьи). За ним следует ключ services, который представляет собой список компонентов
Оглавление

В одном из предыдущих постов мы установили Docker на Raspberry Pi OS

В этой статье мы сделаем из нашей Raspberry Pi веб-сервер используя docker контейнеры.

Мы установим:

  1. Nginx
  2. PHP-FPM
  3. MariaDB
  4. phpMyAdmin

Docker рекомендует запускать только 1 процесс на контейнер, пользуясь этой рекомендацией мы постараемся не запускать больше одного приложения в одном контейнере.

Это довольно просто. Итак, приступим.

Используем Docker Compose.

Docker Compose позволяет определять и запускать многоконтейнерные приложения Docker, а ведь мы собираемся установить 4 контейнера, поэтому использование docker compose значительно облегчит этот процесс.

Чем же конкретно нам поможет Docker Compose:

  • Мы опишем все необходимые нам контейнеры централизованно в одном конфигурационном файле YAML;
  • Docker Compose позаботится о сборке и запуске контейнеров;
  • Контейнеры будут автоматически подключены к внутренней сети.

Устанавливаем Nginx, PHP, MariaDB

Для этого создаем в текстовом редакторе файл docker-compose.yml следующего содержания:

LEMP for Raspberry Pi 3 on Raspberry Pi OS

Ключ version в верхней части файла указывает на версию Docker Compose, которую мы собираемся использовать (3.8 — последняя версия на момент написания статьи).

За ним следует ключ services, который представляет собой список компонентов приложения.

Ключ image указывают какой образ использовать для создания контейнера. Он будет загружен из Docker Hub. Docker Hub это крупнейшее хранилище образов.

Лучше не указывать версию образа latest чтобы избежать в дальнейшем проблем из-за проблем совместимости новых версий со старыми и пр. Лучше указать конкретный номер версии.

Ключ ports и запись 80:80 указывает на то, что мы хотим сопоставить порт 80 нашей локальной машины (используемый HTTP) с портом контейнера. Другими словами, когда мы будем обращаться к порту 80 на нашей локальной машине (т. е. на вашем компьютере), мы будем перенаправлены на порт 80 контейнера Nginx.

Далее рассмотрим сервис PHP-FPM

Cекция volumes, которая встречается нам при описании PHP-FPM и nginx позволяет нам определить тома (в основном, каталоги или отдельные файлы), которые мы хотим подключить к контейнеру. По сути, это означает, что мы можем сопоставить локальные каталоги и файлы с каталогами и файлами внутри контейнера; в нашем случае мы хотим, чтобы Docker Compose смонтировал папку src как папку /var/www/php контейнера.

Что находится в папке src/? Пока ничего, но именно туда мы поместим код нашего приложения. Как только он будет установлен в контейнер, любое изменение, которое мы внесем в наш код, будет сразу же доступно, без необходимости перезапускать контейнер.

Создайте каталог src (на том же уровне, что и docker-compose.yml) и добавьте в него следующий файл index.php:

test file index.php for testing LEMP

Вернемся к сервису Nginx: мы добавили в него секцию volumes, в которой смонтировали каталог с нашим кодом, как и в случае с сервисом PHP (это делается для того, чтобы Nginx получил копию index.php, без которой он вернет 404 Not Found при попытке доступа к файлу), и на этот раз мы также хотим импортировать конфигурацию сервера Nginx, которая будет указывать на код нашего приложения:

- ./.docker/nginx/conf.d:/etc/nginx/conf.d

Поскольку Nginx автоматически читает файлы, заканчивающиеся на .conf, расположенные в каталоге /etc/nginx/conf.d, смонтировав вместо него наш собственный локальный каталог conf.d, мы убедимся, что содержащиеся в нем файлы конфигурации будут обработаны Nginx внутри контейнера.

Создайте папку .docker/nginx/conf.d и добавьте в нее следующий файл php.conf:

Минималистская конфигурация сервера PHP-FPM

Это минималистская конфигурация сервера PHP-FPM, позаимствованная с сайта Linode, в которой нет ничего особенного; просто обратите внимание, что мы указываем корневой каталог /var/www/php, в который мы монтируем код нашего приложения в контейнерах Nginx и PHP, и что мы устанавливаем главную страницу как index.php.

Следующая строка также интересна:

fastcgi_pass php:9000;

Она указывает Nginx перенаправлять запросы к файлам PHP на порт 9000 контейнера PHP, который по умолчанию прослушивает PHP-FPM. Внутри Docker Compose автоматически преобразует ключевое слово php в частный IP-адрес, который он назначил контейнеру PHP.

Это ещё одна замечательная особенность Docker Compose: при запуске он автоматически создает внутреннюю сеть, в которой каждый контейнер можно обнаружить по имени его сервиса.

Наконец, давайте посмотрим на последний раздел конфигурации сервиса Nginx:

depends_on:
- php

Иногда порядок, в котором Docker Compose запускает контейнеры, имеет значение. Поскольку мы хотим, чтобы Nginx перенаправлял PHP-запросы на порт 9000 контейнера PHP, то нам необходимо, чтобы PHP был запущен раньше и был бы готов принимать запросы раньше, чем запустился бы Nginx. Строка указанная выше как раз указывает, что Nginx зависит от PHP.

Иначе, если бы этой строки не было могла бы возникнуть ошибка, которая привела бы к остановке процесса Nginx, а поскольку контейнер Nginx будет работать только до тех пор, пока работает процесс Nginx, контейнер также останавливается. Секция depends_on гарантирует, что контейнер PHP будет запущен раньше контейнера Nginx, что избавляет нас от неловкой ситуации.

Мы уже знакомы с ключом depends_on: мы указываем, что новый сервис MySQL должен быть запущен до PHP.

Ключ condition;

Если говорить о сервисе php, то в нашем случае, для того, чтобы развернуть php мы используем секцию build, а не image. Это нужно для того, чтобы дополнить наш образ php дополнительным плагином, который нам обязательно нужен для связи с базой данных, но которого по-умолчанию нет в стандартном образе докер хаба. Говоря проще секция image скачала бы нам с докер хаба не готовый образ, но без плагина, потому мы используем секцию build, которая обращается к докер-файлу и на его основе подготавливает образ для дальнейшего использования.

Вместо того чтобы использовать официальный образ PHP как есть, мы говорим Docker Compose использовать Dockerfile из .docker/php для сборки нового образа.

Dockerfile — это как рецепт сборки образа: он есть у каждого образа, даже у официального (например, у Nginx).

Создайте папку .docker/php и добавьте в нее файл с именем Dockerfile со следующим содержимым:

-2
Dockerfile for PHP with mysql (mariadb) plugin

Для чтения из базы данных MySQL PHP необходимо расширение pdo_mysql. Хотя оно не входит в официальный образ, описание Docker Hub содержит некоторые инструкции по простой установке расширений PHP. В верхней части нашего Dockerfile мы указываем, что стартуем с официального образа, и переходим к установке pdo_mysql с помощью команды RUN. И это всё! В следующий раз, когда мы запустим наши контейнеры, Docker Compose подхватит изменения и соберет новый образ на основе рецепта, который мы ему дали.

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

Теперь давайте подробнее рассмотрим сервис MySQL в docker-compose.yml

-3

Ключ image указывает на образ MariaDB для версии 10.6-alpine, а за ним следует секция, с которой мы ещё не сталкивались: environment. Она содержит ключи — MARIADB_ROOT_PASSWORD, MARIADB_ROOT_HOST MARIADB_DATABASE ALLOW_EMPTY_PASSWORD и MARIADB_USER— которые являются переменными окружения, то есть будут установлены в контейнере при его создании. Они позволяют нам установить пароль root, разрешить подключения с любого IP-адреса, создать базу данных по умолчанию соответственно.

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

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

Создайте папку .docker/mysql и добавьте в нее следующий файл my.cnf:

Conf file for MySQL and MariaDB for character set
-4

Теперь для тех, кто возможно ставит php8:

-5

Второй том выглядит несколько иначе, чем те, что мы видели до сих пор: вместо указания на локальную папку он ссылается на именованный том, определенный в совершенно новой секции volumes, которая находится на одном уровне с секцией services:

-6

Нам нужен такой том, потому что без него каждый раз, когда контейнер сервиса mariadb уничтожается, база данных уничтожается вместе с ним. Чтобы сделать её постоянной, мы просто говорим контейнеру MariaDB использовать том mariadb для локального хранения данных, причем по умолчанию используется драйвер local (как и сети, тома поставляются с различными драйверами и опциями, о которых вы можете узнать здесь). В результате к контейнеру монтируется локальный каталог, с той лишь разницей, что вместо того, чтобы указывать, какой именно, мы позволяем Docker Compose выбрать место.

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

Вот для чего нужны эти строки в описании сервиса PHP:

-7

По умолчанию depends_on будет просто ждать запуска ссылаемых контейнеров, если мы не укажем иное. Однако эта проверка работоспособности может не сработать с первой попытки, поэтому мы настроили её на повторение попыток каждые 5 секунд до 10 раз, используя ключи interval и retries соответственно.

Сама проверка работоспособности использует mariadb-admin, утилиту администрирования сервера MariaDB, для пинга сервера до получения ответа. Для этого используются пользователь root и значение переменной окружения MYSQL_ROOT_PASSWORD в качестве пароля (в нашем случае это тоже root).

-8

Осталось рассмотреть установку phpMyAdmin.

Когда дело доходит до работы с базой данных MySQL, phpMyAdmin остается популярным выбором; удобно, что они предоставляют образ Docker, который довольно прост в настройке.

Вот секция конфигурации phpMyAdmin из нашего файла конфигурации:

-9

Мы начинаем с версии 5.2.1 образа и сопоставляем порт 8080 локальной машины с портом 80 контейнера. Мы указываем, что контейнер MariaDB должен быть запущен и готов первым с помощью depends_on, и задаем хост, к которому должен подключиться phpMyAdmin с помощью переменной окружения PMA_HOST (помните, что Docker Compose автоматически разрешит mysql в частный IP-адрес, который он назначил контейнеру).

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

-10
  • Папка TehMarket в данном случае это корневая папка в ней лежит docker-compose. yml и, находясь именно в ней мы запускаем команду docker compose up -d
  • В папке .docker/mariadb должен лежать файл my.cnf
  • В папке .docker/nginx/conf.d должен лежать файл php.conf
  • В папке .docker/php должен лежать файл Docerfile
  • В папке src должен лежать файл index.php

Перейдите в папку с файлом docker-compose.yml Запустите docker compose up -d.

Образы будут загружены и собраны, после чего, когда всё будет готово, зайдите с вашего ПК на вашу Raspberri Pi по IP адресу, а затем по IP адресу и порту 8080 например:

  • 192.168.0.101 - Должна загрузиться картинка GIF, информация о базе данных демо и о её таблицах и конфигурация вашего PHP
  • 192.168.0.101:8080 - Должен загрузиться phpMyAdmin

В phpMyAdmin введите root / root в качестве имени пользователя и пароля, создайте пару таблиц в базе данных demo и обновите 192.168.0.101, чтобы убедиться, что они правильно указаны. Затем перезапустите контейнеры и убедитесь, что таблицы после перезапуска успешно сохранились в базе.

И всё! Это было легко, правда?

Команды управления Docker

1. Собирать, конфигурировать и запускать контейнеры описанные в файле docker-compose можно командой:

docker compose up -d

Если мы не будем использовать ключ -d то мы будем видеть всю внутреннюю работу нашего веб сервера, при поступлении на него запросов, и как только мы закроем процесс клавишами ctrl+c, то сервер остановится.

docker compose up

2. Чтобы увидеть какие контейнеры запущены в данный момент, надо после команды docker compose up -d выполнить команду:

docker compose ps

3. Для остановки контейнеров просто выполните следующую команду:

$ docker compose stop

4. Еще из интересных команд, которые могут потребоваться стоит отметить команду исполнения в контейнере, так, например, для того чтобы открыть терминал bash в контейнере php докера, надо выполнить такую команду:

$ docker compose exec php bash

Выполняя эту команду, мы просим Docker Compose выполнить Bash в контейнере PHP. Вы должны получить новое приглашение, указывающее, что в настоящее время вы находитесь в каталоге /var/www/php: именно для этого предназначен ключ working_directory, с которым мы столкнулись ранее. Выполните команду ls для просмотра содержимого каталога: вы должны увидеть index.php, что вполне ожидаемо, поскольку мы смонтировали нашу локальную папку src в папку /var/www/php контейнера.

Выполните exit для выхода из контейнера.

5. Следующая полезная команда

$ docker compose logs -f

собирает логи всех контейнеров, что чрезвычайно полезно для отладки: если что-то идёт не так, первым вашим рефлексом всегда будет просмотр логов. Также можно вывести информацию о конкретном контейнере, просто добавив имя сервиса (например, docker compose logs -f nginx).

Нажмите ctrl+c, чтобы вернуть терминал обратно.

6. перезапуск всех контейнеров

$ docker compose restart

7. Остановка и/или уничтожение контейнеров

$ docker compose down

8. Остановка и/или уничтожение контейнеров и их томов (включая именованные тома)

$ docker compose down -v

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

$ docker compose down -v --rmi all --remove-orphans

Неиспользуемые контейнеры — это оставленные контейнеры, которые раньше соответствовали сервису Docker Compose, но теперь ни к чему не подключены, что иногда случается во время создания вашей установки Docker.