Коли на одному комп’ютері або сервері працює лише один Docker-проєкт, оновлення PHP здається локальною задачею: змінити версію, перебудувати контейнер і перевірити застосунок.
Складність з’являється, коли поруч живе ще один проєкт, який усе ще залежить від іншої версії PHP.
Тоді головне питання вже не "як оновити PHP?", а "де саме проходить межа цього оновлення?"
Якщо межа нечітка, одна зміна в спільному Docker-оточенні може непомітно змінити середовище другого проєкту.
Версія PHP на хості не повинна визначати версію PHP проєкту
Одна з головних переваг Docker у тому, що застосунок може отримати власне середовище виконання.
Проєкт A може працювати на PHP 8.5, а проєкт B - на PHP 8.3, навіть якщо обидва запущені на одній машині.
Для цього команди, тести, Composer і службові процеси кожного проєкту повинні виконуватися всередині його контейнерів, а не випадково використовувати PHP з хоста.
# Hostphp -v # Project Adocker exec project-a-workspace php -v # Project Bdocker exec project-b-workspace php -vWorkspace-контейнер має належати конкретному проєкту
Найнебезпечніша ситуація виникає, коли кілька проєктів неявно покладаються на один і той самий workspace-контейнер.
Тоді оновлення PHP, Composer або системних пакетів для одного проєкту автоматично змінює інструменти другого.
Надійніша модель - окремий workspace для кожного проєкту або окремий сервіс для кожної потрібної версії PHP.
Project A workspace-85 php-fpm-85 Project B workspace-83 php-fpm-83 Shared machine != shared PHP runtimeІмена контейнерів і сервісів - це частина ізоляції
Зрозумілі імена потрібні не лише для зручності.
Коли в Docker одночасно є кілька PHP-FPM, workspace, Redis або Nginx-контейнерів, нечітка назва збільшує ризик запустити команду не там.
Ім’я повинно допомагати одразу побачити, до якого проєкту та версії середовища належить контейнер.
docker ps --format \ 'table {{.Names}}\t{{.Image}}\t{{.Status}}'Docker Compose project name теж має бути ізольованим
Навіть якщо Docker Compose-файли різні, однакові назви проєктів можуть призвести до неочікуваного перетину контейнерів, мереж або томів.
Тому кожне середовище повинно мати власний Compose project name і власні назви ресурсів там, де це потрібно.
docker compose \ -p project_a \ up -d docker compose \ -p project_b \ up -dІзоляція runtime не скасовує конфлікти портів
Два проєкти можуть мати окремі PHP-контейнери й усе одно конфліктувати на рівні хоста.
Наприклад, обидва Nginx-контейнери не можуть одночасно прив’язатися до одного й того самого порту хоста.
Те саме стосується Redis, MySQL, Reverb або інших сервісів, якщо їхні порти опубліковані назовні.
Тому під час зміни Docker-конфігурації варто перевіряти не лише версію PHP, а й фактичні прив’язки портів.
docker ps --format \ 'table {{.Names}}\t{{.Ports}}'Composer потрібно перевіряти в тому самому PHP, де працює застосунок
Composer перевіряє платформні вимоги відносно того PHP, яким він запущений.
Якщо composer install виконати на хості з PHP 8.5, а застосунок реально працює в контейнері з PHP 8.3, можна отримати залежності, які формально встановилися, але не сумісні з реальним runtime проєкту.
Тому Composer для конкретного проєкту варто запускати в його workspace-контейнері.
docker exec project-a-workspace \ composer check-platform-reqs docker exec project-b-workspace \ composer check-platform-reqsОбмеження PHP в composer.json має відображати реальний контракт проєкту
{ "require": { "php": "^8.5" }}Якщо один проєкт уже перейшов на PHP 8.5, це краще зафіксувати не лише в Dockerfile або змінній середовища, а і в Composer-вимогах.
Так несумісність стане видимою раніше: під час встановлення залежностей або перевірки платформи, а не після запуску застосунку.
Не варто ділити vendor між проєктами з різними runtime
Кожен проєкт повинен мати власний vendor і власний composer.lock.
Спільний каталог залежностей між двома застосунками з різними вимогами до PHP руйнує саму ідею ізоляції.
Оновлення одного набору пакетів тоді може змінити код, який завантажує інший проєкт.
Під час оновлення перебудовуйте лише цільові сервіси
docker compose build workspace php-fpm docker compose up -d \ workspace \ php-fpmЯкщо змінилася лише версія PHP, немає потреби бездумно перебудовувати всі сервіси.
Точкове оновлення зменшує площу зміни і спрощує перевірку: ми чітко знаємо, які контейнери повинні отримати новий runtime.
Після оновлення треба перевірити не лише новий runtime, а й сусідній проєкт
Якщо мета ізоляції - не вплинути на другий проєкт, це потрібно підтвердити перевіркою.
Після перебудови варто подивитися версії PHP в обох workspace-контейнерах, перевірити їхні PHP-FPM-сервіси й виконати короткий тест доступності обох застосунків.
Інакше ми перевіряємо лише половину обіцянки.
docker exec project-a-workspace php -vdocker exec project-b-workspace php -v docker exec project-a-workspace \ composer check-platform-reqs docker exec project-b-workspace \ composer check-platform-reqsСпільний .env для Docker-інфраструктури створює приховану зв’язаність
У деяких Docker-оточеннях версія PHP задається змінною у спільному .env.
Якщо два проєкти використовують один і той самий набір Docker-файлів і одну конфігурацію, зміна змінної для проєкту A може непомітно змінити майбутню перебудову проєкту B.
Тому конфігурація runtime теж повинна належати конкретному проєкту або конкретному профілю середовища.
Ізоляція PHP не повинна маскувати спільні залежності
Навіть якщо PHP runtime розділений, проєкти все ще можуть випадково ділити MySQL, Redis, мережу або том.
Це не обов’язково неправильно, але таке спільне використання має бути явним.
Особливо важливо уникати ситуації, де два проєкти використовують однакові назви баз, ключові простори Redis або томи через помилку конфігурації.
Безпечне оновлення одного проєкту має чітку послідовність
1. Зафіксувати поточні runtime обох проєктів.2. Перевірити Docker Compose project names.3. Перевірити імена контейнерів і порти.4. Змінити PHP лише в конфігурації цільового проєкту.5. Перебудувати лише його workspace/php-fpm.6. Перевірити php -v у цільовому контейнері.7. Виконати composer check-platform-reqs.8. Перевірити застосунок.9. Повторно перевірити сусідній проєкт.10. Переконатися, що його runtime не змінився.Оновлення версії і архітектура ізоляції - різні задачі
У окремій статті про безпечне оновлення PHP після критичних вразливостей я розбирала сам процес безпечного оновлення PHP.
Але в Docker-середовищі до нього додається ще одна вимога: зміна має залишитися всередині потрібного проєкту.
Тобто перевірити нову версію PHP недостатньо. Потрібно ще довести, що інші проєкти зберегли свої версії й свої залежності.
Що варто перевірити після оновлення
[ ] Цільовий workspace має нову версію PHP[ ] Сусідній workspace має стару очікувану версію PHP[ ] PHP-FPM обох проєктів працює[ ] Composer platform requirements проходять в обох проєктах[ ] Немає конфліктів портів[ ] Compose project names різні[ ] vendor не спільний[ ] Бази/Redis/volumes не перетнулися випадково[ ] Обидва застосунки відповідають після змінСправжня ізоляція перевіряється тим, що сусідній проєкт не змінився
Docker дозволяє тримати кілька версій PHP на одній машині, але сама наявність контейнерів ще не гарантує ізоляцію.
Межа повинна бути явною у runtime, workspace, Compose project name, портах, залежностях і конфігурації.
Після оновлення потрібно перевірити не лише те, що цільовий проєкт отримав нову версію, а й те, що сусідній проєкт залишився на своїй.
Найкращий доказ ізоляції - не тільки "новий контейнер працює", а й "інший контейнер не змінився".
Оновлення одного контейнерного проєкту вважається ізольованим лише тоді, коли інший проєкт після нього залишився в тому самому середовищі.



