После некоторого исследования и тестирования я обнаружил, что у меня есть некоторые недопонимания относительно времени жизни контейнеров Docker. Простой перезапуск контейнера не заставляет Docker использовать новый образ, если тем временем образ был перестроен. Вместо этого Docker получает образ только перед созданием контейнера. Таким образом, состояние после запуска контейнера является постоянным.
Почему требуется удаление
Следовательно, перестройки и перезапуска недостаточно. Я думал, что контейнеры работают как служба: остановите службу, внесите изменения, перезапустите ее, и они будут применены. Это была моя самая большая ошибка.
Поскольку контейнеры являются постоянными, вы должны docker rm <ContainerName>
сначала удалить их, используя . После того, как контейнер удален, вы не можете просто запустить его docker start
. Это нужно сделать с помощью docker run
, который сам использует последний образ для создания нового экземпляра контейнера.
Контейнеры должны быть максимально независимыми
Обладая этими знаниями, становится понятно, почему хранение данных в контейнерах считается плохой практикой, и Docker рекомендует вместо этого тома данных / монтирование хост-каталогов : поскольку контейнер должен быть уничтожен для обновления приложений, сохраненные данные внутри тоже будут потеряны. Это вызывает дополнительную работу по отключению служб, резервному копированию данных и так далее.
Таким образом, это разумное решение для полного исключения этих данных из контейнера: нам не нужно беспокоиться о наших данных, когда они безопасно хранятся на хосте, а контейнер содержит только само приложение.
Почему -rf
может тебе не помочь
docker run
Команда имеет Очистите переключатель под названием -rf
. Это остановит поведение докер-контейнеров навсегда. Используя -rf
, Docker уничтожит контейнер после его выхода. Но у этого переключателя есть две проблемы:
- Docker также удаляет тома без имени, связанного с контейнером, что может убить ваши данные.
- Используя этот параметр, невозможно запускать контейнеры в фоновом режиме с помощью
-d
переключателя
Хотя -rf
коммутатор является хорошим вариантом для экономии работы во время разработки для быстрых тестов, он менее подходит для производства. Особенно из-за отсутствия возможности запускать контейнер в фоновом режиме, что в большинстве случаев необходимо.
Как снять контейнер
Мы можем обойти эти ограничения, просто удалив контейнер:
docker rm --force <ContainerName>
Переключатель --force
(или -f
), который использует SIGKILL для запущенных контейнеров. Вместо этого вы также можете остановить контейнер до:
docker stop <ContainerName>
docker rm <ContainerName>
Оба равны. docker stop
также использует SIGTERM . Но использование --force
переключателя сократит ваш сценарий, особенно при использовании серверов CI: docker stop
выдает ошибку, если контейнер не запущен. Это приведет к тому, что Jenkins и многие другие серверы CI ошибочно будут считать сборку неудачной. Чтобы исправить это, вы должны сначала проверить, работает ли контейнер, как я сделал в вопросе (см. containerRunning
Переменную).
Полный скрипт для восстановления контейнера Docker
В соответствии с этими новыми знаниями я исправил свой скрипт следующим образом:
#!/bin/bash
imageName=xx:my-image
containerName=my-container
docker build -t $imageName -f Dockerfile .
echo Delete old container...
docker rm -f $containerName
echo Run new container...
docker run -d -p 5000:5000 --name $containerName $imageName
Это отлично работает :)