Skip to main content

在Docker容器中如何用docker exec运行命令

导语

Docker为开发者们提供了一个打包工具,帮助开发者创建与管理可移植且能保持一致的的Linux容器。

在开发与使用容器时,经常需要查看一个正在运行的容器,检查其状态或是进行debug。对此,可以使用Docker提供的 docker exec 命令,在运行中的容器内部再运行命令。

本教程中,我们将了解 docker exec 命令,了解如何用它在一个运行中的Docker容器中运行命令并得到一个交互式shell。

前期准备

本教程需要读者提前完成Docker的安装,并拥有运行 docker 的权限。如果需要作为root用户运行 docker,请在本教程中的命令前加上 sudo

启动一个测试用容器

docker exec 命令需要在一个运行中的Docker容器里运行。如果没有现成的容器,可以用 docker run 命令启动一个测试用容器:

$ docker run -d --name container-name alpine watch "date >> /var/log/date.log"

这会创建一个基于官方 alpiane 镜像的容器。alpine 镜像是一个很流行的容器镜像,使用了Linux的轻量简化版Alpine Linux。

-d 标记用于将容器从终端中分离,使其在后台运行。命令 --name container-name 会将容器命名为 container-name,可以使用任意名称,也可以留为空白,Docker会为新容器自动生成一个独特名称。

随后的 alpine 指定了容器使用的镜像。

最后的 watch "date >> /var/log/date.log" 部分是需要在容器内部运行的命令。watch 会重复运行给定的命令,默认间隔为两秒。在这个例子里,watch 会运行命令 date >> /var/log/date.logdate 会打印现在的日期与时间,效果如下:

Output

Fri Jul 23 14:57:05 UTC 2021

而指令中的 >> /var/log/date.log 部分会将 date 的输出导入到文件 /var/log/date.log 中,附加在文件底部。每过两秒,新的一行就会附加在文件底部。一段时间后,文件内部就会如下:

Output

Fri Jul 23 15:00:26 UTC 2021
Fri Jul 23 15:00:28 UTC 2021
Fri Jul 23 15:00:30 UTC 2021
Fri Jul 23 15:00:32 UTC 2021
Fri Jul 23 15:00:34 UTC 2021

下一步中将会解释如何找到Docker容器的名称。当如果已经有一个目标容器,却不确定该容器的名称时,下一步中的内容会十分有用。

寻找Docker容器的名称

在运行 docker exec 前,需要输入容器的名称(或ID)来指定想要使用的容器。可以用 docker ps 命令来寻找这些信息:

$ docker ps

这条命令会列出目前服务器中正在运行的所有Docker容器,还会给出它们的一些高级信息:

Output

CONTAINER ID   IMAGE     COMMAND
76aded7112d4 alpine "watch 'date >> /var…"

CREATED STATUS PORTS
11 seconds ago Up 10 seconds

NAMES
container-name

在这个例子中,容器名与ID都可以用在 docker exec 中指定所用容器。

如果需要重命名容器,可以用 docker rename 命令:

$ docker rename container-name new-name

接下来,我们会分析几个用 docker exec 在运行中的Docker容器里运行命令的例子。

在Docker容器内运行交互性shell

当需要在Docker容器中启动一个交互式shell时,例如为了检视文件系统或debug正在运行的进程时,可以用 docker exec 后加 -i-t 标记。

-i 标记用来保持输入始终在容器中打开,而 -t 标记会给shell分配一个伪终端。这些标记可以结合,写法如下:

$ docker exec -it container-name sh

该命令会在指定的容器中运行 sh shell,并提供基本的shell提示符。如果要退出容器,输入 exit 然后按下ENTER键:

/# exit

如果容器镜像中包含更高级的shell,例如 bash,可以将上面的 sh 替换为 bash

在Docker容器内部运行一个非交互式的命令

如果想在运行中的容器内部运行非交互式的命令,可以直接使用 docker exec 命令,不加任何标记:

$ docker exec container-name tail /var/log/date.log

这个命令会在 container-name 容器中运行 tail /var/log/date.log,并输出结果。默认情况下,tail 会打印出文件的最后十行。以刚才在第一部分创建的容器为例,以下结果会被输出:

