Подтвердить что ты не робот

Восстановить контейнер Docker при изменении файла

Для запуска приложения ASP.NET Core я создал файл dockerfile, который создает приложение и копирует исходный код в контейнере, который извлекается Git с помощью Jenkins. Поэтому в моей рабочей области я делаю следующее в файле docker:

WORKDIR /app
COPY src src

Пока Jenkins корректно обновляет файлы на моем хосте с помощью Git, Docker не применяет это к моему изображению.

Мой основной script для построения:

#!/bin/bash
imageName=xx:my-image
containerName=my-container

docker build -t $imageName -f Dockerfile  .

containerRunning=$(docker inspect --format="{{ .State.Running }}" $containerName 2> /dev/null)

if [ "$containerRunning" == "true" ]; then
        docker stop $containerName
        docker start $containerName
else
        docker run -d -p 5000:5000 --name $containerName $imageName
fi

Я пробовал разные вещи, такие как --rm и --no-cache для docker run, а также останавливал/удалял контейнер до создания нового. Я не уверен, что я делаю неправильно здесь. Кажется, что докер обновляет изображение правильно, так как вызов COPY src src приведет к идентификатору слоя и вызову кэш-памяти:

Step 6 : COPY src src
 ---> 382ef210d8fd

Каков рекомендуемый способ обновления контейнера?

Моим типичным сценарием было бы: Приложение запускается на сервере в контейнере Docker. Теперь часть приложения обновляется, например. путем изменения файла. Теперь контейнер должен запустить новую версию. Docker, похоже, рекомендует создать новый образ вместо изменения существующего контейнера, поэтому я думаю, что общий способ перестройки, как и я, прав, но некоторые детали в реализации должны быть улучшены.

4b9b3361

Ответ 1

После некоторых исследований и испытаний я обнаружил, что у меня были некоторые недоразумения в отношении срока службы контейнеров Docker. Просто перезагрузка контейнера не заставит Docker использовать новое изображение, когда изображение было перестроено тем временем. Вместо этого Docker извлекает изображение только перед запуском контейнера. Таким образом, состояние после запуска контейнера является постоянным.

Зачем требуется удаление

Поэтому перестройки и перезапуска недостаточно. Я думал, что контейнеры работают как сервис: останавливая службу, делайте свои изменения, перезагружайте ее, и они будут применяться. Это была моя самая большая ошибка.

Поскольку контейнеры постоянны, сначала их нужно удалить, используя docker rm <ContainerName>. После удаления контейнера вы не можете просто запустить его с помощью docker start. Это нужно сделать, используя docker run, который сам использует последнее изображение для создания нового контейнера-экземпляра.

Контейнеры должны быть как можно более независимыми

С этими знаниями понятно, почему хранение данных в контейнерах квалифицируется как плохая практика, и Docker рекомендует тома данных/установка каталогов хостов: поскольку для обновления приложений контейнер должен быть уничтожен, сохраненные данные внутри тоже будут потеряны. Это приводит к дополнительной работе для выключения служб, резервного копирования данных и т.д.

Итак, это умное решение, чтобы полностью исключить эти данные из контейнера: нам не нужно беспокоиться о наших данных, когда он хранится на хосте и контейнере только для самого приложения.

Почему -rf может не помочь вам

В команде docker run есть переключатель очистки, называемый -rf. Это остановит поведение хранения контейнеров докеров навсегда. Используя -rf, Docker уничтожит контейнер после его выхода. Но этот переключатель имеет две проблемы:

  • Docker также удаляет тома без имени, связанного с контейнером, что может убить ваши данные.
  • Используя эту опцию, невозможно запустить контейнеры в фоновом режиме с помощью -d switch

В то время как переключатель -rf является хорошим вариантом для сохранения работы во время разработки для быстрых тестов, он менее подходит для производства. Особенно из-за отсутствующего варианта запуска контейнера в фоновом режиме, который в основном требуется.

Как удалить контейнер

Мы можем обойти эти ограничения, просто удалив контейнер:

docker rm --force <ContainerName>

Переключатель --force (или -f), который использует SIGKILL для запуска контейнеров. Вместо этого вы также можете остановить контейнер до:

docker stop <ContainerName>
docker rm <ContainerName>

Оба равны. docker stop также использует SIGTERM. Но с помощью --force коммутатор сократит ваш script, особенно при использовании серверов CI: docker stop выдает ошибку, если контейнер не запущен. Это может привести к тому, что Дженкинс и многие другие серверы CI будут считать сборку ошибочно неудачной. Чтобы исправить это, сначала нужно проверить, работает ли контейнер, как в вопросе (см. Переменную containerRunning).

Полный script для восстановления контейнера Docker

В соответствии с этим новым знанием я исправил свой script следующим образом:

#!/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

Это отлично работает:)

Ответ 2

Всякий раз, когда вносятся изменения в dockerfile или в состав или требования, перезапустите его, используя docker-compose up --build. Чтобы изображения перестраивались и обновлялись