停止并删除正在运行的Docker容器

151

我希望能够在构建脚本中,以实用的方式停止和删除正在运行的Docker容器。以下是一个示例,在bash脚本中如何停止并删除“rabbitmq” Docker容器(该容器在NAMES列中可见)?

docker ps

CONTAINER ID        IMAGE             COMMAND                  CREATED             STATUS              PORTS                   NAMES
9909a5e2856f        rabbitmq-image   "/docker-entrypoint.s"   11 minutes ago      Up 11 minutes       0.0.0.0:5672->5672/tcp, rabbitmq
8990dd1fe503        redis-image      "/entrypoint.sh redis"   6 weeks ago         Up 4 days           0.0.0.0:32770->6379/tcp redis
etc 
以下命令将删除容器并完成我想要的操作。
docker stop rabbitmq && docker rm -f rabbitmq

然而,我想知道如何将其组合成脚本?我认为它应该看起来像这样。

#!/bin/bash

if [ /*docker ps check some value */ ]; then
   docker stop rabbitmq && docker rm -f rabbitmq
fi
16个回答

292

你可能已经注意到,docker stopdocker rm会退出一个指示失败的状态码,如果容器不存在或未运行。这将导致构建失败。

如果你可以处理构建日志中的错误消息,你可以使用以下小技巧来防止 shell 命令执行失败:

docker stop rabbitmq || true && docker rm rabbitmq || true

如果其中一个Docker命令失败,将调用true,它始终以指示成功的状态代码退出。


容器不存在的错误消息仍然被返回,但状态码表示成功。我的竹子管道过程没有失败,所以对我有效。 - 99problems
5
当容器已被移除时,这将生成“守护进程错误响应:没有此ID:rabbitmq”的错误信息。 - anubhava
4
@anubhava: 正确。正如答案中已经提到的那样:"诀窍"就是忽略docker命令的返回值。如果你需要一个"干净"的解决方案而不出现错误信息,你需要检查容器是否存在。 - Johannes Barop
1
对我来说,这个命令不再起作用了,以前它能够正常工作,但现在却不能... 这种情况发生在其他人身上吗? - joudaon
1
你可以使用 --rm 参数来运行容器,然后使用 docker stop container_name || true 命令停止它。这将自动删除容器。 - igor

78

我有一个类似的问题,但是不喜欢接受的答案,因为它压制了所有命令的错误,而不仅仅是“未找到”的错误。

然而,只有在实际存在该名称的容器时,docker ps -q --filter "name=rabbitmq"才会产生输出,所以受Test if a command outputs an empty string启发,我得出了以下结论:

docker ps -q --filter "name=rabbitmq" | grep -q . && docker stop rabbitmq && docker rm -fv rabbitmq

以下命令对于测试过滤器定义也非常有用:

docker ps -q --filter "name=rabbitmq" | grep -q . && echo Found || echo Not Found

我的实际用例是定义一对Ansible任务,从先前任务生成的名称列表中删除所有当前存在的容器(无论是否正在运行):


- name: Check for containers that actually exist
  shell: 'docker ps -aq --filter "name={{ item }}"'
  with_items:
    - '{{ previous_command.stdout_lines }}'
  register: found_containers

- name: Remove the containers found by the above command
  shell: 'docker stop {{ item.item }} && docker rm -fv {{ item.item }}'
  with_items: '{{ found_containers.results }}'
  when: item.stdout

10
我觉得使用 docker ps -aq ... 很有用。选项 -a 表示它也会找到存在但当前未运行的容器。 - Peter Bloomfield
非常好的答案,我刚在bash脚本中使用了它,如果docker容器已经在运行,则让它重新启动。还使用了ps -aq,正如@PeterBloomfield建议的那样。 - Psiloc
如果容器未找到,则grep -q .也具有非零存在代码,因此整行都会出现错误。这仍然会导致错误。这将迫使我附加|| echo 'not found'或类似的内容。在那一点上,与接受的答案没有太大区别。 - Felix B.
1
为避免过滤器影响整个命令返回代码,您可以将其重构为if语句:if docker ps -q --filter "name=rabbitmq" | grep -q .; then docker stop rabbitmq && docker rm -fv rabbitmq; fi - ncoghlan
1
我使用 docker ps -qa --filter 命令开始操作,以确保任何崩溃的容器也会显示出来。 - Jubair

