Alle Artikel
12. September 2026
7 mins

Ein EOL-Kalender für den ganzen Stack

Von Tim Rutte, Cloud & Software ArchitectThemaLegacy & Modernisierung

Ein Regal mit gleichen weißen Konservendosen, eine davon verbeult und mit blauem Deckel.

Kein Ablaufdatum in einem Software-Stapel kommt überraschend. Sie stehen alle Jahre vorher fest, öffentlich, mit Datum. Trotzdem werden sie zuverlässig verpasst, und zwar nicht von unaufmerksamen Teams, sondern von guten.

Der Grund ist nicht Unwissen. Er ist, dass ein bekanntes Datum ohne Zuständigen und ohne Eintrag im Plan genau so wirksam ist wie ein unbekanntes. Alle wussten, dass die Datenbankfassung im Juni ausläuft. Es hat nur niemand vor Juni etwas damit gemacht.

Dieser Artikel beschreibt eine Liste, die das behebt. Sie kostet einen Tag im Aufbau und einen halben Tag im Quartal, und sie ist der billigste Weg, aus einer Reihe von Notfällen eine Reihe von Terminen zu machen.

Was alles ein Ablaufdatum hat

Die erste Überraschung beim Aufstellen der Liste ist ihre Länge. Gedacht wird an die Sprache und das Framework, und das ist ungefähr ein Drittel.

Ein Ablaufdatum tragen außerdem: das Betriebssystem und jedes Basisabbild, die Datenbank samt der Fassung, die der verwaltete Dienst noch anbietet, die Laufzeitumgebung serverloser Funktionen, jedes Client-Paket zu einem Dienst, den Sie nicht betreiben, die Schnittstellenfassung des Zahlungsanbieters, das Signaturverfahren im Austausch mit dem Steuerberater, die Sicherheitsprotokolle, die ein Browser noch akzeptiert, und der Wartungsvertrag für das Gerät im Keller, das die Zeit stellt.

Zwei Kategorien werden dabei fast immer vergessen, und sie sind die unangenehmsten.

Fassungen verwalteter Dienste. Bei einer selbst betriebenen Datenbank entscheidet man, wann aktualisiert wird. Bei einer verwalteten entscheidet der Anbieter, und er tut es mit Ankündigung und dann ohne Rückfrage. Eine Fassung, die das Wartungsende erreicht, wird in einem Wartungsfenster angehoben, das jemand anderes gewählt hat.

Fremde Schnittstellen. Wenn der Zahlungsanbieter eine Fassung abschaltet, ist das kein Sicherheitsthema, sondern ein Umsatzthema, und die Frist ist kürzer als bei allem anderen auf der Liste.

Die Liste in einem Tag

Das meiste davon lässt sich abfragen statt zusammentragen. Drei Quellen decken den größten Teil ab.

# 1. Was im Projekt steckt, und was davon veraltet ist.
composer outdated --direct --format=json > abhaengigkeiten.json
go list -m -u -json all | jq -r 'select(.Update) | .Path'

# 2. Die Termine dazu. endoflife.date kennt die meisten
#    Fassungen und liefert sie maschinenlesbar.
for p in php symfony ubuntu postgresql nodejs; do
  curl -s "https://endoflife.date/api/$p.json" \
    | jq -r --arg p "$p" '.[] | "\($p) \(.cycle) \(.eol)"'
done

# 3. Und die Termine, die Ihnen der Anbieter setzt.
#    Diese Zeile findet, was bei einer eigenen Datenbank
#    nie zum Termin geworden waere.
aws rds describe-db-engine-versions --engine postgres \
  --query 'DBEngineVersions[].{v:EngineVersion,ende:SupportEndDate}'

Was danach noch fehlt, sind die Dinge, die in keinem Paketverzeichnis stehen: Verträge, Zertifikate, Schnittstellen von Partnern. Die kommen aus einer Runde mit zwei Personen und einer halben Stunde, und sie sind der Teil, der nur einmal weh tut.

Woher die Liste der Pakete kommt, wenn niemand mehr weiß, was installiert ist, steht in Composer als Archäologie.

Was eine Zeile enthalten muss

Die Liste ist wertlos, wenn sie nur aus Komponente und Datum besteht. Dann ist sie eine Sorgenliste, und Sorgenlisten werden nicht abgearbeitet.

Brauchbar wird sie durch vier weitere Spalten, und eine davon ist die entscheidende.

Aufwand, grob in Tagen. Ohne diese Zahl kann niemand planen, und die Schätzung muss nicht gut sein: Der Unterschied zwischen zwei Tagen und drei Wochen ist die Information, um die es geht.

Vorlauf, ebenfalls in Tagen, und das ist etwas anderes als der Aufwand. Ein PHP-Sprung braucht zwei Wochen Arbeit und drei Monate Vorlauf, weil Bibliotheken nachziehen müssen und ein Testlauf im Betrieb dazwischenliegt.

Der Termin, der zählt. Nicht das Ablaufdatum, sondern Ablaufdatum minus Vorlauf. Das ist die einzige Zahl in der Liste, nach der sortiert wird, und sie ist der Grund, warum die Liste funktioniert: Sie verschiebt die Aufmerksamkeit von „wann läuft es ab" zu „wann müssen wir anfangen".

Ein Name. Nicht ein Team, ein Name. Eine Zeile ohne Namen ist eine Zeile, die im Quartalsgespräch vorgelesen wird und sonst nichts bewirkt.

Harte und weiche Termine

Eine Unterscheidung spart mehr Diskussion als jede andere, und sie steht selten auf solchen Listen.

