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

Скажем, я вытащил официальное mysql: 5.6.21 изображение.

Я развернул это изображение, создав несколько контейнеров докеров.

Эти контейнеры работают некоторое время, пока не будет выпущен MySQL 5.6.22. Официальный образ mysql: 5.6 обновляется с новой версией, но мои контейнеры все еще работают 5.6.21.

Как распространять изменения в изображении (то есть обновлять MySQL-дистрибутив) во все мои существующие контейнеры? Каков правильный способ Докера?

Ответ 1

Оценив ответы и изучив тему, я хотел бы подвести итог.

Способ обновления контейнеров с помощью Docker выглядит следующим образом:

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

docker pull mysql
docker stop my-mysql-container
docker rm my-mysql-container
docker run --name=my-mysql-container --restart=always \
  -e MYSQL_ROOT_PASSWORD=mypwd -v /my/data/dir:/var/lib/mysql -d mysql

Вы можете хранить данные либо на хосте (в каталоге, смонтированном как том), либо в специальных контейнерах только для данных. Подробнее об этом

Обновление приложений (например, с помощью обновления yum/apt-get) в контейнерах считается антишаблоном. Прикладные контейнеры должны быть неизменными, что должно гарантировать воспроизводимое поведение. Некоторые официальные образы приложений (в частности, mysql: 5.6) даже не предназначены для самостоятельного обновления (apt-get upgrade не будет работать).

Я хотел бы поблагодарить всех, кто дал свои ответы, чтобы мы могли видеть все разные подходы.

Ответ 2

Мне не нравятся монтажные тома в качестве ссылки на основной каталог, поэтому я придумал шаблон для обновления контейнеров докеров с полностью контейнерами, управляемыми докере. Создание нового контейнера docker с помощью --volumes-from <container> даст новый контейнер с обновленными изображениями, совместно используемыми для хранения файлов, поддерживаемых докером.

docker pull mysql
docker create --volumes-from my_mysql_container [...] --name my_mysql_container_tmp mysql

Не удаляя исходный my_mysql_container, но у вас есть возможность вернуться к известному рабочему контейнеру, если обновленный контейнер не имеет правильных данных или не прошел тест на работоспособность.

В этот момент я, как правило, запускаю любые сценарии резервного копирования, которые у меня есть для контейнера, чтобы дать себе сеть безопасности в случае, если что-то пойдет не так.

docker stop my_mysql_container
docker start my_mysql_container_tmp

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

docker rm my_mysql_container
docker rename my_mysql_container_tmp my_mysql_container

Объемы докеров будут зависеть до тех пор, пока используется какой-либо контейнер, чтобы вы могли безопасно удалить исходный контейнер. После того, как исходный контейнер будет удален, новый контейнер может принять тезку оригинала, чтобы сделать все так же красиво, как и начиналось.

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

Ответ 3

Я хотел бы добавить, что если вы хотите выполнить этот процесс автоматически (загрузить, остановить и перезапустить новый контейнер с такими же настройками, как описано @Yaroslav), вы можете использовать WatchTower. Программа, которая автоматически обновляет ваши контейнеры при их изменении https://github.com/v2tec/watchtower

Ответ 4

Рассмотрим для этого ответы:

  • Имя базы данных app_schema
  • Имя контейнера app_db
  • Пароль root root123

Как обновить MySQL при хранении данных приложения внутри контейнера

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

1) Дамп базы данных как SQL:

docker exec app_db sh -c 'exec mysqldump app_schema -uroot -proot123' > database_dump.sql

2) Обновите изображение:

docker pull mysql:5.6

3) Обновите контейнер:

docker rm -f app_db
docker run --name app_db --restart unless-stopped \
-e MYSQL_ROOT_PASSWORD=root123 \
-d mysql:5.6

4) Восстановить дамп базы данных:

docker exec app_db sh -c 'exec mysql -uroot -proot123' < database_dump.sql

Как обновить контейнер MySQL с помощью внешнего тома

Использование внешнего тома - лучший способ управления данными, и упрощает обновление MySQL. Потеря контейнера не потеряет никаких данных. Вы можете использовать docker-compose, чтобы упростить управление многоконтактными приложениями Docker в одном хосте:

1) Создайте файл docker-compose.yml для управления вашими приложениями:

version: '2'
services:
  app_db:
    image: mysql:5.6
    restart: unless-stopped
    volumes_from: app_db_data
  app_db_data:
    volumes: /my/data/dir:/var/lib/mysql

2) Обновите MySQL (из той же папки, что и файл docker-compose.yml):

docker-compose pull
docker-compose up -d

