Nhầm lẫn về tùy chọn Docker -t để phân bổ giả TTY


207

Chính xác thì tùy chọn này làm gì? Tôi đã đọc rất nhiều trên TTY và vẫn còn bối rối. Tôi đã chơi xung quanh mà không có -tvà chỉ -ivà có vẻ như các chương trình mong đợi đầu vào của người dùng gây ra lỗi mà không có -t. Tại sao điều quan trọng đối với giả TTY được bật?

Câu trả lời:


223

Các -ttùy chọn đi vào như thế nào Unix / Linux xử lý truy cập thiết bị đầu cuối. Trước đây, thiết bị đầu cuối là kết nối đường dây cứng, sau này là kết nối dựa trên modem. Chúng có trình điều khiển thiết bị vật lý (chúng là những thiết bị thực sự). Khi các mạng tổng quát được đưa vào sử dụng, trình điều khiển thiết bị đầu cuối giả được phát triển. Điều này là do nó tạo ra một sự tách biệt giữa việc hiểu những khả năng của thiết bị đầu cuối có thể được sử dụng mà không cần phải viết nó trực tiếp vào chương trình của bạn (đọc các trang hướng dẫn trên stty, curses).

Vì vậy, với nền tảng đó, hãy chạy một thùng chứa không có tùy chọn và theo mặc định, bạn có một luồng đầu ra (vì vậy docker run | <cmd>hoạt động); chạy với -ivà bạn nhận được luồng stdin được thêm vào (vì vậy <cmd> | docker run -ihoạt động); sử dụng -t, thường là trong sự kết hợp -itvà bạn đã thêm trình điều khiển đầu cuối, nếu bạn đang tương tác với quy trình có thể là những gì bạn muốn. Về cơ bản, nó làm cho container bắt đầu trông giống như một phiên kết nối đầu cuối.


7
Đây phải là câu trả lời hàng đầu. Mặc dù nó không phải là kỹ thuật nhất ở đây, nó giải thích hành vi cơ bản của các -itlá cờ.
Kris Khaira

1
Đồng ý với Kris. Tôi đọc các câu trả lời khác và vẫn hoàn toàn bối rối. Câu trả lời này xóa nó đi.
Ben Lee

4
Vâng, có lẽ đáng để đề cập rằng chính "TTY" là từ viết tắt của từ "teletypewriter" (AKA "teleprinter") là tên của thiết bị cho phép bạn nhập văn bản và gửi đi cùng một lúc - giống như điện thoại cho văn bản ;-) Hãy thử docker run -i ubuntudocker run -it ubuntubạn sẽ thấy sự khác biệt ngay lập tức. "-I" cho phép bạn tạo vùng chứa để chờ tương tác từ máy chủ nhưng có thể tương tác thực tế từ bàn điều khiển (thiết bị đầu cuối) sau khi bạn "cấp phát trình điều khiển tty" bằng cờ "-t".
Zegar

Tôi có thể bắt đầu tty trong docker không? Tôi có một số ứng dụng ngừng hoạt động Tôi không chạy docker với -t, nhưng tôi không thể sửa đổi lệnh bắt đầu docker trong sản xuất. Vì vậy, tôi cần phải làm cho ứng dụng nghĩ rằng nó đã được bắt đầu với -t.
mvorisek

97

Trả lời muộn, nhưng có thể giúp được ai đó

docker run/exec -isẽ kết nối STDIN của lệnh bên trong container với STDIN của docker run/execchính nó.

Vì thế

  • docker run -i alpine catcung cấp cho bạn một dòng trống chờ đầu vào. Nhập "xin chào" bạn sẽ nhận được tiếng vang "xin chào". Container sẽ không thoát cho đến khi bạn gửi CTRL+ Dvì quá trình chính catđang chờ đầu vào từ luồng vô hạn là đầu vào cuối của docker run.
  • Mặt khác echo "hello" | docker run -i alpine catsẽ in "xin chào" và thoát ngay lập tức vì catthông báo rằng luồng đầu vào đã kết thúc và tự chấm dứt.

Nếu bạn thử docker pssau khi thoát khỏi một trong những điều trên, bạn sẽ không tìm thấy bất kỳ container nào đang chạy. Trong cả hai trường hợp, catchính nó đã chấm dứt, do đó docker đã chấm dứt container.

Bây giờ cho "-t", điều này cho biết quy trình chính bên trong docker rằng đầu vào của nó là một thiết bị đầu cuối.

