两者都可以在容器中执行命令。 两者都可以分离容器。
那么docker exec和docker attach之间的真正区别是什么?
答案 0 :(得分:68)
有一个commit PR添加到doc:
注意:此命令(
attach
)不适用于在容器中运行新进程。 请参阅:docker exec
。
“Docker. How to get bash\ssh inside runned container (run -d
)?”的答案说明了不同之处:
(docker> = 1.3)如果我们使用
docker attach
,,我们只能使用一个shell实例。
因此,如果我们想要使用容器shell的新实例打开新终端,我们只需要运行docker exec
如果使用
/bin/bash
命令启动了docker容器,则可以使用attach访问它,如果没有,则需要执行命令以使用{在容器内创建bash实例{1}}。
如this issue中所述:
- 附件不是用于在容器中运行额外的东西,而是用于附加到正在运行的进程。
- “
exec
”专门用于在已启动的容器中运行新事物,无论是shell还是其他进程。
同样的问题补充说:
虽然
docker exec
命名不好,特别是因为LXC命令attach
(更类似lxc-attach
,但LXC特定),它确实具有字面附加的特定目的你到Docker开始的过程。
根据流程的不同,行为可能会有所不同,例如附加到docker exec <container> /bin/sh
会给你一个shell,但是附加到redis-server就像你刚刚直接启动redis一样没有守护进程。
答案 1 :(得分:12)
当使用/ bin / bash启动容器时,它将成为容器 PID 1 ,并且docker attach用于获取容器的PID 1内部。所以 docker attach&lt; container-id&gt; 将带你进入bash终端,就像我们在启动容器时提到的PID 1一样。从容器中退出将停止容器。
在 docker exec 命令中,您可以指定要输入的shell。它不会将您带到容器的PID 1。它将为bash创建一个新进程。 docker exec -it&lt; container-id&gt; bash的即可。 从容器中退出不会阻止容器。
您还可以使用 nsenter 输入内部容器。 nsenter -m -u -n -p -i -t&lt;容器的pid&gt; 您可以使用以下命令找到容器的PID:docker inspect&lt; container-id&gt; | grep PID
注意:如果您已使用-d标志启动容器,则退出容器将不会停止容器,无论您使用attach还是exec进入容器。
答案 2 :(得分:1)
正如迈克尔·孙(Michael Sun)在回答中所说的
docker exec
在容器环境中执行一个新命令/创建一个新进程,而docker attach
只是将容器内主进程(带有PID 1)的标准输入/输出/错误连接到当前终端(用于运行命令的终端)的相应标准输入/输出/错误。
我的回答将更多地集中在让您验证以上陈述并更清楚地理解它。
打开一个终端窗口,然后运行命令docker run -itd --name busybox busybox /bin/sh
。该命令将拉取图像busybox
(如果尚不存在)。然后,它将使用该图像创建一个名称为busybox
的容器。
您可以通过运行命令docker ps -a | grep busybox
来检查容器的状态。
如果要运行docker top busybox
,应该会看到类似以下的输出。
UID PID PPID C STIME TTY TIME CMD
root 7469 7451 0 11:40 pts/0 00:00:00 /bin/sh
当然,PID
,PPID
和其他值在您的情况下会有所不同。您可以使用其他工具和实用程序,例如pstree
,top
,htop
来查看PID
和PPID
的列表。
PID
和PPID
表示进程ID和父进程ID。当我们创建并使用命令/bin/sh
启动容器时,该过程开始。现在,运行命令docker attach busybox
。这会将容器的标准输入/输出/错误流附加到您的终端。
在附加容器之后,通过运行命令sh
创建一个Shell会话。按CTRL-p CTRL-q
序列。这将使终端与容器分离,并使容器保持运行状态。如果现在运行docker top busybox
,则应该在列表中看到两个进程。
UID PID PPID C STIME TTY TIME CMD
root 7469 7451 0 11:40 pts/0 00:00:00 /bin/sh
root 7737 7469 0 11:43 pts/0 00:00:00 sh
但是两个过程的PPID
将不同。实际上,第二个过程的PPID
与第一个过程的PID
相同。第一个进程充当我们刚刚创建的Shell会话的父进程。
现在,运行docker exec -it busybox sh
。进入容器后,通过运行命令busybox
在另一个终端窗口中检查容器docker top busybox
的运行进程列表。您应该会看到类似的内容
UID PID PPID C STIME TTY TIME CMD
root 7469 7451 0 11:40 pts/0 00:00:00 /bin/sh
root 7737 7469 0 11:43 pts/0 00:00:00 sh
root 7880 7451 0 11:45 pts/1 00:00:00 sh
第一和第三进程的PPID
相同,这确认docker exec
在容器环境中创建了一个新进程,而docker attach
仅连接了标准输入/输出/容器内部主要过程的错误与当前端子的相应标准输入/输出/错误的对应关系。
答案 3 :(得分:0)
Docker exec在容器环境中执行一个新命令/创建一个新进程,而docker attach只是将容器内主进程(带有PID 1)的标准输入/输出/错误连接到相应的标准输入/输出/当前终端错误(您用于运行命令的终端)。
容器是一个隔离的环境,某些进程在该环境中运行。具体地说,容器具有自己的文件系统空间和PID空间,这些空间与主机和其他容器隔离。 当使用“ docker run –it…”启动容器时,主进程将具有伪tty和STDIN保持打开状态。 在tty模式下连接时,可以使用可配置的键序列从容器分离(并使它保持运行状态)。默认序列为CTRL-p CTRL-q。您可以使用--detach-keys选项或配置文件来配置键序列。 您可以使用docker attach重新连接到分离的容器。
Docker exec只是在容器环境内启动了一个新过程,也就是说,它属于容器的PID空间。
例如,如果您使用“ docker run –dit XXX / bin / bash”启动容器,则可以使用两个不同的终端将其连接到容器(主进程)。在一个端子中输入时,可以看到它出现在另一端子中,因为两个端子都连接到同一tty。 请注意,您现在处于容器的主进程中,如果键入“ exit”,则将退出容器(,请小心,使用detach-key进行分离),您将看到两个终端都退出了。 但是,如果您在两个终端上运行“ docker exec –it XXX / bin / bash”,则您已经在容器内启动了两个新进程,它们彼此之间以及与主进程之间都没有关系,因此可以安全地退出它们