97

两者都将能够在容器中执行命令。两者都可以分离容器。

那么 docker exec 和 docker attach 之间的真正区别是什么?

4

4 回答 4

91

有一个提交 PR添加到文档中:

注意:此命令 ( attach) 不适用于在容器中运行新进程。见:docker exec

Docker.How to get bash\ssh inside runned container ( run -d)? ”的答案说明了不同之处:

(docker >= 1.3) 如果我们使用docker attach我们只能使用一个 shell 实例
因此,如果我们想用容器外壳的新实例打开新终端,我们只需要运行docker exec

如果 docker 容器是使用/bin/bash命令启动的,则可以使用 attach 访问它,如果没有,则需要执行命令以使用exec.

本期所述:

  • 附加不是为了在容器中运行额外的东西,它是为了附加到正在运行的进程。
  • " docker exec" 专门用于在已经启动的容器中运行新事物,无论是外壳还是其他进程。

同样的问题补充说:

虽然attach没有很好的命名,特别是因为 LXC 命令lxc-attach(更相似docker exec <container> /bin/sh,但特定于 LXC),但它确实有一个特定的目的,即从字面上将您附加到 Docker 启动的进程。
根据进程的不同,行为可能会有所不同,例如附加到/bin/bash会给你一个 shell,但附加到 redis-server 就像你刚刚直接启动 redis 而没有守护进程一样。

于 2015-06-21T07:05:05.677 回答
30

当使用 /bin/bash 启动容器时,它将成为容器PID 1并且 docker attach 用于进入容器的 PID 1 内部。所以docker attach < container-id >将带你进入 bash 终端,因为它是我们在启动容器时提到的 PID 1。从容器中退出将停止容器。

而在docker exec命令中,您可以指定要进入的 shell。它不会带您进入容器的 PID 1。它将为 bash 创建一个新进程。 docker exec -it < 容器 ID > bash。从容器中退出不会停止容器。

您还可以使用nsenter进入容器内部。 nsenter -m -u -n -p -i -t < pid of container > 你可以使用以下命令找到容器的 PID: docker inspect < container-id > | grep PID

注意:如果您使用 -d 标志启动了容器,则退出容器不会停止容器,无论您使用 attach 还是 exec 进入。

于 2017-05-09T08:13:28.550 回答
16

正如迈克尔孙在他的回答中所说

docker exec在容器环境中执行一个新命令/创建一个新进程,而docker attach只是将容器内的主进程(PID 1)的标准输入/输出/错误连接到当前终端(终端)的相应标准输入/输出/错误您正在使用来运行命令)。

我的回答将更多地集中在让您验证上述陈述并更清楚地理解它。

打开终端窗口并运行命令docker run -itd --name busybox busybox /bin/shbusybox如果图像不存在,该命令将拉取图像。然后它将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

当然PIDPPID和其他值在您的情况下会有所不同。您可以使用其他工具和实用程序以及pstree,tophtop查看 和 的PID列表PPID

PIDandPPID表示进程 ID 和父进程 ID 。当我们使用命令创建并启动我们的容器时,该过程就开始了/bin/sh。现在,运行命令docker attach busybox。这会将容器的标准输入/输出/错误流附加到您的终端。

附加容器后,通过运行命令创建一个 shell 会话sh。按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 shbusybox进入容器后,通过运行命令在另一个终端窗口中检查容器的运行进程列表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只是将容器内主进程的标准输入/输出/错误连接到当前对应的标准输入/输出/错误终端。

于 2019-07-20T17:05:55.043 回答
6

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-keys 来分离),你会看到两个终端都退出了。但是如果你在两个终端运行“docker exec –it XXX /bin/bash”,那么你已经在容器内启动了两个新进程,它们彼此无关,与主进程无关,你可以安全地退出它们.

于 2018-09-06T07:34:04.710 回答