Vì thế

  • docker run -t alpine catsẽ cung cấp cho bạn một dòng trống, nhưng nếu bạn cố gắng gõ "xin chào", bạn sẽ không nhận được bất kỳ tiếng vang nào. Điều này là do trong khi catđược kết nối với đầu vào đầu cuối, đầu vào này không được kết nối với đầu vào của bạn. "Xin chào" mà bạn đã nhập không đạt đến đầu vào cat. catđang chờ đầu vào không bao giờ đến
  • echo "hello" | docker run -t alpine catcũng sẽ cung cấp cho bạn một dòng trống và sẽ không thoát khỏi container trên CTRL- Dnhưng bạn sẽ không nhận được tiếng vang "xin chào" vì bạn đã không vượt qua-i

Nếu bạn gửi CTRL+ C, bạn sẽ lấy lại được vỏ của mình, nhưng nếu bạn thử docker psngay bây giờ, bạn sẽ thấy catcontainer vẫn chạy. Điều này là do catvẫn đang chờ đợi một luồng đầu vào không bao giờ bị đóng. Tôi đã không tìm thấy bất kỳ sử dụng hữu ích cho -tmột mình mà không được kết hợp với -i.

Bây giờ, cho -itcùng nhau. Điều này cho mèo biết rằng đầu vào của nó là một thiết bị đầu cuối và đồng thời kết nối thiết bị đầu cuối này với đầu vào docker runlà thiết bị đầu cuối. docker run/execsẽ đảm bảo rằng đầu vào của chính nó trong thực tế là một tty trước khi chuyển nó đến cat. Đây là lý do tại sao bạn sẽ nhận được input device is not a TTYnếu bạn cố gắng echo "hello" | docker run -it alpine catvì trong trường hợp này, đầu vào của docker runchính nó là đường ống từ tiếng vang trước đó và không phải là thiết bị đầu cuối nơi docker runđược thực thi

Cuối cùng, tại sao bạn cần phải vượt qua -tnếu -isẽ thực hiện thủ thuật kết nối đầu vào của bạn với catđầu vào của? Điều này là do các lệnh xử lý đầu vào khác nhau nếu đó là một thiết bị đầu cuối. Điều này cũng được minh họa tốt nhất bằng ví dụ

  • docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -u root -psẽ cung cấp cho bạn một dấu nhắc mật khẩu. Nếu bạn nhập mật khẩu, các ký tự được in rõ ràng.
  • docker run -i alpine shsẽ cung cấp cho bạn một dòng trống. Nếu bạn gõ một lệnh như lsbạn nhận được một đầu ra, nhưng bạn sẽ không nhận được một dấu nhắc hoặc đầu ra màu.

Trong hai trường hợp cuối cùng, bạn có hành vi này vì mysqlcũng như shellkhông coi đầu vào là tty và do đó không sử dụng hành vi cụ thể tty như che dấu đầu vào hoặc tô màu đầu ra.


6
Câu trả lời tốt nhất ở đây thực sự khiến tôi hiểu chính xác những gì -t-ilựa chọn làm!
Ruslan Stelmachenko

1
Câu trả lời tuyệt vời dự đoán mọi câu hỏi tôi có
James Machin

@AHmed Ghonim, câu trả lời rất hay. Cảm ơn bạn. Nhưng về "Điều này là do các lệnh xử lý đầu vào khác nhau nếu đó là một thiết bị đầu cuối", tôi nghĩ đó là một sự nhầm lẫn, phải không? Nó phải là "Điều này là do các lệnh xử lý đầu vào khác nhau nếu nó không phải là một thiết bị đầu cuối", phải không?
tuq

@AHmed Ghonim. Tinh thể rõ ràng. Nhưng những gì về docker run -a = stdin alpine cat?
HKIT

1
@HKIIT "-a = stdin" gắn luồng stdin vào vùng chứa nhưng không có cấp phát bộ nhớ. Đó là cờ -i phân bổ bộ nhớ đệm trong vùng chứa cho luồng stdin, do đó mô tả "Giữ STDIN mở ngay cả khi không được đính kèm", khi -i được truyền bộ nhớ được cấp phát cho stdin bất kể cờ đính kèm. Không có bộ nhớ được phân bổ này đọc stdin là trống / eof. Ngoài ra, bạn cần bao gồm "-a = stdout" để xem phản hồi từ lệnh cat chẳng hạn: "docker run -i -a = stdin -a = stdout alpine cat" ... tất nhiên không cần phải làm điều này bạn có thể làm điều này chỉ cần chạy "docker run -i alpine cat".
David D

71

