首页 > 其他分享 >如何正确使用docker run -i -t -d 参数

如何正确使用docker run -i -t -d 参数

时间:2023-02-04 13:23:58浏览次数:72  
标签:node 容器 run -- 宿主机 参数 docker

如何正确使用docker run -i -t -d 参数

在使用docker run命令时,我们经常会使用到-i、-t-d参数,那么这几个参数的作用究竟是什么呢,这篇文章简单讲一下。

选项说明

官方文档对参数的说明:

--interactive , -i      Keep STDIN open even if not attached
--tty , -t              Allocate a pseudo-TTY
--detach , -d           Run container in background and print container ID
  • -d作用:在后台运行容器,并且打印容器id
  • -t作用:分配一个伪TTY
  • -i作用:即使没有attached,也要保持STDIN打开状态

detach选项

大多数情况下,我们都是希望Docker能够在后台运行容器,而不是直接在宿主机上与之交互。如果不加-d选项,容器会在宿主机终端运行,并且把输出的结果(STDOUT)打印到宿主机上面。

使用-d选项后,容器会在后台运行,并输出容器ID,我们可以使用docker logs [containerID]来查看容器的输出结果。如果想跟容器进行交互,可以使用docker exec -it [container ID] /bin/bash来操作。

需要注意的是,容器是否会持久运行,和-d选项无关。关于这一点,在文章docker run 如何让容器启动后不会自动停止中有介绍。

interactive选项

-i选项根据文档的解释就比较费劲了,我们不妨先看另外一个选项-a

-- attached , -a    Attach to STDIN, STDOUT or STDERR

它的意思是把宿主机标准输入,输出和错误流附加到容器。

在Linux中,STDIN是标准的输入流,通常对应终端的键盘;STDOUT是标准输出流,STDERR是标准输出流,STDERR是标准错误输出流,它们都对应终端的屏幕。进程将从标准输入文件中得到输入数据,将正常
输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。关于这方面的更多了解可以参照 What Are stdin, stdout, and stderr on Linux? 这篇文章。

那么我们再来看-i的解释:Keep STDIN open even if not attached

Keep STDIN open就是说让容器的标准输入保持打开状态,

even if not attached强调的是即使没有把宿主机标准输入,输出和错误流附加到容器依然保持容器的标准输入为打开状态。

很多人比较费解的是后半句,其实它只是一个强调。在Docker run reference中有一段提到如果没有指定-a选项,默认会attach stdout和stderr。

那么我们做一个小实验。下面的语句是通过管道把宿主机的echo test命令执行的结果作为node容器的输入,在容器中执行cat命令再通过stdout输出到宿主机。可以打印出test。

echo test | docker run --rm --name node -a stdin -a stdout -i node:12.18.3-slim cat

接下来我们不使用-a选项,得到的也是一样的结果。

echo test | docker run --rm --name node -i node:12.18.3-slim cat

这也就是说,如果加了-i选项,容器的STDIN就会一直保持打开,我们就可以以交互模式(interactive mode)来运行容器了。

交互模式

我们可以让容器运行后执行一条命令,比如前面提到的cat,看一下会发生什么:

docker run --rm --name node -i node:12.18.3-slim cat

如果我们执行的是一个持续与容器交互的程序,容器的状态就会一直保持运行状态。那么如果我们想结束掉与容器的交互呢?

docker attach命令里有介绍到,使用CTRL-c可以让容器停止运行,它是通过发送一个STGKILL信号来实现的。

image_1emb7bg8d10tf1jcf1m0pbtpkni1m.png-42.4kB

但是我们尝试了一下发现并不行,这是因为Linux 1号进程的特殊性。不过,我们可以通过CTRL-d去停止容器,因为它不是发送一个信号,而是表示一个特殊的二进制值EOF

其实这里涉及到几个Linux的知识点:

  • Linux PID1(Linux的1号进程)
  • Linux的信号(SIGINT、SIGTERM、SIGQUIT、SIGKILL、SIGHUP)
  • EOF

如果想让CTRL-c也可以生效,我们可以在docker run命令加上--init选项

docker run --rm --init --name node -i node:12.18.3-slim /bin/bash

对上面提到的几个知识做了一定了解后,我们再来看直接通过-i启动一个容器而不执行命令会发生什么。

docker run --rm --name node -i node:12.18.3-slim

image_1embc11vv1efmhb51q7sned171f23.png-9.8kB

可以看到容器正常启动并保持运行,我们在宿主机的终端输入任何字符都没有反应。

我们可以再开启另外一个终端,进入容器看一下1号进程,发现是node

$ docker exec -it node /bin/bash
$ ps -aux

image_1embccbtfkn1gjb1om61re61kv430.png-104.6kB

所以我们可以得出一个结论:如果容器启动的1号进程是一个shell程序的话,我们通过-i选项就可以与之交互,保持容器持续运行。不指定-i,容器启动后就会自动退出。

