Каждая кнопка в разделе «Сервис» просто запускает shell-скрипт из
директории /tools внутри контейнера. Ничто не мешает запускать те же
скрипты снаружи — командой docker exec с хоста. Это открывает несколько
полезных сценариев: обновление библиотеки по расписанию без участия человека,
восстановление после сбоев, когда веб-интерфейс недоступен, и доступ к базе
через psql без установки клиента на хост.
Как правильно вызывать: docker exec -u www-data
docker exec -u www-data flibusta-fpm /tools/update_daily.sh
Ключевой момент — -u www-data. Внутри контейнера php-fpm работает от
пользователя www-data (uid 82), и всё в /cache и /sql принадлежит ему.
Если запустить скрипт от root (а docker exec по умолчанию делает именно
так), созданные им файлы — скачанные дампы, обложки, файлы блокировок,
лог — окажутся с владельцем root, и потом PHP не сможет их перезаписать.
Симптомы такой ошибки разнообразны и неочевидны («Скачать базу» молча не
обновляет файлы, обложки перестали кэшироваться), поэтому лучше сразу взять
за правило: любой docker exec для библиотеки — с -u www-data.
Если это всё-таки случилось, вылечить просто: перезапуск контейнера
(docker restart flibusta-fpm) — скрипт входа выполняет
chown -R www-data /cache /sql при каждом старте.
Имя контейнера flibusta-fpm задано в container_name шаблона. В
устаревшей конфигурации all-in-one контейнер называется
<проект>-php-fpm-1; уточнить можно через docker ps.
Переменные окружения (FLIBUSTA_URL, параметры БД, пути к секретам)
docker exec наследует от контейнера, поэтому скрипты работают ровно так
же, как из веб-интерфейса.
Какие скрипты есть
| Скрипт | Кнопка в «Сервисе» | Блокировки | Примечания |
|---|---|---|---|
/tools/getsql.sh |
Скачать базу данных | admin | пропускает файлы с неизменившимся ETag |
/tools/app_import_sql.sh |
Обновить базу данных | admin + db | библиотека в режиме техобслуживания на время выполнения |
/tools/getcovers.sh |
Скачать обложки | admin | проверяет скачанные архивы через unzip -t |
/tools/update_daily.sh |
Скачать последние обновления | admin | кладёт архивы в /cache/local; чистит ETag-записи старше 90 дней |
/tools/app_reindex.sh |
Сканирование ZIP | admin + db | быстрый: читает только имена файлов |
/tools/add_torrent_books.sh <tmpdir> <magnet или .torrent> |
Добавить книги из торрента | admin | tmpdir нужно создать самому в /cache/tmp |
php /tools/merge_local_books.php |
(часть импорта) | — | переносит добавленные вручную книги обратно после импорта |
php /tools/update_zip_list.php |
(часть сканирования) | — | сам индексатор: заполняет таблицу book_zip и файл /cache/zip_index.php, без блокировок |
php /tools/build_zip_index.php |
— | — | собирает /cache/zip_index.php из таблицы book_zip, если файла нет; запускается при старте контейнера. С ключом --force перестроит существующий |
php /tools/cache_bump.php |
(часть импорта и сканирования) | — | сбрасывает кэш описаний книг в Redis. Без Redis — ничего не делает и завершается успешно |
«admin» — общая блокировка операций (/cache/locks/adminop.lock): второй
скрипт одновременно не запустится и завершится с сообщением failed to obtain admin op lock. «db» — блокировка БД (/cache/locks/dbupdate.lock): пока
она удерживается, веб-интерфейс показывает страницу техобслуживания. Обе
блокировки — flock, снимаются автоматически при завершении процесса, в том
числе аварийном.
Скрипты пишут ход выполнения в stdout (по-русски, это то, что видно в веб-интерфейсе) и служебные отметки в stderr.
Показывать ход выполнения в веб-интерфейсе
Веб-интерфейс определяет «идёт операция» по блокировке, а текст берёт из
файла /cache/status. Если скрипт запущен через docker exec, страница
«Сервис» покажет спиннер, но с текстом предыдущей операции. Чтобы
администратор в браузере видел актуальный вывод, перенаправьте stdout в тот
же файл:
docker exec -u www-data flibusta-fpm sh -c '/tools/update_daily.sh > /cache/status 2>&1'
Обёртка sh -c нужна, чтобы перенаправление выполнилось внутри контейнера,
а не на хосте. stdbuf -o0 в веб-интерфейсе добавлен ради построчного вывода
без буферизации; для cron это не принципиально.
Пример: обновление библиотеки по cron
Самый востребованный сценарий. Флибуста выкладывает ежедневные добавления в
/daily/, а полный дамп базы обновляется раз в несколько дней. Разумный
график: каждую ночь — обновления и пересканирование, раз в неделю — свежий
дамп и импорт.
Откройте crontab пользователя, у которого есть право на docker (root или
член группы docker):
sudo crontab -e
# Flibusta-at-home: ежедневные обновления и пересканирование архивов, 04:10
10 4 * * * docker exec -u www-data flibusta-fpm sh -c '/tools/update_daily.sh > /cache/status 2>&1 && /tools/app_reindex.sh >> /cache/status 2>&1'
# Flibusta-at-home: свежий дамп БД и полный импорт, понедельник 03:00
0 3 * * 1 docker exec -u www-data flibusta-fpm sh -c '/tools/getsql.sh > /cache/status 2>&1 && /tools/app_import_sql.sh >> /cache/status 2>&1'
# Flibusta-at-home: обложки, первое число месяца
30 3 1 * * docker exec -u www-data flibusta-fpm sh -c '/tools/getcovers.sh > /cache/status 2>&1'
Несколько замечаний:
&&между скриптами гарантирует, что импорт не начнётся, если скачивание завершилось с ошибкой. Скрипты завершаются ненулевым кодом при невозможности взять блокировку, так что случайное наложение на операцию, запущенную из браузера, просто отменит cron-задание, а не сломает что-то.- Импорт переводит библиотеку в режим техобслуживания на минуты или десятки минут (зависит от диска и процессора). Ставьте его на время, когда никто не читает.
- Время в cron — часовой пояс хоста, а не контейнера.
- Вывод cron-задания уходит в
/cache/statusи виден в «Сервисе» как «лог последней операции». Если хочется получать письма об ошибках, уберите перенаправление2>&1— stderr тогда пойдёт в почту cron.
Если на хосте systemd и хочется видеть историю запусков в journalctl, тот
же вызов оформляется как .service + .timer; содержательно ничего не
меняется.
Пример: восстановление, когда веб-интерфейс недоступен
Реальный случай: импорт прерван перезапуском хоста посреди операции. Таблицы могут оказаться частично заполненными, библиотека — в странном состоянии. Лечится повторным полным импортом с консоли:
docker exec -u www-data flibusta-fpm sh -c '/tools/app_import_sql.sh > /cache/status 2>&1'
docker exec -u www-data flibusta-fpm tail -f /cache/log/dbupdate.log
Дампы уже лежат в /sql, скачивать заново не нужно (если .gz уже
распакованы, gzip пожалуется, но импорт продолжится — это не ошибка).
Пример: psql к базе библиотеки
В образе есть клиент Postgres, а скрипт dbinit.sh умеет собрать строку
подключения из переменных окружения и секрета с паролем:
docker exec -it -u www-data flibusta-fpm sh -c '. /tools/dbinit.sh; $SQL_CMD'
Дальше — обычный psql. Пара запросов, которые бывают полезны:
-- кто есть в библиотеке
SELECT id, username, is_admin, created_at FROM users ORDER BY id;
-- неудачные попытки входа за сутки
SELECT attempt_time, ip_address, username, outcome
FROM login_attempts WHERE outcome > 0 AND attempt_time > now() - interval '1 day'
ORDER BY attempt_time DESC;
-- какие архивы и диапазоны id знает библиотека
SELECT filename, start_id, end_id, usr FROM book_zip ORDER BY usr, start_id;
Сменить пароль пользователя из psql нельзя без вычисления bcrypt-хэша, но
можно сделать это в одну строку через PHP из того же контейнера:
docker exec -u www-data flibusta-fpm sh -c \
'. /tools/dbinit.sh; H=$(php -r "echo password_hash(\"НовыйПароль\", PASSWORD_DEFAULT);"); \
$SQL_CMD -c "UPDATE users SET password_hash='"'"'$H'"'"' WHERE username='"'"'reader'"'"'"'
(Вложенные кавычки выглядят устрашающе, но проще, чем ставить PHP на хост.
Для администратора есть более простой путь — через FLIBUSTA_APP_ADMIN, см.
переменные окружения.)
Где смотреть логи
| Что | Где |
|---|---|
лог контейнера (старт, инициализация БД, ошибки PHP через error_log) |
docker logs flibusta-fpm |
| импорт дампа | /cache/log/dbupdate.log |
| индексация архивов | /cache/log/update_zip_list.log |
| миграции схемы при старте | /cache/log/postgres_migration.log |
| последняя операция из «Сервиса» или cron | /cache/status |
| неудачные попытки входа | /cache/login_attempts/flibusta_login_attempts.log |
| доступ и ошибки nginx | у reverse proxy; в шаблонах — flibusta.access.log и flibusta.error.log |
Всё, что в /cache, доступно и с хоста по пути смонтированной директории —
docker exec для чтения логов не обязателен.
Диагностика: сколько запросов к базе делает страница
Переменная окружения FLIBUSTA_DEBUG_DB=true добавляет в лог контейнера по
строке на каждый запрос:
docker logs -f flibusta-fpm | grep dbstats
dbstats /fb2.php?id=123 connected=0 statements=0
dbstats /book/view/123 connected=1 statements=4
connected показывает, открывалось ли вообще соединение с Postgres,
statements — сколько запросов выполнено. Полезно, чтобы убедиться, что кэш
работает, или найти страницу, которая внезапно стала делать слишком много
запросов. Подробности — в
статье о кэше и производительности.
В обычной работе переменную держите выключенной: она пишет строку на каждый запрос, включая каждую картинку.