43

这是我首选的停止和删除docker容器的方式。添加true管道是为了确保它始终输出成功信息。如果没有它,任何bash脚本在容器名称不存在时都会退出并报错。

docker rm -f container_name || true

19
docker rm -f container_name &>/dev/null && echo 'Removed old container' - filimonov
1
强制删除正在运行的容器(使用SIGKILL)。 - Jason Law
您可以使用 --rm 运行容器,使用 docker stop container_name || true 命令停止容器。 - igor
1
@igor 今天才发现这个。虽然来晚了,但使用 --rm 意味着您无法利用 Docker 的重启策略。我使用 restart=unless-stopped 来排除使用 --rm。--rm 似乎是为开发目的而设计的便利功能。在部署中,您希望 Docker 在重新启动或出现错误情况后尝试重新启动容器。 - cstrutton

21
@ncoghlan的答案的一个变体:
# stop runnin container(s)
docker ps -q --filter "name=$name" | xargs -r docker stop
# remove existing container(s)
docker ps -aq --filter "name=$name" | xargs -r docker rm
  • 使用xargs的管道是利用输出构建命令的惯用方式
  • xargs -r在没有匹配容器时避免运行docker命令
  • 第一个docker ps查找所有匹配的正在运行的容器
  • 第二个docker ps查找所有匹配的容器,即使它们没有运行
  • 分开的命令确保即使容器没有运行也会被删除

13

你可以使用:

app="rabbitmq"
if docker ps | awk -v app="$app" 'NR > 1 && $NF == app{ret=1; exit} END{exit !ret}'; then
  docker stop "$app" && docker rm -f "$app"
fi
  • awk 命令从 BASH 的变量 $app 中获取一个命令行变量 app
  • NR>1 跳过 docker ps 命令的第一行标题。
  • $(NF) == app 比较最后一列 NAMES 是否等于变量 app。

嗨,谢谢你的回答,它确实有效。你能否稍微解释一下它正在做什么?如果我有一个app=''some-rabbitmq',它不喜欢连字符吗? - Robbo_UK
它应该能够使用连字符工作,我在答案中添加了一些解释。 - anubhava
1
解决方案太复杂了。第二个答案更好。 - Scoota P
2
这是最完整的答案。添加 || true 的问题在于仍然存在一个带有 Docker 错误的 bash 脚本。通过检查容器列表,您可以确保只有在容器存在时才调用 stop 和 rm,消除错误并允许脚本运行所需的所有容器命令。 - AsAP_Sherb

7
# Stop and remove containers with names like "rabbitmq" and "rabbitmq123" if they exist
CONTAINER_NAME="rabbitmq"
OLD="$(docker ps --all --quiet --filter=name="$CONTAINER_NAME")"
if [ -n "$OLD" ]; then
  docker stop $OLD && docker rm $OLD
fi

5
我建议在bash中使用以下咒语:
( docker stop $CONTAINER > /dev/null && echo Stopped container $CONTAINER && \
  docker rm $CONTAINER ) 2>/dev/null || true

该命令总是以0结束,如果容器未在运行,则不会报错,并且如果它确实被停止,则会打印Stopped container $CONTAINER


干净的拆除,如果没有找到容器,则会“静默”失败,但如果找到容器,则不会静默地stop/rm容器。 - emmagras

3

基于这里的一些答案,可以构建一个通用表格:

docker rm -f container_name > /dev/null 2>&1 && echo '已删除容器' || echo '没有要删除的内容'


2

尝试下面的函数。改编自https://dev59.com/_lkT5IYBdhLWcg3wc_JR#60579344

    function remove_previous_instance(){
        echo "Container name: $1"
        CNAME=$1
        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
    }

称之为:

调用它: remove_previous_instance "CNAME"


2

停止容器操作 for i in $(docker ps | awk '{print $1}) ; do docker stop "$i"; done

删除容器操作 for i in $(docker ps | awk '{print $1}) ; do docker rm "$i"; done


1
你的回答可以通过添加更多支持信息来改进。请[编辑]以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Ethan

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