如果不存在给定名称的Docker容器,如何执行Bash命令?

132
在Jenkins机器上,我想创建一个指定名称的Docker容器,但仅当它不存在时(在shell脚本中)。我认为可以运行创建容器的命令,并忽略失败(如果有的话),但这会导致我的Jenkins作业失败。
因此,我想知道如何使用bash检查Docker容器是否存在。
14个回答

225

您可以通过搜索 <name> 来检查未运行的容器是否存在,然后稍后像这样启动它:

[ ! "$(docker ps -a | grep <name>)" ] && docker run -d --name <name> <image>

更好的方式:

利用https://docs.docker.com/engine/reference/commandline/ps/命令检查已退出的容器是否阻塞,以便在运行容器之前先将其删除:

if [ ! "$(docker ps -a -q -f name=<name>)" ]; then
    if [ "$(docker ps -aq -f status=exited -f name=<name>)" ]; then
        # cleanup
        docker rm <name>
    fi
    # run your container
    docker run -d --name <name> my-docker-image
fi

4
没错 - 你需要使用 -a 参数,否则尝试运行一个已退出的容器将会失败。 - ldg
14
如果您有两个名称相似的容器,此响应将无效。例如:cool.project(容器1)和dashboard.cool.project(容器2)。 - Maxim Tkach
2
@MaximTkach这就是为什么使用第二种方法更好,即在docker ps命令中完全限定容器名称。但是您也可以在grep命令中引入正则表达式以查找名称前后的空格。此测试有意留给读者。 - ferdy
3
WiRai的回答更简短,没有与grep相关的问题。 - erik258
4
docker ps -aq -f name=^name$ 只匹配完全相同的名称。 - Olix
显示剩余2条评论

56

我想

docker container inspect <container-name> || docker run...

由于 Docker 容器检查调用会在容器不存在时将 $? 设置为 1(不能检查),但在容器存在时将其设置为 0(这尊重停止的容器)。因此,如果容器不存在,run 命令将会按预期被调用。


22
我会选择使用 docker container inspect <容器名称> > /dev/null 2>&1 命令来丢弃成功和失败的输出。 - Mikhail Vasin
这实际上是更实用/更少容易出错的答案;通常更好地依赖于退出代码而不是文本处理,因为文本输出更有可能在不同的版本中发生变化。 - Gerard van Helden

41

您可以使用 docker ps 命令的 filterformat 选项,避免与类Unix工具(如 grep, awk 等)一起使用管道。

name='nginx'

[[ $(docker ps --filter "name=^/$name$" --format '{{.Names}}') == $name ]] ||
docker run -d --name mynginx <nginx-image>

6
这将匹配部分字符串,但是你可以使用 --filter "name=^/$name$" 来获得精确匹配。 - bcoughlan
@bcoughlan,这个在哪里有文档记录呢?anubhava:https://dev59.com/questions/_lkT5IYBdhLWcg3wc_JR#43202632 已经提到过了,你可以参考一下。 - Ciro Santilli OurBigBook.com
3
第一个 $ 的作用是将 name 替换为名为 name 的 shell 变量的值。这个变量在之前被定义过。"name=^/$name$" 相当于 "name=^/${name}$"(个人认为后者更易读)。 - fstamour

26
只需要在名称前加上^ /,后缀为$。看起来这是一个正则表达式:
CONTAINER_NAME='mycontainername'

CID=$(docker ps -q -f status=running -f name=^/${CONTAINER_NAME}$)
if [ ! "${CID}" ]; then
  echo "Container doesn't exist"
fi
unset CID

22

使用 docker top 命令可以更加简洁:

docker top <name> || docker run --name <name> <image>

docker top 返回非零值当没有匹配名称的容器运行时,否则它返回进程ID、用户、运行时间和命令。


小提示:问题是“是否存在”,而不是“是否运行”...我使用了您的解决方案,没有考虑到我的容器在那个时间点可能已经停止...似乎我必须进行检查,即使顶部较短。 - andymel

