Abhängigkeiten zwischen Services aus /proc kartieren, ohne Agent-SDK
Man muss nichts instrumentieren, um zu wissen, welcher Service mit welchem spricht. Der Kernel hat es bereits vermerkt.
10. Juli 2026 · 8 Min. Lesezeit
„Fügen Sie jedem Service einen Agent hinzu" ist die Antwort, die Ihnen die meisten Observability-Tools für Service-Discovery geben, und das ist eine vernünftige Antwort, wenn Sie bereit sind, jedes Deployment-Manifest anzufassen, jeden Prozess neu zu starten und die SDK-Version über ein Dutzend Services hinweg synchron zu halten, die Leuten gehören, die Ihnen nicht unterstellt sind. Es ist eine deutlich weniger vernünftige Antwort, wenn Sie versuchen, ein System in den ersten fünf Minuten der Nutzung eines Produkts zu kartieren, bevor irgendjemand zugestimmt hat, eine einzige Konfigzeile zu ändern.
Der Kernel weiß bereits, welche Sockets offen sind und wem sie gehören. Man muss es nur auslesen.
Was tatsächlich in /proc steckt
Jeder Prozess unter Linux bekommt ein Verzeichnis unter /proc/<pid>, und darin listet net/tcp (und net/tcp6 für IPv6) jeden TCP-Socket auf, der im Netzwerk-Namespace dieses Prozesses sichtbar ist: lokale Adresse, entfernte Adresse, Verbindungsstatus, und — das hier relevante Feld — eine Inode-Nummer. Diese Inode ist dieselbe Zahl, die Sie unter /proc/<pid>/fd/ als Symlink-Ziel für jeden Dateideskriptor finden, der tatsächlich dieser Socket ist. Gehen Sie die Dateideskriptoren jedes Prozesses durch, gleichen Sie Inodes mit der Socket-Tabelle ab, und Sie haben eine Prozess-zu-Verbindung-Karte, ohne einen einzigen Prozess um Erlaubnis zu fragen.
Von dort aus ist es Addition, keine Innovation: jede PID ihrem Container zuordnen (der cgroup-Pfad oder die Docker-API sagt Ihnen das direkt), und aus einer rohen Liste „Prozess 4821 hat eine etablierte Verbindung zu 10.0.4.12:5432" wird „der Orders-Container spricht mit dem Postgres-Container". Kein Agent in Orders, kein Agent in Postgres, kein Codepfad in beiden, der sich bewusst ist, beobachtet zu werden.
Der Teil, der tatsächlich die Iterationen brauchte
Die Tabelle einmal zu lesen ist die einfachen 80 %. Das Problem ist, dass /proc/net/tcp ein Snapshot ist: eine Verbindung, die zwischen zwei Abfragen öffnet und schließt, erscheint einfach in keiner der beiden Stichproben. Ein Health-Check, der alle 45 Sekunden gegen ein 60-Sekunden-Abfrageintervall feuert, ein ausgehender Aufruf, der in 200 ms abgeschlossen ist, ein Batch-Job, der einmal in Ihrem Fünf-Minuten-Fenster verbindet und nie wieder — all das sind echte Abhängigkeiten, und ein naiver Snapshot-Diff verpasst sie ständig. Bei einem stark ausgelasteten Service ist der Großteil des interessanten Traffics genau diese Art von kurzlebiger Verbindung, was frustrierend zu erfahren ist, nachdem Ihre Topologieansicht Sie bereits überzeugt hat, vollständig zu sein.
Unsere Lösung ist ein gleitendes Retention-Fenster statt eines nackten Snapshots: eine Kante, die in einem der letzten fünf Abfragezyklen gesehen wurde, bleibt im Graphen und wird erst entfernt, nachdem sie über diese gesamte Spanne hinweg tatsächlich abwesend war. Es ist kein cleverer Algorithmus — es ist eher „merken Sie sich, was Sie gesehen haben, ein bisschen länger, als Sie denken zu müssen" — aber es ist der Unterschied zwischen einer Topologie, die plausibel aussieht, und einer, die tatsächlich stimmt.
Wo dieser Ansatz an seine Grenzen stößt
Es lohnt sich, ehrlich über die Grenzen zu sein. Namespace-pro-Container-Setups (der übliche Fall bei Docker und Kubernetes) bedeuten, dass Sie den eigenen Netzwerk-Namespace jedes Containers lesen statt einer geteilten Tabelle für den Host, was mehr Buchhaltung, aber nicht grundsätzlich schwieriger ist. Verschlüsselter Traffic verbirgt die Verbindung nicht — TCP-Metadaten sind alles, was wir hier brauchen, nicht die Payload —, aber es bedeutet, dass wir nur wissen, dass zwei Container sprechen, nicht über welches Protokoll oder zu welchem Endpunkt; dafür ist die Beyla-basierte RED-Metriken-Schicht da, und die beiden sind so konzipiert, dass sie zusammen gelesen werden, nicht als Ersatz füreinander. Und dies ist grundsätzlich eine Ansicht auf TCP-Ebene: UDP-basierte Protokolle brauchen eine völlig andere Lesung, die auf der Liste steht, aber noch nicht im Agent ist.
Möchten Sie das an Ihrem eigenen System sehen?
Für den statischen Graphen genügt eine Repository-URL. Der Runtime-Agent braucht nur eine docker-compose-Datei.
