สับสนเกี่ยวกับตัวเลือก Docker -t เพื่อจัดสรร pseudo-TTY


206

ตัวเลือกนี้จะทำอะไรกันแน่? ฉันอ่าน TTY มากและยังคงสับสนอยู่ ผมเล่นไปรอบ ๆ ด้วยไม่ได้มี-tเพียงและดูเหมือนว่าโปรแกรมที่คาดหวังว่าผู้ใช้ป้อนโยนความผิดพลาดโดยไม่ต้อง-i -tทำไมการเปิดใช้งานหลอก -TTY จึงสำคัญ?

คำตอบ:


223

-tตัวเลือกที่จะไปว่า Unix / Linux จัดการเข้า terminal ในอดีตเทอร์มินัลเป็นการเชื่อมต่อแบบอนุกรมหลังจากนั้นเป็นการเชื่อมต่อแบบโมเด็ม เหล่านี้มีไดรเวอร์อุปกรณ์ทางกายภาพ (เป็นอุปกรณ์จริง) เมื่อเครือข่ายทั่วไปเข้ามาใช้ไดรเวอร์ pseudo-terminal ได้รับการพัฒนา นี่เป็นเพราะมันสร้างการแยกระหว่างการทำความเข้าใจความสามารถของเทอร์มินัลที่สามารถใช้งานได้โดยไม่จำเป็นต้องเขียนลงในโปรแกรมของคุณโดยตรง (อ่าน man pages on stty, curses)

ดังนั้นด้วยการที่เป็นพื้นหลังให้เรียกใช้คอนเทนเนอร์โดยไม่มีตัวเลือกและโดยค่าเริ่มต้นคุณจะมีสตรีม stdout (ดังนั้นใช้docker run | <cmd>งานได้); ทำงานด้วย-iและคุณจะได้รับกระแส stdin เพิ่ม ( <cmd> | docker run -iทำงานได้ดี); ใช้งาน-tโดยทั่วไปจะเป็นการรวมกัน-itและคุณได้เพิ่มไดรเวอร์เทอร์มินัลซึ่งหากคุณมีปฏิสัมพันธ์กับกระบวนการน่าจะเป็นสิ่งที่คุณต้องการ โดยพื้นฐานแล้วทำให้การเริ่มต้นคอนเทนเนอร์ดูเหมือนเซสชันการเชื่อมต่อเทอร์มินัล


7
นี่ควรเป็นคำตอบที่ดีที่สุด แม้ว่ามันจะไม่ใช่เทคนิคที่ดีที่สุดที่นี่ แต่มันอธิบายพฤติกรรมพื้นฐานของ-itธง
กริช Khaira

1
เห็นด้วยกับคริส ฉันอ่านคำตอบอื่น ๆ และยังคงสับสนโดยสิ้นเชิง คำตอบนี้จะเคลียร์มัน
Ben Lee

3
ใช่มันอาจคุ้มค่าที่จะพูดถึงว่า "TTY" นั้นเป็นตัวย่อที่มาจากคำว่า "teletypewriter" (AKA "teleprinter") ซึ่งเป็นชื่อของอุปกรณ์ที่ช่วยให้คุณพิมพ์ข้อความและส่งออกไปในเวลาเดียวกัน - เหมือนโทรศัพท์ สำหรับข้อความ ;-) ลองdocker run -i ubuntuและdocker run -it ubuntuคุณจะเห็นความแตกต่างทันที "-i" ช่วยให้คุณสร้างคอนเทนเนอร์เพื่อรอการโต้ตอบจากโฮสต์ แต่การโต้ตอบจริงจากคอนโซล (เทอร์มินัล) เป็นไปได้หลังจากที่คุณ "จัดสรรไดรเวอร์ tty" ด้วยแฟล็ก "-t"
Zegar

ฉันสามารถเริ่ม tty ภายใน docker ได้ไหม? ฉันมีแอพบางตัวที่หยุดทำงานฉันไม่ได้เรียกใช้ docker ด้วย-tแต่ฉันไม่สามารถแก้ไขคำสั่ง docker start ในการผลิตได้ -tดังนั้นผมจึงต้องการที่จะทำให้แอปคิดว่ามันเริ่มต้นด้วย
mvorisek

97

ตอบช้า แต่อาจช่วยใครซักคน

docker run/exec -iจะเชื่อมต่อ STDIN ของคำสั่งภายในคอนเทนเนอร์กับ STDIN ของdocker run/execตัวเอง