现在还有一个问题就是,如果只指定了-i选项,我们在宿主机终端输入任何字符都没有反应。这个问题,我们可以用-it来解决,所以我们接下来就介绍一下-t选项的作用。

tty选项

如果对Linux的TTY比较熟悉的话,对于这个选项就比较了解了。我们可以把它理解为Linux的终端程序,所以-t选项就可以理解为为容器分配一个伪tty终端并绑定到容器的标准输入上,之后用户就可以通过终端来控制容器了。

一般-t都是与-i一起出现的,也就是-it。再讲这个之前,我们先单独分析一下-t吧。

我们首先试一下运行容器后执行一个交互命令,看与-i的区别是什么:

docker run --rm --name node -t node:12.18.3-slim cat

执行完后,容器也可以保持运行。与单独指定-i不一样的是,在终端中输入任何字符都没有反应;CTRL-d终止不了容器;直接关闭宿主机的终端,容器还继续保持运行。

我们来解释一下执行的结果为什么是这样的。首先,输入任何字符都没有反应,是因为容器没有打开标准输入,我们输入的任何字符都是没有传递进容器的。所以cat一直会在等待永远不会到来的输入,也就一直保持容器运行状态。CTRL-d同样也不会传递到容器,直接关闭宿主机的终端也是同样的道理,因为它是在容器内部分配了一个伪终端。所以,我们关闭宿主机的终端后,开启一个新的终端输入docker ps,可以看到容器仍然在运行。

通过-t选项直接运行一个容器也是一样的结果。

docker run --rm --name node -t node:12.18.3-slim

执行完后,容器也可以持续运行。与单独指定-i不一样对是,在终端中输入任何字符都没有反应;CTRL-d终止不了容器;直接关闭宿主机的终端,容器还继续保持运行。

我们来解释一下执行的结果为什么是这样的。首先,输入任何字符都没有反应,是因为容器没有打开标准输入,我们输入的任何字符都是没有传递进容器的。所以cat一直会等待永远不会到来的输入,也就一直保持容器运行状态。CTRL-d同样也不会传递到容器,直接关闭宿主机的终端也是同样的道理,因为它是容器内部分配的一个伪终端。所以,我们关闭宿主机的终端后,开启一个新的终端输入docker ps,可以看到容器仍然在运行。

通过-t选项直接运行一个容器也是一样的结果。

docker run --rm --name node -t node:12.18.3-slim

image_1embjiati177np9t17uiuk31q5f3q.png-14.4kB

我们可以看到与-i不同的是,它会使用伪终端进入到node到shell中,但是我们输入任何字符都是没用的。关闭宿主机的终端后,容器依然运行。

这也就解释了为什么容器启动的1号进程是一个shell程序的话,我们使用-dt就可以保持容器持续在后台运行。

-it

前面我们知道了如果直接执行docker run,它默认会有stdout流,如果我们加了-i,它会保持stdin流打开。那么,我们再加上-t选项,就是说标准输入变成了一个伪tty终端。从这里也可以看出,交互模式下单独指定-t选项是没有意义的,因为如果容器的标准输入没有打开,我们是输入不了任何内容的。

简单来说,指定-t而不指定-i,意味着在容器里开启了一个伪终端,但是我们的输入并不会传递到伪终端的输入。

所以,官方文档也写道了,在交互模式下,-i-t选项必须结合使用,也就是-it

image_1embgldkgurj1t191201g081m6q3d.png-20kB

那么,我们使用-it选项来启动一个容器,看一下有哪些变化:

docker run --rm --name node -it node:12.18.3-slim

我们进入了node的shell,并且可以使用快捷键Tab来显示信息。

image_1embl9gtb11p18pl2j11au19v47.png-107.2kB

也可以通过CTRL-c来退出交互模式。

image_1emblccqol781u1n3rb9i43bm4k.png-30.6kB

参考:

https://jerrymei.cn/docker-run-interactive-tty-detach/

  1. [What's the difference between ^C and ^D for UNIX/Mac OS X terminal?](https://superuser.com/questions/169051/whats-the-difference-between-c-and-d-for-unix-mac-os-x-terminal#:~:text=Ctrl C tells the terminal,as a desire to exit.&text=Ctrl %2B D ( ^D ) means end of file.)
  2. Avoid running Node.js as PID 1 under Docker images
  3. Linux命令中Ctrl+z、Ctrl+c和Ctrl+d
  4. linux的 0号进程 和 1 号进程
  5. Termination-Signals
  6. Linux 的伪终端的基本原理 及其在远程登录(SSH,telnet等)中的应用
  7. What is a TTY on Linux? (and How to Use the tty Command)
  8. What does “the input device is not a TTY” exactly mean in “docker run” output?
  9. [Confused about Docker -t option to Allocate a pseudo-TTY](

标签:node,容器,run,--,宿主机,参数,docker
From: https://www.cnblogs.com/alvisClub/p/17091305.html

相关文章