Was bedeutet "Das Eingabegerät ist kein TTY" genau in der Ausgabe "docker run"?

Dies ist ein Befehl, der funktioniert:

$ echo 'hi there' | docker run -i ubuntu cathi there

Dies ist ein Befehl, der mit einer Fehlermeldung antwortet:

$ echo 'hi there' | docker run -it ubuntu catthe input device is not a TTY

Ich würde gerne genau herausfinden, was hier passiert. Nicht nur "remove -t und es wird repariert".

Das weiß ich docker run's -t option steht für "Allocate a pseudo-TTY", und ich habe gelesen historische Übersichten darüber, wofür TTY steht, aber es hat mir nicht geholfen zu verstehen, welche Art von Vertrag hier verletzt wird.

Späte Antwort, könnte aber jemandem helfen

docker run/exec -i verbindet die Standardeingabe des Befehls im Container mit der Standardeingabe des docker run/exec selbst.

So

  • docker run -i alpine cat gibt Ihnen eine leere Zeile, die auf Eingabe wartet. Geben Sie "hello" ein und Sie erhalten ein Echo "hello". Der Container wird erst beendet, wenn Sie STRG + D senden, da der Hauptprozess cat wartet auf Eingaben aus dem unendlichen Stream, der der Terminaleingang des docker run.
  • Auf der anderen Seite echo "hello" | docker run -i alpine cat wird "hallo" drucken und sofort beenden, weil cat stellt fest, dass der Eingabestream beendet wurde und sich selbst beendet.

Wenn du es versuchst docker ps nachdem Sie einen der oben genannten Schritte beendet haben, werden Sie keine laufenden Container finden. In beiden Fällen, cat selbst beendet wurde, hat Docker den Container beendet.

Jetzt für "-t" teilt dies dem Hauptprozess im Docker mit, dass seine Eingabe ein Terminalgerät ist.

So

  • docker run -t alpine cat gibt Ihnen eine leere Zeile, aber wenn Sie versuchen, "hello" einzugeben, erhalten Sie kein Echo. Dies liegt daran, dass während cat an einen Terminaleingang angeschlossen ist, ist dieser Eingang nicht mit Ihrem Eingang verbunden. Das von Ihnen eingegebene "hallo" hat die Eingabe von nicht erreicht cat. cat wartet auf Eingaben, die nie ankommen.
  • echo "hello" | docker run -t alpine cat gibt Ihnen auch eine leere Zeile und verlässt den Container nicht mit STRG-D, aber Sie erhalten kein Echo "hallo", weil Sie nicht bestanden haben -i

Wenn Sie STRG + C senden, erhalten Sie Ihre Shell zurück, aber wenn Sie es versuchen docker ps jetzt sehen Sie die cat container läuft noch. Dies liegt daran, dass cat wartet immer noch auf einen Eingabestream, der nie geschlossen wurde. Ich habe keine nützliche Verwendung für die gefunden -t allein, ohne mit kombiniert zu werden -i.

Jetzt, für -it zusammen. Dies teilt cat mit, dass sein Eingang ein Terminal ist, und verbindet dieses Terminal gleichzeitig mit dem Eingang von docker run welches ist ein Terminal. docker run/exec wird sicherstellen, dass seine eigene Eingabe tatsächlich ein tty ist, bevor es an übergeben wird cat. Deshalb erhalten Sie eine input device is not a TTY wenn du es versuchst echo "hello" | docker run -it alpine cat weil in diesem Fall die Eingabe von docker run selbst ist die Pipe vom vorherigen Echo und nicht das Terminal, wo docker run wird ausgeführt

Schließlich, warum solltest du bestehen müssen -t wenn -i wird den Trick machen, Ihre Eingabe mit zu verbinden cat's Eingabe? Dies liegt daran, dass Befehle die Eingabe anders behandeln, wenn es sich um ein Terminal handelt. Dies lässt sich auch am besten anhand eines Beispiels veranschaulichen

  • docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -uroot -p wird Ihnen eine Passwortabfrage geben. Wenn Sie das Passwort eingeben, werden die Zeichen sichtbar gedruckt.
  • docker run -i alpine sh wird Ihnen eine leere Zeile geben. Wenn Sie einen Befehl wie eingeben ls sie erhalten eine Ausgabe, aber keine Eingabeaufforderung oder farbige Ausgabe.

In den letzten beiden Fällen erhalten Sie dieses Verhalten, weil mysql sowie shell behandelten die Eingabe nicht als tty und verwendeten daher kein tty-spezifisches Verhalten wie Maskieren der Eingabe oder Einfärben der Ausgabe.

Diese Antwort hat mir geholfen, meinen Kopf herumzuwickeln:

  • standardmäßig (ohne -i noch -t optionen) ein Docker-Container sendet seine Ausgabe nur anSTDOUT,
  • mit -i option für die Verbindung zu STDIN,
  • -t option zieht einen Terminalschnittstellentreiber ein, das funktioniert über STDIN / STDOUT. Und wenn ein Terminaltreiber eingezogen wird, muss die Kommunikation mit einem Container dem entsprechen terminalschnittstellenprotokoll. Piping eines Strings nicht.

Ein tty zeigt an, dass Sie ein Terminal haben, etwas, das von xterm oder einer der vielen Linux-Befehlszeilenschnittstellen bereitgestellt wird. Es benötigt eine Tastatur und eine damit verbundene Textausgabeschnittstelle. Typische Gründe dafür sind die Unterstützung der Farbtextausgabe, die Handhabung verschiedener Tastenkombinationen (wie der Pfeiltasten) und die Möglichkeit, den Cursor auf dem Bildschirm zu bewegen.

Wenn Sie einen Befehl in Docker wie Ihren pipen echo das Beispiel zeigt, dass Pipe die Eingabe ist und dass Pipe keine tty-Schnittstelle hat, sondern nur ein Textstrom. Der Versuch, damit ein tty zu erstellen, schlägt fehl, wie in der Fehlermeldung angegeben.

Kann ich tty im Docker starten? Ich habe eine App, die nicht mehr funktioniert, aber ich starte den Docker nicht mit -t, aber ich kann den Docker-Startbefehl in der Produktion nicht ändern. Also muss ich die App denken lassen, dass sie mit `-t’ gestartet wurde.

Es ist nicht redundant, Docker kann ein TTY erstellen, ohne etwas daran anzuhängen. Ihre Ausgabe würde Zeichen für Farbe usw. enthalten, aber Ihre Terminalausgabe würde nicht in die Eingabe des Containers geleitet. Die von Ihnen eingegebenen Zeichen werden also für den nächsten Befehl in die Warteschlange gestellt, den Sie ausführen, nachdem der Docker-Befehl beendet wurde.