Ein harter Termin heißt, dass jemand anderes etwas abschaltet. Die verwaltete Datenbank wird angehoben. Die Schnittstelle antwortet nicht mehr. Das Zertifikat wird nicht mehr akzeptiert. Diese Termine sind keine Abwägung, sie sind ein Datum, an dem etwas aufhört zu funktionieren.

Ein weicher Termin heißt, dass es weiterläuft, aber keine Sicherheitsaktualisierungen mehr gibt. PHP 8.1 funktioniert auch heute. Es bekommt nur keine Korrekturen mehr, und das ist ein Risiko, keine Störung.

Der Fehler, der daraus regelmäßig entsteht: Beide werden gleich behandelt. Weiche Termine wandern dann ins nächste Quartal, bis sie sich stapeln, und harte Termine bekommen dieselbe Aufmerksamkeit wie ein Aufräumvorhaben.

Die Regel, die daraus folgt, ist kurz: Harte Termine sind nicht verhandelbar und kommen in die Quartalsplanung wie ein Kundentermin. Weiche werden gesammelt und in Gruppen erledigt, meistens zusammen mit dem nächsten harten Termin im selben Bereich, weil die Testarbeit dann nur einmal anfällt.

Der Teil, der von allein passiert

Eine Liste, die von Hand gepflegt wird, ist nach zwei Quartalen falsch. Der Abgleich gehört deshalb in einen Lauf, der einmal pro Woche stattfindet und sich nur meldet, wenn sich etwas ändert:

#!/usr/bin/env bash
# Laeuft montags. Meldet nur, was innerhalb des Vorlaufs liegt:
# eine Meldung, die jede Woche kommt, wird nach drei Wochen
# nicht mehr gelesen.
heute=$(date +%s)

while IFS=, read -r komponente fassung eol vorlauf verantwortlich; do
  ende=$(date -d "$eol" +%s)
  start=$(( ende - vorlauf * 86400 ))
  [ "$heute" -lt "$start" ] && continue

  tage=$(( (ende - heute) / 86400 ))
  echo "$komponente $fassung: noch $tage Tage, zustaendig $verantwortlich"
done < eol-kalender.csv

Zwei Entscheidungen darin sind wichtiger als der Code. Gemeldet wird nur, was innerhalb seines Vorlaufs liegt, weil eine wöchentliche Vollmeldung nach drei Wochen ungelesen ist. Und gemeldet wird mit Namen, weil eine Meldung an alle eine Meldung an niemanden ist.

Wie ein solcher Termin konkret abgearbeitet wird, steht am Beispiel Symfony in Symfony-Deprecations abarbeiten, ohne im Log zu ertrinken.

Wenn der Termin schon vorbei ist

Der häufigere Fall beim ersten Aufstellen der Liste ist nicht ein Termin in acht Monaten, sondern einer, der vor zwei Jahren war. Dafür gibt es drei Wege, und der erste wird zu selten geprüft.

Verlängerte Wartung kaufen. Für die großen Betriebssysteme und einige Datenbanken gibt es sie, und sie kostet einen Bruchteil dessen, was ein überstürzter Sprung kostet. Sie ist keine Lösung, sie ist gekaufte Zeit, und genau deshalb ist sie richtig: Sie verwandelt einen Notfall zurück in einen Termin.

Die Stelle einzäunen. Läuft eine alte Fassung nur noch für einen Teil des Systems, wird dieser Teil abgetrennt: eigener Prozess, kein direkter Zugang von außen, ein schmaler Übergang zum Rest. Das senkt nicht das Risiko der Komponente, sondern die Fläche, auf der es wirkt.

Zwischenschritte statt eines Sprungs. Von PHP 7.2 auf 8.4 in einem Schritt ist ein Vorhaben mit offenem Ende. In drei Schritten, jeder für sich lieferbar, ist es eine Reihe von Wochen. Der Zwischenstand ist nie das Ziel und immer besser als der Ausgangspunkt.

Was in dieser Lage nicht hilft, ist die Entscheidung, gleich alles neu zu bauen. Das ist die Antwort, die entsteht, wenn ein verpasster Termin sich anfühlt wie ein Grundproblem, und sie tauscht ein bekanntes Risiko gegen ein unbekanntes.

Für Systeme, bei denen der Sprung nicht mehr lohnt, gibt es einen anderen Zustand: Wartungsmodus.

Der Satz, der das Budget bringt

Bleibt die Frage, wie diese Liste an Geld kommt, und hier liegt der eigentliche Wert.

Ein Upgrade ist gegenüber einer Geschäftsführung schwer zu begründen, weil es nichts Neues bringt. Ein Datum ist leicht zu begründen, weil es nicht zur Debatte steht. Der Unterschied zwischen den beiden Sätzen ist der ganze Trick:

„Wir sollten mal auf PHP 8.4 gehen" ist eine Meinung. „Am 31. Dezember bekommt unsere PHP-Fassung keine Sicherheitskorrekturen mehr; der Umstieg braucht zwei Wochen Arbeit und drei Monate Vorlauf, also fangen wir Ende September an" ist ein Termin. Der erste Satz konkurriert mit Funktionen, der zweite nicht.

Das ist auch der Grund, warum sich diese Liste lohnt, selbst wenn sie ein Quartal lang niemand anschaut: Sie verwandelt die technischen Schulden, über die sich schlecht reden lässt, in Zeilen mit Datum, über die sich gut reden lässt. Wie ein PHP-Upgrade in der Praxis abläuft, steht auf einer eigenen Seite.

Dieser Artikel gehört zu einer Reihe über Systeme, die es schon gibt. Der Rückblick ordnet alle Artikel der Reihe nach Anlass.