Після security-оновлення легко отримати новий Docker-образ, перевірити в ньому потрібну версію PHP і вирішити, що проблема закрита.
Але Docker Compose запускає не абстрактно "найновіший образ". Він використовує конфігурацію, яка вийшла після об’єднання Compose-файлів, змінних середовища, image, build та override.
У моєму локальному Laradock це стало окремою частиною перевірки: після підготовки виправлених PHP-FPM, workspace і phpMyAdmin образів потрібно було довести, що наступний запуск не поверне старі image references.
Новий образ і фактична Compose-модель - це різні речі
Docker image може вже існувати локально і навіть успішно пройти перевірки. Це ще не означає, що сервіс описаний у Compose саме через цей image reference.
Сервіс може мати старий image:, залишений build:, інший override або запускатися через іншу комбінацію -f файлів.
Тому після підготовки нового образу я перевіряю не тільки сам image, а й те, що Docker Compose реально бачить після злиття конфігурації.
Спочатку перевіряємо, що Compose-конфігурація валідна
cd ~/Projects/laradock || exit 1 docker compose config -qdocker compose config -q не запускає контейнери. Він перевіряє, чи може Docker Compose зібрати конфігурацію без синтаксичних і частини структурних помилок.
Для security-зміни це важливий перший guard: якщо override написаний неправильно, немає сенсу переходити до recreate контейнерів.
Дивимося, які образи Compose справді збирається використовувати
cd ~/Projects/laradock || exit 1 docker compose config --imagesЦя команда значно корисніша за простий docker image ls, коли потрібно відповісти на запитання: "Що саме Compose планує використати?"
docker image ls показує, що є локально. docker compose config --images показує image references, які вийшли з Compose-моделі.
Якщо оновлений образ є локально, але його немає в результаті config --images, він сам по собі нічого не виправляє.
Якщо використовуються кілька Compose-файлів, перевіряємо саме їхню комбінацію
Найнебезпечніша помилка тут - перевірити один Compose-файл, а запускати середовище іншою командою.
Якщо Laradock використовує базовий файл і кілька override, усі перевірки повинні повторювати той самий набір -f, який буде використано для наступного запуску.
docker compose \ -f docker-compose.yml \ -f docker-compose.override.yml \ -f docker-compose.local.yml \ -f docker-compose.security-php.yml \ config -q docker compose \ -f docker-compose.yml \ -f docker-compose.override.yml \ -f docker-compose.local.yml \ -f docker-compose.security-php.yml \ config --imagesImage tag недостатньо: фіксуємо immutable image ID
Tag зручний для людини, але він не є незмінною ідентичністю образу. Сьогодні my-php:8.5-secure може вказувати на один image ID, а після rebuild той самий tag уже вказуватиме на інший.
Тому під час контрольованого security-оновлення я фіксую і tag, і immutable image ID.
docker image inspect \ --format '{{.RepoTags}} | id={{.Id}}' \ my-php:8.5-secureПеревіряємо, який image ID реально використовує контейнер
docker inspect \ --format 'name={{.Name}} image={{.Config.Image}} image_id={{.Image}} state={{.State.Status}}' \ laradock-php-fpm-85-1Тут важливо порівняти три речі:
- який image reference дає
docker compose config --images; - на який image ID зараз вказує цей tag;
- який image ID реально має контейнер.
Лише збіг цих даних дає зрозумілу картину поточного стану.
Чому build може знову змінити результат
Навіть якщо image: уже вказує на потрібний образ, активний build: може змінити поведінку наступної команди залежно від способу запуску.
У моєму випадку безпечний override був навмисно побудований так, щоб для потрібних PHP-сервісів ефективна модель містила зафіксовані image references, а небажаний rebuild не повертав стару базу.
docker compose config \ | grep -nE '^[[:space:]]+(image|build):'Постійний override важливіший за одноразовий успішний запуск
Одноразово запустити контейнер на правильному image ID недостатньо. Якщо наступного дня звичайний docker compose up не підключить потрібний override, середовище може повернутися до старого image reference або знову піти в build.
Саме тому image pin має бути частиною повторюваної Compose-конфігурації, а не лише ручною командою під час аварійного оновлення.
Перевіряємо різницю до будь-якого recreate
Перед recreate я хочу бачити мінімальну очікувану зміну: для потрібних PHP-сервісів змінилися image references, а інші сервіси, порти, volumes і мережі залишилися без несподіваних змін.
Це хороший момент зберегти санітизований effective config до і після зміни та порівняти їх.
docker compose config --images \ | sort \ > /tmp/compose-images.after.txt cat /tmp/compose-images.after.txtЩо я перевіряю перед наступним запуском
Перед будь-яким mutating Compose-запуском у мене має бути відповідь на кілька конкретних запитань:
- чи валідний потрібний набір Compose-файлів;
- чи показує
config --imagesсаме оновлені image references; - чи відомі immutable image IDs цих образів;
- чи немає небажаного
build:для сервісів, які повинні використовувати готові images; - чи не змінює override unrelated ports, volumes або інші сервіси;
- чи буде наступна команда використовувати той самий набір
-fфайлів.
Безпечний Docker-образ не допомагає, якщо фактична Compose-конфігурація під час наступного запуску вибере інший образ.
Підсумок
У security-оновленні Docker важливо розділяти два факти: "я створила виправлений образ" і "Laradock гарантовано використає його". Це не одне й те саме.
Мій практичний висновок простий: після оновлення образів потрібно перевірити effective Compose-модель, image references, immutable image IDs і постійний override. І лише після цього переходити до контрольованого recreate контейнерів.
Наступна проблема, яку варто розібрати окремо: чому Docker Compose іноді піднімає більше сервісів, ніж очікуєш, навіть коли команда здається локальною і точковою.



