Після деяких досліджень та випробувань я виявив, що мав певні непорозуміння щодо терміну служби контейнерів 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
Це чудово працює :)