ดังนั้น

  • docker run -i alpine catช่วยให้คุณมีบรรทัดว่างรอการป้อนข้อมูล พิมพ์ "สวัสดี" คุณจะได้รับเสียงสะท้อน "สวัสดี" ภาชนะที่จะไม่ออกจนกว่าคุณจะส่งCTRL+ Dเพราะกระบวนการหลักคือการรอคอยสำหรับการป้อนข้อมูลจากกระแสอนันต์ที่มีการป้อนข้อมูลที่ขั้วของcatdocker run
  • ในทางกลับกันecho "hello" | docker run -i alpine catจะพิมพ์ "hello" และออกทันทีเพราะcatสังเกตว่ากระแสข้อมูลได้สิ้นสุดลงและยุติตัวเอง

หากคุณลองdocker psหลังจากออกจากข้อใดข้อหนึ่งข้างต้นคุณจะไม่พบคอนเทนเนอร์ที่ใช้งานอยู่ ในทั้งสองกรณีcatตัวเองได้ยกเลิกดังนั้นนักเทียบท่าได้ยกเลิกภาชนะ

ตอนนี้สำหรับ "-t" นี่จะบอกกระบวนการหลักภายในตัวเทียบท่าว่าอินพุตเป็นอุปกรณ์เทอร์มินัล

ดังนั้น

  • docker run -t alpine catจะให้บรรทัดว่าง แต่ถ้าคุณลองพิมพ์ "hello" คุณจะไม่ได้เสียงสะท้อนใด ๆ นี่เป็นเพราะขณะที่catเชื่อมต่อกับอินพุตเทอร์มินัลอินพุตนี้ไม่ได้เชื่อมต่อกับอินพุตของคุณ "Hello" catที่คุณพิมพ์ไม่ถึงการป้อนข้อมูลของ catกำลังรออินพุตที่ไม่เคยมาถึง
  • echo "hello" | docker run -t alpine catจะให้บรรทัดว่างกับคุณและจะไม่ออกจากคอนเทนเนอร์ในCTRL- Dแต่คุณจะไม่ได้รับเสียงสะท้อน "สวัสดี" เพราะคุณไม่ผ่าน-i

ถ้าคุณส่งCTRL+ Cคุณจะได้เปลือกของคุณกลับมา แต่ถ้าคุณลองdocker psตอนนี้คุณจะเห็นว่าcatคอนเทนเนอร์ยังคงทำงานอยู่ ทั้งนี้เป็นเพราะcatยังคงรอสตรีมอินพุตที่ไม่เคยปิด ฉันไม่ได้พบการใช้ประโยชน์ใด ๆ สำหรับคนเดียวโดยไม่ต้องถูกรวมกับ-t-i

ตอนนี้เพื่อ-itร่วมกัน สิ่งนี้บอกกับ cat ว่าอินพุตเป็นเทอร์มินัลและในเวลาเดียวกันเชื่อมต่อเทอร์มินัลนี้กับอินพุตdocker runซึ่งเป็นเทอร์มินัล docker run/execจะให้แน่ใจว่าการป้อนข้อมูลของตัวเองในความเป็นจริง TTY catก่อนที่จะผ่านไปยัง นี่คือเหตุผลที่คุณจะได้รับinput device is not a TTYถ้าคุณลองecho "hello" | docker run -it alpine catเพราะในกรณีนี้อินพุตของdocker runตัวเองเป็นไพพ์จากเสียงก้องก่อนหน้าและไม่ใช่เทอร์มินัลที่docker runถูกเรียกใช้งาน

ในที่สุดทำไมคุณจะต้องผ่าน-tหาก-iจะทำเคล็ดลับในการเชื่อมต่ออินพุตของคุณกับcatอินพุตของ นี่เป็นเพราะคำสั่งจัดการอินพุตต่างกันถ้ามันเป็นเทอร์มินัล นี่เป็นตัวอย่างที่ดีที่สุด

  • docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -u root -pจะให้พรอมต์รหัสผ่านแก่คุณ หากคุณพิมพ์รหัสผ่านอักขระจะถูกพิมพ์อย่างชัดเจน
  • docker run -i alpine shจะให้บรรทัดที่ว่างกับคุณ หากคุณพิมพ์คำสั่งเช่นlsคุณได้รับผลลัพธ์ แต่คุณจะไม่ได้รับพรอมต์หรือสีที่ส่งออก

ในสองกรณีสุดท้ายคุณจะได้รับพฤติกรรมนี้เพราะmysqlเช่นเดียวกับที่shellไม่ได้รับการรักษาอินพุตเป็น tty และดังนั้นจึงไม่ได้ใช้พฤติกรรมที่เฉพาะเจาะจงเช่น tty เช่นปิดบังอินพุตหรือระบายสีเอาท์พุท


