# CI/CD: automatyczna przebudowa obrazów PHP

> Automatyczna przebudowa obrazów Docker: buildy według harmonogramu, kontrola wersji w pipeline i wdrożenie po digeście, by poprawki PHP docierały.

Źródło: https://phpsos.de/pl/blog/php-images-in-ci-neu-bauen/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**Krótko:** Obraz Docker zawiera PHP w stanie z chwili budowy i starzeje się nawet bez zmian w kodzie. Kto przebudowuje obrazy automatycznie, według harmonogramu i przy komunikatach bezpieczeństwa, sprawdza wersję PHP w pipeline i wdraża po digeście, wprowadza poprawki takie jak ta przeciw PHP2Shell na produkcję w sposób planowalny. Zielony build sam w sobie nie jest przy tym dowodem; liczy się wersja w działającym kontenerze.

## Dlaczego obrazy starzeją się bez zmian w kodzie

W wielu zespołach pipeline buildu startuje tylko wtedy, gdy ktoś zmieni kod. Dla aplikacji jest to logiczne. Dla bezpieczeństwa to problem, ponieważ PHP w obrazie pochodzi z obrazu bazowego w stanie z tagu ostatniego buildu.

PHP2Shell to uwidoczniło. Poprawione wersje 8.5.12, 8.4.27, 8.3.36 i 8.2.35 ukazały się 21 października 2026. Projekt, nad którym w tych dniach nikt nie pracował, nie dostał nowego buildu i działał dalej na starym PHP, choć obraz bazowy dawno zaktualizowano. Ręczną drogę wyjścia z tej sytuacji opisuje [Łatanie PHP w kontenerach Docker](https://phpsos.de/pl/php2shell/docker-container-patchen/). Ten artykuł pokazuje, jak ją zautomatyzować.

## Automatyczna przebudowa obrazów Docker: trzy wyzwalacze

Solidny proces łączy kilka wyzwalaczy, aby żaden nie musiał dźwigać wszystkiego sam.

| Wyzwalacz | Realizacja | Na co zwrócić uwagę |
|---|---|---|
| Harmonogram | workflow według harmonogramu, np. co tydzień | pobiera poprawki także bez zmian w kodzie |
| Nowy obraz bazowy | narzędzie monitorujące obrazy bazowe i proponujące zmiany | działa głównie przy stałych tagach wersji |
| Komunikat bezpieczeństwa | ręczne uruchomienie pipeline przez zespół operacyjny | wymaga jasno wskazanej osoby odpowiedzialnej |

W GitHub Actions harmonogram obsługuje zdarzenie `schedule`. Według dokumentacji GitHub używa ono składni cron z pięcioma polami, działa w UTC i tylko na domyślnej gałęzi. Zaplanowane przebiegi mogą przy dużym obciążeniu startować z opóźnieniem, a w repozytoriach publicznych GitHub wyłącza je po 60 dniach bez aktywności. To ostatnie dotyka spokojnych projektów, czyli właśnie tych, które najpilniej potrzebują automatycznej przebudowy.

Dla drugiego wyzwalacza Dependabot obsługuje według dokumentacji GitHub ekosystem `docker` i proponuje nowe stany obrazów bazowych jako pull request. Warto znać dwa ograniczenia. Po pierwsze, ktoś musi pull request sprawdzić i scalić, w przeciwnym razie leży. Po drugie, przy tagu gałęzi, takim jak `php:8.3-fpm`, w Dockerfile nic się nie zmienia, gdy obraz bazowy zostanie zbudowany od nowa. Narzędzie proponujące zmiany tekstu nie ma wtedy czego proponować. Właśnie dlatego potrzebna jest dodatkowo przebudowa według harmonogramu.

Trzeci wyzwalacz brzmi banalnie, w praktyce jednak często zawodzi na pytaniu, kto go uruchamia. Proszę ustalić, kto śledzi komunikaty bezpieczeństwa o PHP i kto może uruchomić pipeline, także w weekend. Przy PHP2Shell między zapowiedzią a poprawką minął tylko jeden dzień.

## Pipeline, który wyłapuje przestarzałe PHP

Poniższy przykład dla GitHub Actions buduje obraz co tydzień i na żądanie, sprawdza wersję PHP i przerywa, jeśli jest niższa od poprawionego stanu. Rejestr, nazwy i minimalną wersję proszę dostosować.

```yaml
name: php-image-rebuild
on:
  schedule:
    - cron: "0 3 * * 1"      # w poniedziałki o 03:00 UTC
  workflow_dispatch: {}      # ręczny start przy komunikatach bezpieczeństwa

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Image ohne Cache und mit frischem Basis-Image bauen
        run: docker build --pull --no-cache -t app:${{ github.run_id }} .
      - name: PHP-Version prüfen (Mindeststand des Zweigs 8.3)
        run: |
          docker run --rm app:${{ github.run_id }} php -v
          docker run --rm app:${{ github.run_id }} \
            php -r 'exit(version_compare(PHP_VERSION, "8.3.36", ">=") ? 0 : 1);'
```

Kontrola wersji działa w oficjalnych obrazach PHP, w których numer wersji podaje faktyczny stan. Jeśli Państwa obraz używa pakietów PHP dystrybucji, numer po backporcie często pozostaje taki sam. Wtedy zamiast numeru sprawdzają Państwo changelog pakietu pod kątem numerów CVE, jak opisano w artykule [Dowód CVE w changelogu pakietu](https://phpsos.de/pl/blog/cve-im-changelog-nachweisen/).

Po kontroli w praktyce następują trzy dalsze kroki: przeskanować obraz pod kątem znanych podatności, wysłać go do rejestru z datą i digestem oraz przekazać digest do wdrożenia. Jakie tagi i warianty nadają się na bazę, wyjaśniają [Oficjalne obrazy PHP Docker](https://phpsos.de/pl/blog/offizielle-php-docker-images/).

## Od buildu do działającego kontenera

Najczęstszy błąd myślowy: pipeline jest zielony, więc wszystko jest załatane. Faktycznie nowy obraz leży tylko w rejestrze. Poprawka staje się skuteczna dopiero wtedy, gdy każdy kontener został utworzony od nowa z nowego obrazu.

1. **Wdrażać po digeście:** Wdrożenie odwołuje się do digestu nowego obrazu, a nie do wędrującego tagu.
2. **Najpierw staging, potem produkcja:** Automatyczne testy na kopii wychwytują załamania spowodowane nowymi obrazami bazowymi.
3. **Sprawdzić w działaniu:** Po wdrożeniu wykonać `php -v` w działającym kontenerze i porównać digest z buildem.
4. **Ograniczyć drogę powrotu:** Stary obraz pozostaje dostępny na krótko jako droga powrotu, ale zawiera podatne PHP.

W Kubernetes obowiązują własne zasady, na przykład dotyczące polityki pobierania; znajdą je Państwo w [Łatanie PHP w Kubernetes](https://phpsos.de/pl/server/kubernetes/).

## Typowe luki w łańcuchu

- **Pamięć podręczna buildu na runnerze:** Bez `--pull` i `--no-cache` używany jest ponownie stary obraz bazowy.
- **Lustro rejestru:** Wewnętrzna pamięć pośrednia nadal dostarcza stary stan obrazu bazowego.
- **Buildy wieloetapowe:** Liczy się wersja PHP ostatniego etapu, a sprawdzany bywa często tylko pierwszy.
- **Obrazy poboczne:** Workery kolejek, kontenery cron i narzędzia wewnętrzne mają własne pipeline albo żadnych.
- **Wpisane na stałe digesty:** Raz zapisany digest obrazu bazowego nigdy nie jest aktualizowany, jeśli żadne narzędzie go nie monitoruje.

> **Ważne:**
> Przebudowa zastępuje PHP, a nie dane. Złośliwy kod, który przed poprawką trafił do woluminów, katalogów uploadu lub bazy danych, pozostaje i trzeba go sprawdzić osobno.

## Kto reaguje, gdy przebudowa się nie powiedzie?

Automatyczna przebudowa jest tyle warta, ile reakcja na jej niepowodzenie. Jeśli kontrola wersji zgłosi alarm albo build przerwie się z powodu zmienionego obrazu bazowego, ktoś musi to zauważyć. W wielu zespołach takie komunikaty trafiają do skrzynki, której nikt nie czyta, albo na kanał, na którym czerwone buildy dawno są codziennością.

Sprawdziła się jasna zasada: nieudana przebudowa bezpieczeństwa to zgłoszenie z osobą odpowiedzialną i terminem, a nie jedna z wielu uwag. Proszę ponadto zapisywać dla każdego wdrożonego obrazu datę, digest i sprawdzoną wersję PHP. Ta lista odpowiada przy następnym komunikacie w minuty, które aplikacje są dotknięte, a wobec audytorów lub ubezpieczycieli służy jako dowód. Jak z tego powstaje trwały proces, opisuje [Zarządzanie poprawkami jako proces, a nie akcja gaśnicza](https://phpsos.de/pl/blog/patch-management-prozess/).

## Jak konkretnie pomaga PHP SOS?

- **Sprawdzić pipeline:** Przyglądamy się Państwa łańcuchom buildu i wdrożenia i pokazujemy, gdzie poprawka może utknąć.
- **Zautomatyzować przebudowę:** Konfigurujemy buildy według harmonogramu, kontrolę wersji i wdrożenie po digeście.
- **Zebrać wszystkie obrazy:** Przypisujemy każdemu działającemu kontenerowi jego pipeline, także obrazy poboczne i stare.
- **Opiekować się na stałe:** W ramach [umowy serwisowej bezpieczeństwa](https://phpsos.de/pl/leistungen/security-wartungsvertrag/) śledzimy komunikaty bezpieczeństwa i uruchamiamy przebudowy.


## Częste pytania

**Jak często należy przebudowywać obraz PHP?**  
Nie ma stałej liczby. Sprawdza się regularny build według harmonogramu, na przykład co tydzień, oraz natychmiastowy build przy komunikatach bezpieczeństwa. Rozstrzygające jest, aby nowa poprawka nie musiała czekać na następną zmianę w kodzie.

**Czy udany build wystarcza jako dowód?**  
Nie. Build dowodzi tylko, że istnieje nowy obraz. Poprawka jest skuteczna dopiero wtedy, gdy działające kontenery zostały utworzone od nowa z tego obrazu, a php -v pokazuje w nich poprawioną wersję.

**Dlaczego po przebudowie nadal pojawia się stara wersja PHP?**  
Częste przyczyny to pamięć podręczna buildu, która ponownie wykorzystuje stary obraz bazowy, lustro rejestru ze starym stanem albo drugi wiersz FROM w buildzie wieloetapowym. Proszę budować z --pull i --no-cache oraz sprawdzić każdy etap.

**Czy Dependabot może aktualizować obrazy bazowe?**  
Według dokumentacji GitHub Dependabot obsługuje ekosystem Docker dla aktualizacji wersji i bezpieczeństwa. Proponuje zmiany obrazów bazowych jako pull request. Nie zastępuje to przebudowy przy niezmienionym tagu.

## Źródła

- [GitHub Docs: zdarzenia uruchamiające workflow (schedule)](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows)
- [GitHub Docs: ekosystemy obsługiwane przez Dependabot](https://docs.github.com/en/code-security/dependabot/ecosystems-supported-by-dependabot/supported-ecosystems-and-repositories)
- [Docker Hub: oficjalny obraz PHP](https://hub.docker.com/_/php)
- [PHP: wspierane wersje](https://www.php.net/supported-versions.php)