Đối -tsố KHÔNG được ghi lại tốt, hoặc được nhiều người nhắc đến thường xuyên, theo một tìm kiếm của Google.

Nó thậm chí không hiển thị khi bạn hiển thị danh sách (tất cả phải là) tất cả các đối số máy khách docker bằng cách nhập dockertại dấu nhắc Bash (với phiên bản 1.8.1 mới nhất).

Trong thực tế, nếu bạn cố gắng nhận trợ giúp cụ thể về đối số này bằng cách nhập docker -t --helpnếu đưa ra câu trả lời mơ hồ đáng kinh ngạc này:

cờ được cung cấp nhưng không được xác định: -t

Vì vậy, bạn không thể đổ lỗi cho việc nhầm lẫn về lập luận này!

Có một đề cập trong tài liệu trực tuyến Docker nói rằng đó là "Phân bổ giả" và thường được sử dụng với -i:

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

Tôi thấy nó được sử dụng trong tài liệu cho jwilder/nginx-proxycontainer docker tuyệt vời theo cách sau:

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

Trong trường hợp này, những gì nó làm là gửi đầu ra đến 'ảo' tty (dấu nhắc lệnh / thiết bị đầu cuối Bash) trong thùng chứa docker này. Sau đó, bạn có thể thấy đầu ra này bằng cách chạy lệnh docker docker logs CONTAINER, nơi CONTAINERlà cặp ký tự đầu tiên của ID chứa này. ID CONTAINER này có thể được tìm thấy bằng cách gõdocker ps -a

Tôi đã thấy -tlập luận này được đề cập ngắn gọn trong liên kết sau, nơi nó nói

Các cờ -t-iphân bổ một giả-tty và giữ stdin mở ngay cả khi không được đính kèm. Điều này sẽ cho phép bạn sử dụng bộ chứa như một VM truyền thống miễn là dấu nhắc bash đang chạy.

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

Tôi hi vọng cái này giúp được! Tôi không chắc tại sao điều này không được ghi lại hoặc sử dụng nhiều. Có lẽ đó là thử nghiệm và sẽ được triển khai như một tính năng được ghi lại trong các phiên bản sắp tới.


21
Các tài liệu xuất hiện cho docker run --help, không phải docker -t --help: -t, --tty=false Allocate a pseudo-TTY"
bskagss

5

Những gì tôi biết về -tlà như sau:

docker exec -ti CONTAINER bash- cho phép tôi "đăng nhập" trong container. Nó cảm thấy như ssh-ing (không phải vậy).

Nhưng rắc rối là khi tôi muốn khôi phục cơ sở dữ liệu.

Thông thường tôi làm docker exec -ti mysql.5.7 mysql- Ở đây tôi thực thi lệnh mysql trong container và nhận một thiết bị đầu cuối tương tác.

Tôi đã thêm vào <dump.sqllệnh trước để tôi có thể khôi phục db. Nhưng nó đã thất bại với cannot enable tty mode on non tty input.

Loại bỏ sự -tgiúp đỡ. Vẫn không hiểu tại sao:

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

Cái cuối cùng hoạt động. Hy vọng điều này sẽ giúp mọi người.


Tôi có thể bắt đầu tty trong docker không? Tôi có một số ứng dụng ngừng hoạt động Tôi không chạy docker với -t, nhưng tôi không thể sửa đổi lệnh bắt đầu docker trong sản xuất. Vì vậy, tôi cần phải làm cho ứng dụng nghĩ rằng nó đã được bắt đầu với -t.
mvorisek

1

Trong linux khi bạn chạy một lệnh, bạn cần một terminal (tty) để thực thi nó.

Vì vậy, khi bạn muốn kết nối với docker (hoặc chạy lệnh trong container docker), bạn phải cung cấp tùy chọn -t trong việc xem xét thiết bị đầu cuối bên trong container docker.


0

Mỗi quá trình có ba luồng dữ liệu tức là STDIN/ STDOUT/ STDERR. Khi một tiến trình đang chạy trong một container, theo mặc định, terminal được kết nối với luồng STDOUT của tiến trình đang chạy trong container. Do đó tất cả các luồng đầu ra sẽ hiển thị trong khi chạy docker runlệnh trong thiết bị đầu cuối. Nhưng nếu bạn muốn cung cấp đầu vào cho quy trình đang chạy trong vùng chứa thì bạn phải kết nối với kênh STDIN của quy trình không theo mặc định và được thực hiện bằng docker run -ilệnh.

-t được sử dụng cho các hoạt động đầu vào tương tác / định dạng.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.