6
คำตอบที่ดีที่สุดที่นี่ทำให้ฉันเข้าใจในสิ่งที่-tและ-iตัวเลือกทำจริงๆ!
Ruslan Stelmachenko

1
คำตอบที่ยอดเยี่ยมซึ่งคาดว่าจะมีทุกคำถามที่ฉันมี
เจมส์

@ Ahmed Ghonim คำตอบที่ดีมาก ขอบคุณ. แต่เกี่ยวกับ "นี่เป็นเพราะคำสั่งรักษาอินพุตต่างกันถ้ามันเป็นเทอร์มินัล" ฉันคิดว่านั่นคือการพิมพ์ผิดใช่มั้ย ควรเป็น "นี่เป็นเพราะคำสั่งจัดการอินพุตต่างกันถ้าไม่ใช่เทอร์มินัล" ใช่ไหม?
tuq

@ Ahmed Ghonim ใส. แต่สิ่งที่เกี่ยวกับนักเทียบท่าวิ่ง -a = stdin แมวอัลไพน์?
HKIT

1
@HKIIT "-a = stdin" แนบ stdin stream เข้ากับคอนเทนเนอร์ แต่ไม่มีการจัดสรรหน่วยความจำ เป็นแฟล็ก -i ที่จัดสรรหน่วยความจำบัฟเฟอร์ในคอนเทนเนอร์สำหรับ stdin stream ดังนั้นคำอธิบาย "เปิด STDIN ไว้แม้ว่าจะไม่ได้แนบ" เมื่อ -i ถูกส่งผ่านหน่วยความจำจะถูกจัดสรรสำหรับ stdin โดยไม่คำนึงถึงแฟล็กสิ่งที่แนบ หากไม่มีการจัดสรรหน่วยความจำนี้การอ่านไปยัง stdin จะว่างเปล่า / eof นอกจากนี้คุณต้องรวม "-a = stdout" เพื่อดูการตอบสนองจากคำสั่ง cat ตัวอย่างเช่น: "docker run -i -a = stdin -a = stdout alpine cat" ... แน่นอนว่าคุณไม่จำเป็นต้องทำเช่นนี้ เพียงแค่เรียกใช้ "นักเทียบท่าวิ่ง -i อัลไพน์แมว"
David D

71

-tโต้แย้งไม่ได้เอกสารดีหรือกล่าวถึงโดยคนจำนวนมากมักจะตามการค้นหาของ Google

มันจะไม่ปรากฏขึ้นเมื่อคุณแสดงรายการข้อโต้แย้งไคลเอนต์นักเทียบท่าทั้งหมดโดยพิมพ์dockerที่ Bash prompt (ด้วยเวอร์ชันล่าสุดของ 1.8.1)

ในความเป็นจริงถ้าคุณพยายามขอความช่วยเหลือเฉพาะเกี่ยวกับเรื่องนี้โดยการพิมพ์docker -t --helpถ้าให้คำตอบที่คลุมเครืออย่างน่าอัศจรรย์นี้:

ให้ไว้ แต่ไม่ได้กำหนด: -t

ดังนั้นคุณไม่สามารถถูกตำหนิว่าสับสนกับเรื่องนี้!

มีการกล่าวถึงในเอกสารออนไลน์ของ Docker ซึ่งกล่าวว่าเป็นการ "จัดสรรหลอก" และมักใช้กับ-i:

https://docs.docker.com/reference/run/

ฉันเห็นมันใช้ในเอกสารประกอบสำหรับตัวjwilder/nginx-proxyเทียบท่าที่ยอดเยี่ยมด้วยวิธีต่อไปนี้:

docker run -d -p 80:80 --name nginx -v /tmp/nginx:/etc/nginx/conf.d -t nginx

ในกรณีนี้สิ่งที่มันคือการส่งออกไปยัง 'เสมือน' tty (พรอมต์คำสั่ง / ขั้ว / Bash) ภายในคอนเทนเนอร์นักเทียบท่านี้ จากนั้นคุณสามารถเห็นเอาต์พุตนี้โดยการรันคำสั่ง docker docker logs CONTAINERโดยที่CONTAINERเป็นคู่แรกของอักขระของ ID คอนเทนเนอร์นี้ รหัสคอนเทนเนอร์นี้สามารถพบได้โดยการพิมพ์docker ps -a

