Коротко
Обновление пакетов на хост-системе не трогает PHP внутри контейнера. Нужно взять свежий базовый образ, пересобрать свой и перезапустить контейнеры. Проверять версию следует внутри контейнера, а не на хосте.
Шаг 1. Понять, что у вас внутри
docker ps --format '{{.Names}}\t{{.Image}}'
docker exec -it имя_контейнера php -v
docker exec -it имя_контейнера sh -c 'dpkg -l | grep php || rpm -q php-cli'Официальные образы PHP собраны из исходников, поэтому номер версии там честный: 8.3.36 и новее — исправлено, 8.3.35 и старше — нет.
Шаг 2. Обновить базовый образ
Если в Dockerfile закреплён точный тег, поднимите его до исправленной версии:
FROM php:8.3.36-fpm-bookwormЕсли тег плавающий (php:8.3-fpm), достаточно скачать образ заново:
docker pull php:8.3-fpm
docker compose build --pull --no-cache
docker compose up -dФлаг --pull здесь ключевой: без него сборка возьмёт старый слой из локального кэша, и уязвимость останется.
Шаг 3. Проверить результат
docker compose exec php php -v
docker compose exec php php -r 'echo PHP_VERSION, PHP_EOL;'Версия должна быть не ниже 8.3.36 для ветки 8.3, 8.4.27 для 8.4, 8.5.12 для 8.5, 8.2.35 для 8.2.
Шаг 4. Убедиться, что старые контейнеры не работают
Частая ошибка: образ обновлён, а рядом крутится контейнер, запущенный неделю назад.
docker ps --format '{{.Names}}\t{{.Image}}\t{{.CreatedAt}}'Если контейнер создан раньше, чем вы пересобрали образ, пересоздайте его.
Чтобы не повторилось
- Закрепляйте точные теги версий — так видно, что именно развёрнуто.
- Пересобирайте образы по расписанию, а не только при правке кода: базовый образ стареет сам по себе.
- Добавьте в конвейер проверку уязвимостей образа:
docker scout cves имя_образаилиtrivy image имя_образа.
Частые вопросы
Нужно ли обновлять PHP на хосте, если всё в контейнерах?
Если на хосте PHP не используется — нет. Но проверьте: утилиты вроде composer или скрипты cron могли притащить системный PHP.
Образ на Alpine тоже уязвим?
Да, уязвим сам код PHP, а не дистрибутив. Обновлять нужно так же.
Как быстро проверить весь парк контейнеров?
for c in $(docker ps -q); do printf '%s ' "$(docker inspect -f '{{.Name}}' $c)"; docker exec $c php -v 2>/dev/null | head -1 || echo 'без php'; done