Працюють у короткій feature-гілці від main, підтягують чужі зміни через rebase локально, у main вливають через pull request і merge, а втрачені після rebase чи force push коміти дістають із git reflog.
Питання на співбесіду з DevOps для PHP
Питання про інфраструктуру PHP-застосунків: Docker і шари образу, кеш білду, CI-пайплайни, деплой без простою, логи й моніторинг, змінні середовища та секрети.
composer.json описує допустимі діапазони версій, composer.lock фіксує точні версії, які реально встановлені; install ставить строго з lock і дає однакові залежності всюди, update перераховує діапазони й переписує lock.
Compose описує сервіси локального стенду: PHP (php-fpm поруч з nginx або один контейнер FrankenPHP), база, кеш; код заходить через bind mount, а vendor і дані БД живуть у named volumes, бо саме bind mount повільний на macOS та Windows; Xdebug ставлять в образ, але тримають у режимі off і вмикають змінною XDEBUG_MODE на час сесії.
nginx сам PHP не виконує: він упаковує запит у FastCGI-записи й віддає їх у сокет пулу PHP-FPM, де вільний воркер виконує скрипт із `SCRIPT_FILENAME`. Маршрутизацію задає `try_files`, пропускну здатність - `pm` і `pm.max_children`, який вважають від реально вільної памʼяті, а видимість проблем дають `slowlog` і `request_terminate_timeout`.
Multi-stage: у білдерах Composer і збірка ассетів, у фінальному образі лише runtime, vendor без dev-залежностей і код; шари впорядковані так, щоб зміна коду не інвалідувала шар із залежностями.
Новий реліз збирається і прогрівається в окремій теці, трафік перемикається однією атомарною заміною симлінка (або поступовою заміною контейнерів за readiness-пробою), після чого скидаються realpath cache й OPcache і перезапускаються воркери; відкат - та сама операція у зворотний бік.
Воркер - це звичайний PHP-процес, який рано чи пізно завершиться, тому поруч має бути менеджер процесів: supervisor із `autorestart=true` і `numprocs`, systemd-юніт із `Restart=always` або сам оркестратор контейнерів. Ключове налаштування - час очікування після SIGTERM (`stopwaitsecs`, `TimeoutStopSec`), більший за найдовшу задачу.
Конфігурація приходить у процес через змінні оточення й відрізняється по середовищах, код лишається однаковим; .env — це локальна зручність розробника, яку не комітять, а на продакшені значення дає pool php-fpm, оркестратор або менеджер секретів. У Laravel env() дозволений лише у файлах config/, бо після config:cache .env не завантажується взагалі.
Встановлення залежностей з кешем, перевірка стилю, статичний аналіз, тести на реальній базі й збірка артефакту; швидкі кроки першими, щоб пайплайн падав рано.
Логи пишемо структурованим JSON у stdout одним рядком на подію й віддаємо збирачу, помилки дублюємо в Sentry, де вони групуються за fingerprint і мають реліз та контекст, а сигналом «щось не так» служать не логи, а метрики RED (rate, errors, duration) з алертами на симптоми, які бачить користувач.
Треба винести назовні весь стан, який зараз лежить на локальному диску чи в памʼяті процесу: сесії — у Redis/БД, завантажені файли — в обʼєктне сховище, кеш і локи — у спільний Redis, черги й планувальник — в окремі процеси з дедуплікацією; липкі сесії це не рішення, а спосіб не помітити проблему.
Схема змінюється у фази expand і contract: спершу зміни, сумісні зі старим кодом, потім деплой коду, який працює з обома варіантами, і лише після повного викочування прибирання старого.
Три сигнали налаштовують як один набір даних, зшитий спільним trace_id: OpenTelemetry дає trace через PECL-розширення й auto-instrumentation, той самий trace_id підмішується процесором у кожен запис структурованого лога, а метрики через shared-nothing модель PHP збирає не сам процес, а локальний Collector; алерти вішають лише на SLI з бюджетом помилок, решта живе на дашборді.
Від PHP-розробника не чекають рівня SRE, достатньо розуміти, що відбувається при білді й деплої. Питання переважно практичні: чому образ важить 1.2 ГБ і чому кеш злітає на кожному коміті.