Зупиніть і видаліть контейнер докера, якщо він запущений


81

Я прагну практично зупинити та видалити контейнер докера, якщо він запущений. Це для сценарію збірки.

Візьмемо такий приклад. Як зупинити та видалити контейнер докера "rabbitmq", як показано в стовпці НАЗВИ у сценарії 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

У разі відмови однієї з команд докера trueвикликається, яка завжди виходить із кодом стану, що вказує на успіх.


Повідомлення про помилку про те, що контейнер не існує, все ще повертається, але код стану вказує на успіх. Мій бамбуковий трубопровід обробляється без збоїв, тому він працює для мене.
shamanSK

3
Це генерується, Error response from daemon: no such id: rabbitmqколи контейнер уже видалено.
анубхава

3
@anubhava: Правильно. Як вже зазначалося у відповіді: "Хитрість" полягає у просто ігноруванні поверненого значення команд докера. Якщо вам потрібно "чисте" рішення без повідомлень про помилки, вам потрібно перевірити, чи є контейнер.
Йоганнес Бароп,

Для мене ця команда вже не працює, вона працювала раніше, але зараз не ... Чи трапляється це з кимось іншим?
joudaon

37

У мене схожа проблема, але мені не сподобалася прийнята відповідь, оскільки вона придушує всі помилки команд, а не лише помилку "не знайдено".

Однак docker ps -q --filter "name=rabbitmq"результат видається лише в тому випадку, якщо контейнер з цим ім'ям насправді існує, тому натхненний тестом, якщо команда видає порожній рядок, який я придумав:

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'чи щось подібне. І на той момент різниця між прийнятою відповіддю і не є великою
Фелікс Б.

Щоб уникнути впливу фільтра на загальний код повернення команди, ви можете перефакторизувати його як оператор 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'
Філімонов

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

привіт спасибі за відповідь це працює. Не могли б ви трохи розширити те, що він робить. Якщо у мене є app = '' some-rabbitmq ', це не подобається hypen?
Robbo_UK

Це повинно працювати з дефісами, я додаю пояснення у відповідь.
анубхава

1
занадто складне рішення. Друга відповідь краща
Scoota P

2
Це найбільш повна відповідь. проблема з додаванням `|| true` все ще існує сценарій 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

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.03.20

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.