Примечание. Последняя команда выше обновит образ MySQL, заново создаст и запустит контейнер с новым изображением.

Ответ 5

Просто для предоставления более общего (не специфичного для mysql) ответа...

  1. Короче

Синхронизировать с реестром образа сервиса (https://docs.docker.com/compose/compose-file/#image):

docker-compose pull 

Создайте контейнер заново, если изменились файл или изображение docker-compose:

docker-compose up -d
  1. Фон

Управление изображениями контейнеров является одной из причин использования docker-compose (см. Https://docs.docker.com/compose/reference/up/).

Если для службы существуют контейнеры, а конфигурация или образ служб были изменены после создания контейнеров, docker-compose обрабатывает изменения, останавливая и воссоздавая контейнеры (сохраняя подключенные тома). Чтобы запретить Compose принимать изменения, используйте флаг --no-воссоздать.

Аспект управления данными также охватывается docker-compose через подключенные внешние "тома" (см. Https://docs.docker.com/compose/compose-file/#volumes) или контейнер данных.

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

Ответ 6

Подобный ответ выше

docker images | awk '{print $1}' | grep -v 'none' | grep -iv 'repo' | xargs -n1 docker pull

Ответ 7

Вот как это выглядит при использовании docker-compose при создании пользовательского Dockerfile.

  1. Сначала создайте свой собственный файл Dockerfile, добавив следующий номер версии для разграничения. Пример: docker build -t imagename:version. Это будет хранить вашу новую версию локально.
  2. Запустить docker-compose down
  3. Отредактируйте файл docker-compose.yml чтобы отразить новое имя изображения, которое вы задали на шаге 1.
  4. Запустите docker-compose up -d. Он будет искать изображение локально и использовать ваш обновленный.

-РЕДАКТИРОВАТЬ-

Мои шаги выше более многословны, чем они должны быть. Я оптимизировал рабочий процесс, добавив build:. параметр моего docker-compose файла. Пошаговые шаги выглядят так:

  1. Убедитесь, что мой Dockerfile - это то, что я хочу, чтобы он выглядел.
  2. Установите номер версии моего имени изображения в моем файле docker-compose.
  3. Если мой образ еще не собран: запустите docker-compose build
  4. Запустите docker-compose up -d

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

Ответ 8

Если вы не хотите использовать Docker Compose, я могу порекомендовать portainer. Он имеет функцию воссоздания, которая позволяет воссоздать контейнер при извлечении последнего изображения.

Ответ 9

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

Ответ 10

Взятие из http://blog.stefanxo.com/2014/08/update-all-docker-images-at-once/

Вы можете обновить все существующие изображения, используя следующий конвейер команд:

docker images | awk '/^REPOSITORY|\<none\>/ {next} {print $1}' | xargs -n 1 docker pull

Ответ 11

У меня была такая же проблема, поэтому я создал docker-run, очень простой инструмент командной строки, который запускается внутри контейнер докеров для обновления пакетов в других запущенных контейнерах.

Он использует docker-py для связи с запущенными контейнерами докеров и пакетами обновления или для запуска любой произвольной одиночной команды

Примеры:

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run exec

по умолчанию это будет запускать команду date во всех запущенных контейнерах и возвращать результаты, но вы можете выдать любую команду, например. docker-run exec "uname -a"

Чтобы обновить пакеты (в настоящее время используется только apt-get):

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run update

Вы можете создавать и использовать псевдоним и использовать его как обычную командную строку например.

alias docker-run='docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run'

Ответ 12

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

Ответ 13

Это то, с чем я тоже борюсь за свои собственные изображения. У меня есть серверная среда, из которой я создаю образ Docker. Когда я обновляю сервер, я бы хотел, чтобы все пользователи, которые запускали контейнеры на основе моего изображения Docker, могли обновиться до последнего сервера.

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

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

Изображение/контейнер фактически не изменяется, но "внутренности" этого контейнера меняются. Вы могли бы представить себе то же самое с apt-get, yum или любым подходящим для вас окружением. Наряду с этим я бы обновил myserver: последнее изображение в реестре, чтобы все новые контейнеры были основаны на последнем изображении.

Мне было бы интересно узнать, существует ли какой-либо предшествующий уровень техники, который затрагивает этот сценарий.

Ответ 14

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

docker pull image.uri.io:latest
docker restart the-container

При условии что

docker ps --format 'table{{.Names}}\t{{.Image}}'
NAMES              IMAGE
the-container      image.uri.io:latest

Преимущество этого способа заключается в том, что вам не нужно выполнять docker run Docker и повторять все эти параметры создания, как в ответе @Yaroslav.