Під час відновлення локального Laradock після PHP security-оновлення один із контейнерів не запускався. На перший погляд це легко сприйняти як проблему проєкту: "Laravel зламався після оновлення".
Насправді причина була на іншому рівні. Workspace для PHP 8.3 намагався опублікувати порт 5173, але цей порт уже використовував інший процес на хості.
Цей випадок добре показує, чому Docker-помилку потрібно спочатку локалізувати, а вже потім робити висновки про Laravel.
Починаємо зі стану контейнера, а не з Laravel
Якщо контейнер не запустився, перше питання просте: який його фактичний стан після команди?
Не потрібно одразу запускати artisan, очищати кеш або змінювати application config. Спочатку перевіряємо Docker.
cd ~/Projects/laradock || exit 1 docker compose ps -a workspace docker ps -a \ --filter 'name=laradock-workspace' \ --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'У моєму випадку workspace для PHP 8.3 залишався неактивним, тоді як інші PHP-FPM і workspace 8.4/8.5 уже могли працювати.
Це одразу звужує діагностику: проблема не виглядає як загальна поломка всього Laradock або всіх PHP runtime.
Дивимося Docker error для конкретного контейнера
docker inspect \ --format 'status={{.State.Status}} exit={{.State.ExitCode}} error={{.State.Error}}' \ laradock-workspace-1.State.Error корисний саме для помилок, які виникають під час створення або запуску контейнера. Якщо Docker не зміг прив’язати published port, застосунок усередині контейнера міг навіть не дійти до запуску.
У такій ситуації Laravel ще не мав можливості "зламатися", тому що проблема сталася раніше, на рівні Docker runtime.
Перевіряємо, хто вже слухає порт 5173
sudo ss -H -ltnp \ '( sport = :5173 )'Якщо команда показує процес, який уже слухає 5173, причина конфлікту підтверджується на рівні хоста.
Далі важливо не завершувати цей процес автоматично. Спочатку потрібно зрозуміти, кому він належить і чи не використовує його інший локальний проєкт або активний dev server.
Перевіряємо published ports самого workspace
docker inspect \ --format '{{json .HostConfig.PortBindings}}' \ laradock-workspace-1Ця перевірка відповідає на друге запитання: чи контейнер узагалі намагається опублікувати той порт, який уже зайнятий.
Якщо Docker configuration містить host binding для 5173, а ss показує іншого слухача, це вже достатньо сильний доказ конфлікту портів.
Logs корисні, але вони не завжди є головним доказом
docker logs \ --tail 100 \ laradock-workspace-1 \ 2>&1Якщо контейнер не зміг стартувати ще на етапі port binding, application logs можуть бути порожніми або не містити причини.
Тому для такого класу помилок я більше довіряю комбінації docker inspect .State.Error, published port configuration і ss, ніж відсутності або наявності Laravel stack trace.
Окремо доводимо, що Laravel працює
Після того як конфлікт порту локалізований, Laravel потрібно перевірити окремо в уже робочому PHP-FPM контейнері. У моєму середовищі PHP-FPM 8.5 був активний і вже використовував виправлений PHP.
Для базової перевірки достатньо довести, що Composer platform check проходить і Laravel може завантажитися та показати свою версію.
cd ~/Projects/laradock || exit 1 docker compose exec -T php-fpm-85 \ php /var/www/icanup/vendor/composer/platform_check.php docker compose exec -T php-fpm-85 \ sh -lc 'cd /var/www/icanup && php artisan --version --no-ansi'Конфлікт порту і проблема Laravel мають різні ознаки
Для себе я розділяю ці два класи помилок так:
- Docker port conflict: контейнер не переходить у running,
.State.Errorвказує на bind або port allocation,ssпоказує іншого слухача, application logs можуть бути порожніми; - Laravel problem: контейнер уже працює, PHP виконується, але
artisan, HTTP-запит або application logs показують помилку самого застосунку.
Це не абсолютне правило для всіх випадків, але воно добре не дає змішувати два різні рівні системи.
Не повторюємо docker compose up навмання
Після першої помилки легко просто ще раз виконати docker compose up -d. У складному Laradock це погана звичка.
Попередня команда могла вже запустити інші залежності, а новий повтор ще раз змінить стан середовища. Спочатку потрібно подивитися, що реально працює після частково невдалої операції.
cd ~/Projects/laradock || exit 1 docker compose ps -a echoecho "===== RUNNING =====" docker ps \ --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'Мій порядок діагностики
Для подібної ситуації я використовую короткий порядок:
- перевіряю стан проблемного контейнера через
docker compose ps -a; - читаю
.State.Errorчерезdocker inspect; - перевіряю published ports контейнера;
- шукаю власника конфліктного порту через
ss; - дивлюся останні Docker logs, але не вважаю їх єдиним джерелом причини;
- окремо перевіряю Laravel у вже робочому PHP runtime;
- лише після цього вирішую, чи потрібно звільняти порт, змінювати конфігурацію або просто залишити цей workspace зупиненим.
Контейнер, який не зміг прив’язати порт, ще нічого не говорить про стан Laravel усередині іншого робочого PHP runtime.
Підсумок
У моєму випадку workspace PHP 8.3 не запускався через зайнятий 5173. Це була Docker-інфраструктурна проблема, а не доказ поломки Laravel.
Laravel окремо проходив базовий bootstrap у робочому PHP-FPM, інші PHP-сервіси працювали, а конфлікт локалізувався конкретним published port.
Головний висновок для мене: спочатку визначити рівень помилки. Docker, порт, PHP runtime і Laravel - це різні шари, і діагностувати їх потрібно окремо.