ฉันเคยเห็น-tอาร์กิวเมนต์นี้พูดถึงสั้น ๆ ในลิงค์ต่อไปนี้ที่มันบอกว่า

-tและ-iธงจัดสรรหลอก TTY และให้ stdin เปิดแม้ว่าจะไม่ได้แนบมา สิ่งนี้จะช่วยให้คุณใช้คอนเทนเนอร์เช่น VM ดั้งเดิมได้ตราบใดที่พรอมต์ bash กำลังทำงาน

https://coreos.com/os/docs/latest/getting-started-with-docker.html

ฉันหวังว่านี่จะช่วยได้! ฉันไม่แน่ใจว่าทำไมสิ่งนี้จึงไม่ถูกบันทึกหรือใช้มากนัก อาจเป็นการทดลองและจะนำไปใช้เป็นคุณลักษณะที่บันทึกไว้ในเวอร์ชันที่กำลังจะมาถึง


21
เอกสารแสดงให้เห็นถึงdocker run --helpไม่ใช่docker -t --help: -t, --tty=false Allocate a pseudo-TTY"
bskaggs

5

สิ่งที่ฉันรู้เกี่ยวกับ-tสิ่งต่อไปนี้:

docker exec -ti CONTAINER bash- ช่วยให้ฉัน "เข้าสู่ระบบ" ในภาชนะ มันรู้สึกเหมือน ssh-ing (ไม่ใช่)

แต่ปัญหาคือเมื่อฉันต้องการคืนค่าฐานข้อมูล

ฉันมักจะทำdocker exec -ti mysql.5.7 mysql- ที่นี่ฉันรันคำสั่ง mysql ในภาชนะและรับ terminal โต้ตอบ

ฉันเพิ่ม<dump.sqlไปยังคำสั่งก่อนหน้าเพื่อให้ฉันสามารถคืนค่า db cannot enable tty mode on non tty inputแต่ก็ล้มเหลวด้วย

การถอด-tช่วย ยังไม่เข้าใจว่าทำไม:

docker exec -i mysql.5.7 mysql < dump.sql

อันสุดท้ายใช้ได้ผล หวังว่านี่จะช่วยให้ผู้คน


ฉันสามารถเริ่ม tty ภายใน docker ได้ไหม? ฉันมีแอพบางตัวที่หยุดทำงานฉันไม่ได้เรียกใช้ docker ด้วย-tแต่ฉันไม่สามารถแก้ไขคำสั่ง docker start ในการผลิตได้ -tดังนั้นผมจึงต้องการที่จะทำให้แอปคิดว่ามันเริ่มต้นด้วย
mvorisek

1

ใน linux เมื่อคุณรันคำสั่งคุณจำเป็นต้องมีเทอร์มินัล (tty) เพื่อเรียกใช้งาน

ดังนั้นเมื่อคุณต้องการที่จะเชื่อมต่อกับนักเทียบท่า (หรือเรียกใช้คำสั่งในคอนเทนเนอร์นักเทียบท่า) คุณจะต้องให้ตัวเลือก -t ซึ่งใช้ในการพิจารณาของสถานีภายในภาชนะที่นักเทียบท่า


0

STDIN/ STDOUT/ STDERRทุกขั้นตอนมีสามกระแสข้อมูลคือ เมื่อกระบวนการทำงานในคอนเทนเนอร์โดยเทอร์มินัลเริ่มต้นจะเชื่อมต่อกับสตรีม STDOUT ของกระบวนการที่ทำงานในคอนเทนเนอร์ ดังนั้นสตรีมเอาต์พุตทั้งหมดจะมองเห็นได้ในขณะที่รันdocker runคำสั่งในเทอร์มินัล แต่ถ้าคุณต้องการป้อนข้อมูลให้กับกระบวนการที่กำลังทำงานอยู่ในคอนเทนเนอร์คุณต้องเชื่อมต่อกับช่อง STDIN ของกระบวนการซึ่งไม่ได้เป็นค่าเริ่มต้นและทำด้วยdocker run -iคำสั่ง

-t ใช้สำหรับการป้อนข้อมูลแบบโต้ตอบ / จัดรูปแบบ


-3

-itแนะเทียบท่าที่จะจัดสรรหลอก TTY เชื่อมต่อกับ stdin คอนเทนเนอร์ที่การสร้างเปลือกทุบตีโต้ตอบในภาชนะ

--interactive, -i falseให้ STDIN เปิดอยู่แม้ว่าจะไม่ได้เชื่อมต่อก็ตาม

--tty, -t false จัดสรรหลอก TTY

https://docs.docker.com/engine/reference/commandline/run/

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.