11

不带未记录行为的强大grep ^$

这是我能找到的最精确和灵活的方法:

container_name=mycont
if sudo docker ps -a --format '{{.Names}}' | grep -Eq "^${container_name}\$"; then
  echo exists
else
  echo 'does not exist'
fi

背景:

  1. https://dev59.com/_lkT5IYBdhLWcg3wc_JR#38576401 如果容器名是另一个容器的子串,则无法正常使用
  2. https://dev59.com/_lkT5IYBdhLWcg3wc_JR#45171589https://dev59.com/_lkT5IYBdhLWcg3wc_JR#43202632 依赖于我找不到文档支持的行为: docker container inspect 的退出状态和 -f name 接受某种形式的正则表达式。

Python

这里提供了Python版本,以便于在项目中使用:

containers = subprocess.check_output([
        'sudo',
        'docker',
        'ps',
        '-a',
        '--format', '{{.Names}}',
]).decode()
if container_name in containers.split():
    # Exists.

9
这是我用来检查运行中容器、停止它并移除它的解决方案。
CNAME=$CONTAINER_NAME-$CODE_VERSION
if [ "$(docker ps -qa -f name=$CNAME)" ]; then
    echo ":: Found container - $CNAME"
    if [ "$(docker ps -q -f name=$CNAME)" ]; then
        echo ":: Stopping running container - $CNAME"
        docker stop $CNAME;
    fi
    echo ":: Removing stopped container - $CNAME"
    docker rm $CNAME;
fi

我不止一次地搜索了这个问题,因为即使上面有100多个回答,它们实际上并不能起作用。我认为原因是对于docker ps的误解。 docker ps 显示正在运行的容器。docker ps -q 也是如此,但输出内容只包括容器ID。docker ps -a 列出所有容器(无论是否在运行中)。docker ps -qa 是所有容器的简单列表,而docker ps -q 是正在运行的容器的简单列表。docker ps -q -f name=ContainerName是具有名称 ContainerName 的正在运行的容器的简单列表。docker ps -qa -f 将包括已退出的容器,因此逻辑必须检查 -a(包括所有容器,无论是否在运行状态),然后再没有 -a,以查看它不仅仅存在,而且正在运行(需要先停止)。

1
这些对我的使用情况非常完美:每次重新创建容器,无论它是否存在。 - Vitalis

2

我使用以下代码来确定是否存在Docker容器:

CONTAINER_NAME='my_docker_container'
# Checking if docker container with $CONTAINER_NAME name exists.
COUNT=$(docker ps -a | grep "$CONTAINER_NAME" | wc -l)
if (($COUNT > 0)); then
    echo 'container exists'
fi

如果子字符串匹配失败,或者ps -a的其他字段匹配失败,并且您不需要wc,则可以直接使用grep状态。我的版本没有这些问题:https://dev59.com/_lkT5IYBdhLWcg3wc_JR#50841982 - Ciro Santilli OurBigBook.com

2

-a 如果你想列出所有状态(停止、运行等)
-f status=running (如果只想列出正在运行的容器,则不需要)

$ docker ps -f name=containerName | grep containerName

如果命令的状态码有1行或更多行,则为0。如果没有容器,grep将以1状态码结束。您可以通过以下方式处理它:
Windows
$ echo %errorlevel%

Linux

$ echo $?

容器正在运行

当容器停止时

查看execSync的属性 Ref: https://www.cyberciti.biz/faq/linux-bash-exit-status-set-exit-statusin-bash/


1
这是一个关于通过确切名称检查Docker容器是否存在的示例:
(docker ps -a --format {{.Names}} | grep container_name -w) && echo Exists || echo "Doesn't exist"

这是 https://dev59.com/_lkT5IYBdhLWcg3wc_JR#50841982 的副本。 - SiKing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接