Dumb-Init ist ein einfacher Prozessleiter und Init-System, der als PID 1 in minimalen Containerumgebungen (wie Docker) ausgeführt wurde. Es wird als kleine, statisch verbundene Binärin in C eingesetzt, die in C geschrieben wurden.
Leichte Container haben die Idee, einen einzelnen Prozess oder Service ohne normale Init -Systeme wie Systemd oder Sysvinit auszuführen, populär gemacht. Das Auslassen eines Init -Systems führt jedoch häufig zu einem falschen Umgang mit Prozessen und Signalen und kann zu Problemen wie Containern führen, die nicht anmutig gestoppt werden können, oder und undichte Container, die zerstört werden sollen.
dumb-init können Sie Ihren Befehl einfach mit dumb-init vorfixieren. Es fungiert als PID 1 und erzeugt Ihren Befehl sofort als Kinderprozess, um Signale ordnungsgemäß zu behandeln und zu leiten, sobald sie empfangen werden.
Wenn Sie einen Docker -Container starten, wird der Prozess, den Sie ausführen, normalerweise zu PID 1, sodass ihm die Macken und Verantwortlichkeiten mit dem Init -System für den Container einhergehen.
Es gibt zwei gemeinsame Themen, die sich vorstellen:
In den meisten Fällen werden Signale nicht ordnungsgemäß behandelt.
Der Linux -Kernel wendet eine spezielle Signalbehandlung auf Prozesse an, die als PID 1 ausgeführt werden.
Wenn Prozesse ein Signal auf ein normales Linux -System gesendet werden, prüft der Kernel zunächst nach benutzerdefinierten Handlern, die der Prozess für dieses Signal registriert hat, und fällt ansonsten auf das Standardverhalten zurück (z. B. das Töten des Prozesses auf SIGTERM ).
Wenn der Prozess, der das Signal erhält, jedoch PID 1 ist, wird die spezielle Behandlung vom Kernel behandelt. Wenn es keinen Handler für das Signal registriert hat, fällt der Kernel nicht auf das Standardverhalten zurück, und es passiert nichts. Mit anderen Worten, wenn Ihr Prozess diese Signale nicht ausdrücklich behandelt, hat das Senden von SIGTERM überhaupt keine Auswirkungen.
Ein allgemeines Beispiel sind CI-Jobs, die docker run my-container script : SIGTERM an den docker run tötet normalerweise den Befehl docker run ab, lassen Sie den Container jedoch im Hintergrund ausgeführt.
Orphaned Zombie -Prozesse werden nicht richtig geerntet.
Ein Prozess wird beim Ausgang zu einem Zombie und bleibt ein Zombie, bis seine Eltern eine Variation des wait() -Systemaufrufs darauf nennen. Es bleibt in der Prozesstabelle als "verstorbener" Prozess. Normalerweise ruft ein übergeordneter Prozess wait() sofort an und vermeidet langlebige Zombies.
Wenn ein Elternteil vor seinem Kind verlässt, ist das Kind "verwaiste" und unter PID 1 erneut unterzogen. Das Init -System ist somit für wait() auf OrphaNed Zombie -Prozessen.
Natürlich werden die meisten Prozesse nicht auf zufällige Prozesse wait() , die sich an ihnen befinden, sodass Behälter oft mit Dutzenden von Zombies enden, die auf PID 1 verwurzelt sind.
dumb-init ist dumb-init läuft als PID 1 und wirkt sich wie ein einfaches Init-System. Es startet einen einzigen Prozess und stellte anschließend alle Signale für eine Sitzung auf, die auf diesem Kinderprozess verwurzelt ist.
Da Ihr tatsächlicher Prozess nicht mehr PID 1 ist, werden die Standard-Signalhandler angewendet, wenn er Signale von dumb-init erhält, und Ihr Prozess wird sich so verhalten, wie Sie es erwarten würden. Wenn Ihr Prozess stirbt, stirbt auch dumb-init achtet darauf, alle anderen Prozesse zu bereinigen, die noch bestehen bleiben.
Im Standardmodus legt dumb-init eine Sitzung ein, die beim Kind verwurzelt ist, und sendet Signale an die gesamte Prozessgruppe. Dies ist nützlich, wenn Sie ein schlecht benachbartes Kind haben (z. B. ein Shell-Skript), das seine Kinder normalerweise vor dem Sterben nicht signalisiert.
Dies kann außerhalb von Docker -Containern in regelmäßigen Prozessaufsichtsbehörden wie Daemontools oder Supervisford für die Überwachung von Shell -Skripten nützlich sein. Normalerweise wird ein Signal wie SIGTERM von einer Hülle nicht an Subprozesse weitergeleitet. Stattdessen stirbt nur der Shell -Prozess. Mit Dumb-Init können Sie einfach Shell-Skripte mit Dumb-Init im Shebang schreiben:
#!/usr/bin/dumb-init /bin/sh
my-web-server & # launch a process in the background
my-other-server # launch another process in the foreground
Normalerweise würde eine an die Hülle gesendete SIGTERM die Hülle abtöten, aber die Prozesse laufen (sowohl den Hintergrund als auch den Vordergrund!). Mit Dumb-Init erhalten Ihre Subprozesse die gleichen Signale, die Ihre Shell ausführt.
Wenn Sie möchten, dass Signale nur an das direkte Kind gesendet werden, können Sie mit dem Argument für --single-child ausgeführt oder die Umgebungsvariable DUMB_INIT_SETSID=0 festlegen, wenn Sie dumb-init ausführen. In diesem Modus ist Dumb-Init vollständig transparent. Sie können sogar mehrere zusammen anhalten (wie dumb-init dumb-init echo 'oh, hi' ).
Dumb-Init ermöglicht das Umschreiben eingehender Signale, bevor sie sie vergrößern. Dies ist nützlich in Fällen, in denen Sie einen Docker -Supervisor (wie Mesos oder Kubernetes) haben, der immer ein Standardsignal sendet (z. B. sigterm). Einige Apps erfordern ein anderes Stoppsignal, um eine anmutige Reinigung durchzuführen.
Um das Signal sigterm (Nummer 15) in Sigquit (Nummer 3) umzuschreiben, fügen Sie einfach --rewrite 15:3 in der Befehlszeile hinzu.
Um ein Signal vollständig fallen zu lassen, können Sie es in die Sonderzahl 0 umschreiben.
Wenn Sie im SetSID -Modus ausgeführt werden, reicht es nicht aus, in den meisten Fällen SIGTSTP / SIGTTIN / SIGTTOU weiterzuleiten. Wenn der Prozess keinen benutzerdefinierten Signalhandler für diese Signale hinzugefügt hat, wendet der Kernel keine Standard -Signalhandhabungsverhalten an (die den Prozess aussetzen würde), da es sich um eine verderbte Prozessgruppe handelt. Aus diesem Grund setzen wir aus diesen drei Signalen standardmäßige Umschreibungen in SIGSTOP . Sie können dieses Verhalten abmelden, indem Sie die Signale auf Wunsch zu ihren ursprünglichen Werten umschreiben.
Eine Einschränkung mit dieser Funktion: Für Jobsteuerungssignale ( SIGTSTP , SIGTTIN , SIGTTOU ) wird sich Dumb-Init immer nach Erhalt des Signals selbst einsetzen, auch wenn Sie es in etwas anderes umschreiben.
Sie haben einige Optionen für die Verwendung dumb-init :
Viele beliebte Linux-Distributionen (einschließlich Debian (seit stretch ) und Debian-Derivaten wie Ubuntu (seit bionic )) enthalten nun in ihren offiziellen Repositorys dumme Pakete.
Bei Debian-basierten Verteilungen können Sie apt install dumb-init Init zu installieren, genau wie Sie ein anderes Paket installieren würden.
Hinweis: Die meisten von Distro geplanten Versionen von Dumb-Init sind im Gegensatz zu den von uns bereitgestellten Versionen nicht statisch verbunden (siehe die anderen Optionen unten). Dies ist normalerweise vollkommen in Ordnung, bedeutet aber, dass diese Versionen von Dumb-Init im Gegensatz zu den statisch verbundenen Versionen, die wir bereitstellen, im Allgemeinen nicht funktionieren, wenn sie in andere Linux-Distributionen kopiert werden.
Wenn Sie einen internen APT-Server haben, ist das Hochladen der .deb auf Ihren Server die empfohlene Möglichkeit, dumb-init zu verwenden. In Ihren Dockerfiles können Sie einfach apt install dumb-init und es wird verfügbar sein.
Debian -Pakete sind auf der Registerkarte Github Releases erhältlich oder Sie können ausführen, make builddeb .
.deb -Pakets manuell (Debian/Ubuntu) Wenn Sie keinen internen APT -Server haben, können Sie dpkg -i verwenden, um das .deb -Paket zu installieren. Sie können auswählen, wie Sie den .deb auf Ihren Container bringen (Montage eines Verzeichnisses oder wget -ing -es sind einige Optionen).
Eine Möglichkeit besteht bei den folgenden Befehlen in Ihrer Dockerfile:
RUN wget https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_amd64.deb
RUN dpkg -i dumb-init_*.debDa Dumb-Init als statisch verknüpfte Binärdatei veröffentlicht wird, können Sie es normalerweise einfach in Ihre Bilder einfügen. Hier ist ein Beispiel dafür in einer Dockerfile:
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64
RUN chmod +x /usr/local/bin/dumb-init Obwohl dumb-init ausschließlich in C geschrieben ist, bieten wir auch ein Python-Paket an, das das Binäre zusammenstellt und installiert. Es kann von PYPI mit pip installiert werden. Sie möchten zuerst einen C-Compiler installieren (auf Debian/Ubuntu, apt-get install gcc ist ausreichend) und dann nur pip install dumb-init .
Ab 1.2.0 ist das Paket bei PYPI als vorgefertigtes Rad-Archiv erhältlich und muss nicht auf gemeinsamen Linux-Verteilungen zusammengestellt werden.
Sobald Sie in Ihrem Docker-Container installiert sind, präfixen Sie Ihre Befehle einfach mit dumb-init (und stellen Sie sicher, dass Sie die empfohlene JSON-Syntax verwenden).
In einer Dockerfile ist es eine gute Praxis, Dumb-Init als Einstieg Ihres Containers zu verwenden. Ein "Einstiegspunkt" ist ein teilweise Befehl, der auf Ihre CMD Anweisung vorbereitet wird, was es zu einer guten Passform für Dumb-Inits macht:
# Runs "/usr/bin/dumb-init -- /my/script --with --args"
ENTRYPOINT [ "/usr/bin/dumb-init" , "--" ]
# or if you use --rewrite or other cli flags
# ENTRYPOINT ["dumb-init", "--rewrite", "2:3", "--"]
CMD [ "/my/script" , "--with" , "--args" ] Wenn Sie einen Einstiegspunkt in einem Basisbild deklarieren, müssen alle Bilder, die daraus abstammen, auch nicht für dumme Initen deklarieren. Sie können einfach wie gewohnt eine CMD einstellen.
Für die interaktive einmalige Verwendung können Sie es einfach manuell vorbereiten:
$ docker run my_container dumb-init python -c 'while True: pass'
Wenn Sie denselben Befehl ohne dumb-init ausführen, kann dies dazu führen, dass der Container ohne SIGKILL nicht gestoppt wird. Mit dumb-init können Sie ihm jedoch mehr humanere Signale wie SIGTERM senden.
Es ist wichtig, dass Sie die JSON -Syntax für CMD und ENTRYPOINT verwenden. Andernfalls ruft Docker eine Shell an, um Ihren Befehl auszuführen, was zu PID 1 anstelle von Dumb-Init führt.
Oft möchten Container einige Vorstartarbeiten ausführen, die während der Bauzeit nicht erledigt werden können. Zum Beispiel möchten Sie möglicherweise einige Konfigurationsdateien basierend auf Umgebungsvariablen ausführen.
Der beste Weg, dies mit Dumb-Init zu integrieren, ist wie folgt:
ENTRYPOINT [ "/usr/bin/dumb-init" , "--" ]
CMD [ "bash" , "-c" , "do-some-pre-start-thing && exec my-server" ]Indem Sie immer noch Dumb-Init als Einstiegspunkt verwenden, verfügen Sie immer über ein ordnungsgemäßes Init-System.
Der exec -Teil des Bash -Befehls ist wichtig, da er den Bash -Prozess durch Ihren Server ersetzt, so dass die Shell nur momentan zu Beginn existiert.
Um die Binärdauer des dummen Initus aufzubauen, sind ein Arbeitsverfahren und LIBC-Header und Standardeinstellungen für Glibc erforderlich.
$ make
Statisch zusammengestelltes Dumb-Init ist aufgrund von GLIBC über 700 KB, aber Musl ist jetzt eine Option. apt-get install musl-tools um die Quelle und die Verpackungen zu installieren, und dann nur:
$ CC=musl-gcc make
Wenn sie statisch mit Musl zusammengestellt werden, liegt die binäre Größe bei etwa 20 KB.
Wir verwenden die Standard -Debian -Konventionen zur Angabe von Build -Abhängigkeiten (schauen Sie in debian/control ). Eine einfache Möglichkeit, den Einstieg zu erstellen, besteht darin, sudo mk-build-deps -i --remove apt-get install build-essential devscripts equivs und dann alle fehlenden Build-Abhängigkeiten automatisch zu installieren. Sie können dann make builddeb verwenden, um dumme Debian-Pakete zu erstellen.
Wenn Sie einen automatisierten Debian-Paket-Build mit Docker bevorzugen, rennen Sie einfach make builddeb-docker . Dies ist einfacher, aber Sie müssen Docker auf Ihrem Computer laufen lassen.