Холодный апгрейд docker-контейнера из нового образа

Обзор

В случаях, когда обновление через API невозможно, необходимо провести операцию апгрейда с заменой docker-образа и пересозданием контейнера.

Все данные, сохраненные в БД, а также файлы и каталоги в волюмах на хосте, остаются нетронутыми, и после запуска новой версии системы сохраняются и используются.

Процедура апгрейда

Шаг 1. Выяснить текущее имя контейнера с платформой.

Это имя формата "era<Postfix>", заданное при установке системы или при прошлом апгрейде.

Обнаружить его можно, выполнив команду:

docker ps -a

и найдя активный контейнер с указанным форматом имени.

Шаг 2. Сгенерировать строку запуска контейнера.

Для этого выполнить скрипт из инсталлятора - gen_container_cmd_ssh.sh

bash gen_container_cmd_ssh.sh --user=user --host=192.168.10.127 --port=22

Скрипт спросит недостающие параметры подключения, скопирует инсталлятор в /tmp/era_installer на сервере и запустит там чтение контейнеров. Ничего на сервере при этом не меняется: команда восстанавливается через docker inspect.

Дальше он отобразит список контейнеров — в строке видно и каталог данных, и имя:

Какой контейнер?
   1) каталог: /opt/era_11, контейнер: era_11
   2) каталог: /opt/era_11/postgresql, контейнер: postgres_11

необходимо указать номер контейнера для которого нужно сгенерировать команду (в примере: 1), после чего будет сгенерирована команда, например:

1
Восстанавливаем команду запуска для era_11
docker run --name=era_11 \
           --volume=/opt/era_11/syncroot:/var/lib/era_files/syncroot:rslave \
           --volume=/opt/era_11/era_recpath:/var/lib/era_files/recpath:rslave \
           --volume=/opt/era_11/era_siteshare:/var/lib/era_files/siteshare:rslave \
           --volume=/opt/era_11/c:/var/lib/era_files/c:rslave \
           --volume=/opt/era_11/lib:/var/lib/era:rslave \
           --volume=/opt/era_11/local:/var/lib/era_files/local:rslave \
           --volume=/opt/era_11/era_globalshare:/var/lib/era_files/globalshare:rslave \
           --volume=/opt/era_11/a:/var/lib/era_files/a:rslave \
           --volume=/opt/era_11/b:/var/lib/era_files/b:rslave \
           --volume=/opt/era_11/log:/var/log/era:rslave \
           --volume=/opt/era_11/rectemp:/var/lib/era_files/rectemp:rslave \
           --volume=/opt/era_11/logstore:/var/lib/era_files/logstore:rslave \
           --cap-add=CAP_NET_ADMIN \
           --cap-add=CAP_NET_BIND_SERVICE \
           --cap-add=CAP_NET_RAW \
           --network=host \
           --restart=unless-stopped \
           --env=STARTTYPE=firstinit \
           --env=SRVIP=192.168.10.127 \
           --env=SRVNAME=testsrv \
           --env=PSK=123456 \
           --env=SQLSTR=host:192.168.10.127,port:5451,login:platformpgadmin,pwd:Era_User_pwd,database:postgres \
           --env=GENDOMAIN=tester.ru \
           --tty \
           --detach=true \
           era:v.1

Команда понадобится в пункте 5. Запоминать её не нужно: инсталлятор сохраняет её файлом рядом со своим логом — /tmp/era_installer/logs/<имя контейнера>.run.sh на сервере, права 0700. При запуске через gen_container_cmd_ssh.sh этот файл вместе с логом возвращается на вашу машину, в logs/remote/<адрес сервера>/.

ВАЖНО! Проверить в полученной команде наличие параметра "--restart unless-stopped". Без него контейнер не стартанет после будущего обновления.

ВАЖНО! Перед применением удалить из строки указание volume на localtime и timezone, т.к. начиная с версии 1.9.0 настройка часового пояса происходит внутри контейнера через параметр мастер домена settings.timezone

Пример строк которые нужно удалить:

  --volume=/etc/localtime:/etc/localtime:rprivate \
  --volume=/etc/timezone:/etc/timezone:rprivate \

Шаг 3. Загрузить новый образ

docker load -i <ImageFileName>

заменив "<ImageFileName>" на имя docker-образа с новой версией. Образ имеет имя формата "era_<VERSION>_docker.tar.gz".

Команда docker load печатает имя, под которым образ загрузился, например Loaded image: era:v.1. Это имя стоит последней строкой в команде из пункта 2. Если новый образ загрузился под тем же именем, команда запустит уже новую версию — заменять в ней ничего не нужно; старый контейнер при этом продолжит работать на прежнем образе, потому что привязан к его идентификатору, а не к имени. Если имя другое — подставьте его в конец команды вместо прежнего.

Шаг 4. Остановить текущий контейнер

docker container stop <CurrentContainerName>

Остановка обязательна, а не желательна: контейнер платформы работает с --network=host, то есть занимает порты хоста напрямую. Два контейнера с этой настройкой одновременно не поднимутся — новый упрётся в занятые порты. Удалять старый контейнер на этом шаге не нужно: остановленный, он не мешает и остаётся способом отката.

Шаг 5. Запустить новый контейнер

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

docker run --name era<Postfix1> ...

то она становится:

docker run --name era<Postfix2> ...

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

Шаг 6. Проверить, что новая версия поднялась

docker ps

Новый контейнер должен быть в состоянии Up, а старый — отсутствовать в этом списке (он остановлен).

Дальше стоит посмотреть, что платформа сообщила при старте:

docker logs <NewContainerName> --tail 50

Об успешной инициализации платформа сообщает строкой вида:

EraInstallResult: <<success<>Install server success!>>

Ровно этой строки дожидается инсталлятор при обычной установке. Если вместо success пришла ошибка — новый контейнер можно остановить и запустить старый: данные в томах и в базе не изменились, откат возвращает прежнюю версию.

Шаг 7. Проверить часовой пояс внутри контейнера

Для этого необходимо проверить настройку мастер домена timezone (domain.settings.timezone) и при необходимости указать нужный часовой пояс, после чего перезагрузить систему (или контейнер)