Остановите и удалите контейнер докеров, если он запущен


81

Я хочу прагматично остановить и удалить контейнер докера, если он запущен. Это для сценария сборки.

Возьмем следующий пример. Как мне остановить и удалить докер-контейнер rabbitmq, как показано в столбце NAMES в сценарии bash?

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

Ответы:


189

Как вы, наверное, заметили, docker stopа также docker rmвыход с кодом состояния, указывающим на сбой, если контейнер не существует или не запущен. Это приводит к сбою сборки.

Если вы можете справиться с сообщениями об ошибках в журнале сборки, вы можете сделать этот небольшой трюк, чтобы предотвратить сбой команды оболочки:

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

В случае сбоя одной из команд docker trueвызывается, который всегда завершается с кодом состояния, указывающим на успех.


Сообщение об ошибке, что контейнер не существует, по-прежнему возвращается, но код состояния указывает на успех. Мой бамбуковый конвейер работает без сбоев, поэтому он работает для меня.
— shamanSK

3
Это будет сгенерировано, Error response from daemon: no such id: rabbitmqкогда контейнер уже удален.
— anubhava 02

3
@anubhava: Верно. Как уже упоминалось в ответе: «Уловка» состоит в том, чтобы просто игнорировать возвращаемое значение команд докеров. Если вам нужно «чистое» решение без сообщений об ошибках, вам нужно проверить, присутствует ли контейнер.
— Йоханнес Бароп 08

Для меня эта команда больше не работает, раньше работала, а теперь нет ... Такое бывает с кем-нибудь еще?
— joudaon

37

У меня аналогичная проблема, но мне не понравился принятый ответ, поскольку он подавляет все ошибки команд, а не только ошибку «не найдено».

Однако docker ps -q --filter "name=rabbitmq"выводит результат только в том случае, если контейнер с таким именем действительно существует, поэтому, вдохновленный Test, если команда выводит пустую строку, которую я придумал:

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

5
Считаю полезным пользоваться docker ps -aq .... Эта -aопция означает, что он также найдет контейнеры, которые существуют, но в настоящее время не работают.
— Питер Блумфилд

Отличный ответ, я просто использовал это в сценарии bash, позвольте ему перезапустить контейнер докера, если он уже запущен. Также используется ps -aq, как предлагает @PeterBloomfield.
— Psiloc

если контейнер не найден, grep -q .также имеет ненулевой существующий код и, следовательно, всю вашу строку. Так что это все равно приводит к ошибке. Что заставило бы меня добавить || echo 'not found'или что-то в этом роде. И здесь нет большой разницы с принятым ответом
— Felix B.

Чтобы фильтр не влиял на общий код возврата команды, вы можете реорганизовать его как оператор if:if docker ps -q --filter "name=rabbitmq" | grep -q .; then docker stop rabbitmq && docker rm -fv rabbitmq; fi
— ncoghlan

23

Уже давно пользуюсь докером. Это мой предпочтительный способ остановки и удаления контейнера докеров. Принцип истины нужен для того, чтобы всегда обеспечивать успех. Без него все сценарии bash завершились бы и выдали ошибку, если бы имя контейнера не существовало.

docker rm -f container_name || true

11
docker rm -f container_name &>/dev/null && echo 'Removed old container'
— filimonov

док-контейнер rm | Документация Docker : принудительное удаление работающего контейнера (использует SIGKILL) .
— Джейсон Лоу

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команда получает appпеременную командной строки из переменной BASH$app
  • NR>1пропускает первую строку заголовка из docker psкоманды.
  • $(NF) == appСравнить последний столбец NAMESравен переменной приложения или нет

привет, спасибо за ответ, он работает. Не могли бы вы немного рассказать, чем он занимается. Если у меня есть app = '' some-rabbitmq ', ему не нравится шумиха?
— Robbo_UK

Он должен работать с дефисами, в ответ я добавляю пояснения.
— анубхава

1
слишком сложное решение. Второй ответ лучше
— Scoota P

2
Это наиболее полный ответ. проблема с добавлением `|| true` заключается в том, что все еще существует сценарий bash с ошибкой докера. проверив список контейнеров докеров для контейнера, вы гарантированно вызовете только stop и rm, если они существуют, исключив ошибки и позволив скрипту выполнить все необходимые команды контейнера.
— AsAP_Sherb 05

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

4

Я предлагаю это заклинание в bash:

( docker stop $CONTAINER > /dev/null && echo Stopped container $CONTAINER && \
  docker rm $CONTAINER ) 2>/dev/null || true

Он всегда завершается с 0, не жалуется, если контейнер не запущен, и печатает, Stopped container $CONTAINERесли он действительно остановился.


Чистый срыв, который "терпит неудачу" молча, если контейнер не найден, но не молча stop/ rmконтейнер, если он найден.
— emmagras 03

2

Общая форма, основанная на некоторых ответах здесь:

docker rm -f container_name > /dev/null 2>&1 && echo 'removed container' || echo 'nothing to remove'


0

Скопируйте этот код в свой script.sh, если хотите, stopи removeвсе

#!/bin/sh
ids=$(docker ps -a -q)
for id in $ids
do
  echo "$id"
  docker stop $id && docker rm $id
done

0

Если вы не удалите остановленные контейнеры, другой простой способ решить эту проблему - положиться на него docker ps -a, который всегда будет возвращать этот идентификатор контейнера. Затем выполнение docker stopв этом остановленном контейнере идемпотентно просто ничего не сделает:

docker stop $(docker ps -a --filter name= rabbitmq -q )


-2

чтобы сначала остановить все контейнеры, вы должны остановить все контейнеры с помощью

docker kill $(docker ps -q)

и удалить все контейнеры

docker rm $(docker ps -a -q)

и если вы хотите удалить все изображения, это команда

docker rmi $(docker images -q)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.