两者都将能够在容器中执行命令。两者都可以分离容器。
那么 docker exec 和 docker attach 之间的真正区别是什么?
有一个提交 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 而没有守护进程一样。
当使用 /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 进入。
正如迈克尔孙在他的回答中所说
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
andPPID
表示进程 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 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
只是将容器内主进程的标准输入/输出/错误连接到当前对应的标准输入/输出/错误终端。
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”,那么你已经在容器内启动了两个新进程,它们彼此无关,与主进程无关,你可以安全地退出它们.