Output

Mon Jul 26 14:39:33 UTC 2021
Mon Jul 26 14:39:35 UTC 2021
Mon Jul 26 14:39:37 UTC 2021
Mon Jul 26 14:39:39 UTC 2021
Mon Jul 26 14:39:41 UTC 2021
Mon Jul 26 14:39:43 UTC 2021
Mon Jul 26 14:39:45 UTC 2021
Mon Jul 26 14:39:47 UTC 2021
Mon Jul 26 14:39:49 UTC 2021
Mon Jul 26 14:39:51 UTC 2021

本质上,这等同于在Docker容器内打开一个交互式shell,并在shell内运行 tail /var/log/date.log 命令。然而,这个方法不需要打开shell及在命令完成后关闭shell,也不需要分配一个伪终端,只需要一条命令就可以得到一样的输出。

在Docker容器中的自选路径运行命令

--workdir 标记指定路径,就可以在容器内部的指定路径运行命令:

$ docker exec --workdir /tmp container-name pwd

这条指令会创建 /tmp 路径作为工作路径,然后运行 pwd 命令。pwd 命令会打印出目前的工作路径:

Output

/tmp

这个结果确认了目前工作路径是 /tmp

以不同用户身份在Docker容器内部运行命令

添加 --user 标记即可在容器内以不同用户身份运行命令:

$ docker exec --user guest container-name whoami

这会以guest用户在容器内运行 whoami 命令。whoami 会打印目前用户的用户名:

Output

guest

这个结果证实了目前容器内的用户是guest

将环境变量传入Docker容器内

有时,在将命令传入容器的同时还需要一同传入环境变量。-e 标记可以用于指定一个环境变量。

$ docker exec -e TEST=sammy container-name env

这条命令会将 sammy 赋值给 TEST 环境变量,然后在容器内运行 env 命令。env 会打印所有环境变量:

Output

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=76aded7112d4
TEST=sammy
HOME=/root

可以看到,TEST 已被设置为 sammy

如果要给多个变量赋值,需要重复 -e 标记:

$ docker exec -e TEST=sammy -e ENVIRONMENT=prod container-name env

如果需要将一个全部是环境变量的文档传入,可以用 --env-file 标记。

首先,用文档编辑器创建一个文件。在这个例子中,我们使用 nano 打开新文件,你也可以用任何你喜欢的编辑器:

$ nano .env

.env 作为文件名,这是用此类文件控制版本之外信息的一个普遍标准。

现在在文件内用 KEY=value 格式赋值变量,每个变量一行,如下:

TEST=sammy
ENVIRONMENT=prod

随后,保存并关闭文件。先按 CTRL+0,在按 ENTER 就可以保存,然后按 CTRL+X 就可以退出 nano 了。

现在运行 docker exec 命令,并在 --env-file 后指定文件名:

$ docker exec --env-file .env container-name env

Output

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=76aded7112d4
TEST=sammy
ENVIRONMENT=prod
HOME=/root

可以看到文件中的两个变量已被赋值。

使用是 --env-file 标记时,可以指定多个文件。如果不同文件内部多次覆盖了同一个变量,指令内排在后面的文件会覆盖之前的。

常见报错

在使用 docker exec 命令时,可能会遇到以下几个常见报错:

Error: No such container: container-name

No such container 报错表明指定的容器不存在,可能是容器名拼写错误导致。需要用 docker ps 命令列出所有运行中容器的名字,并检查容器名输入是否有误。

Error response from daemon: Container 2a94aae70ea5dc92a12e30b13d0613dd6ca5919174d73e62e29cb0f79db6e4ab is not running

not running 消息表明虽然指定的容器存在,但已经停止运行了。可以通过 docker start container-name 命令启动容器。

Error response from daemon: Container container-name is paused, unpause the container before exec

Container is paused 报错将问题解释的比较清楚,需要用 docker unpause container-name 恢复容器的进程。

结语

本教程简单介绍了如何在运行中的容器内部再执行命令,同时给出了一些可能有帮助的命令行举例。 如果需要了解更多有关Docker的信息,请参阅Docker tag page,那里有各类Docker教程、相关问答及其它有用信息的链接。