Как конфигурация docker-compose может перейти от использования анонимных томов к именованным томам при сохранении существующих данных?

#docker-compose

#docker-compose

Вопрос:

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

Я вношу свой вклад в серверное приложение с открытым исходным кодом, которое пользователи устанавливают в различных инфраструктурах. Наши пользователи обычно не очень техничны и ограничены в ресурсах. Мы предоставили простую docker-compose настройку. Постоянные данные находятся в контейнерной базе данных postgres, которая хранит свои данные на анонимном томе. Все наши инструкции по администрированию включают остановку запущенных контейнеров, но не их остановку.

Это хорошо работает для большинства пользователей, но некоторые пользователи в конечном итоге делают docker-compose down это либо потому, что у них есть небольшой опыт работы с Docker, либо по простой аналогии с up . Когда они восстанавливают свой сервер, они получают новые анонимные тома, и похоже, что они потеряли свои данные. Мы предоставили инструкции по восстановлению из этого состояния, но это происходит достаточно часто, поэтому мы пересматриваем нашу конфигурацию и изучаем переход к именованным томам.

Многие пользователи с удовольствием используют анонимные тома и точно следуют нашим административным инструкциям. Это наши наименее технические пользователи, и мы хотим убедиться, что на них не повлияют никакие изменения, которые мы вносим в docker-compose конфигурацию. По этой причине мы не можем «просто» изменить docker-compose конфигурацию для использования именованных томов и предоставить сценарий для переноса данных. Слишком высок риск того, что пользователи забудут / не смогут запустить скрипт и в конечном итоге подумают, что потеряли все свои данные. Такой подход был бы хорош, если бы мы могли каким-то образом гарантировать, что резервное копирование службы с новой конфигурацией будет успешным только в том случае, если миграция данных завершена.

Примечание для тех, кто интересуется нашим выбором использования контейнерной базы данных: у нас также есть путь для пользователей, чтобы указать внешний сервер БД (например, RDS), но он доступен только для наших наиболее ресурсоемких пользователей.

Редактировать: вот аналогичный вопрос по ошибке сервера.

Комментарии:

1. Не могли бы вы предоставить файл конфигурации docker compose в качестве примера?

2. @paltaa github.com/getodk/central/blob/master/docker-compose.yml является ли конфигурация, о которой идет речь. Обратите внимание на анонимное монтирование для postgres.

Ответ №1:

Учитывая, что вы используете официальный образ PostgreSQL, вы можете использовать их систему инициализации базы данных

Если вы хотите выполнить дополнительную инициализацию в образе, полученном на основе этого, добавьте один или несколько *.sql, * .sql.gz , или скрипты *.sh в /docker-entrypoint-initdb.d (при необходимости создавая каталог). После того, как точка входа вызывает initdb для создания пользователя и базы данных postgres по умолчанию, она запустит любые файлы * .sql, запустит любые исполняемые скрипты * .sh и отправит любые неисполняемые скрипты * .sh, найденные в этом каталоге, для дальнейшей инициализации перед запуском службы.

с изменением PGDATA

Эта необязательная переменная может использоваться для определения другого местоположения — например, подкаталога — для файлов базы данных. По умолчанию используется /var/lib/postgresql/data . Если используемый вами том данных является точкой монтирования файловой системы (например, с постоянными дисками GCE) или удаленной папкой, которая не может быть передана пользователю postgres (например, для некоторых подключений NFS), Postgres initdb рекомендует создать подкаталог для хранения данных.

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

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

docker-compose.yml:

 version: "3.7"
services:
  postgres:
    image: postgres
    environment:
      POSTGRES_PASSWORD: test
    volumes:
      - ./test.sh:/docker-entrypoint-initdb.d/test.sh
  

test.sh:

 #!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "postgres" --dbname "postgres" <<-EOSQL
    CREATE TABLE public.test_table (test_column integer NOT NULL);
    INSERT INTO public.test_table VALUES (1);
    INSERT INTO public.test_table VALUES (2);
    INSERT INTO public.test_table VALUES (3);
    INSERT INTO public.test_table VALUES (4);
    INSERT INTO public.test_table VALUES (5);
EOSQL
  

Обратите внимание, как это test.sh монтируется, оно должно быть в /docker-entrypoint-initdb.d/ каталоге, чтобы выполняться на этапе инициализации. Поднимите и опустите стек, чтобы инициализировать базу данных с помощью этого примера данных.

Теперь создайте сценарий для перемещения данных:

move.sh:

 #!/bin/bash
set -e

rm -rf $PGDATA/*
mv /var/lib/postgresql/data/* "$PGDATA/"
  

и обновите docker-compose.yml с помощью именованного тома и настраиваемого местоположения для данных:

docker-compose.yml:

 version: "3.7"
services:
  postgres:
    image: postgres
    environment:
      POSTGRES_PASSWORD: test
      # set a different location for data
      PGDATA: /pgdata
    volumes:
      # mount the named volume
      - pgdata:/pgdata
      - ./move.sh:/docker-entrypoint-initdb.d/move.sh

volumes:
  # define a named volume
  pgdata: {}
  

Когда вы поднимаете этот стек, он не найдет базу данных (поскольку именованный том изначально пуст), и Postgres запустит сценарии инициализации. Сначала он запускает свой собственный скрипт для создания пустой базы данных, затем запускает пользовательские скрипты из /docker-entrypoint-initdb.d каталога. В этом примере я подключился move.sh к этому каталогу, который удалит временную базу данных и переместит старую базу данных в новое местоположение.

Комментарии:

1. Спасибо, отличные идеи здесь! У меня возникли проблемы с запуском вашего примера. Мне пришлось изменить mv cp значение, за которым следует, rm -rf потому что я использую разные тома. Теперь я получаю PANIC: could not locate a valid checkpoint record при попытке миграции. Есть идеи?

2. Спасибо! Полностью понял, что это всего лишь пример. Я надеюсь, что смогу запустить его, прежде чем применять извлеченные из него уроки. Кавычки, похоже, не имеют значения. Если я помещаю ls $PGDATA/* вместо этого, я получаю ls: cannot access '/pgdata/*': No such file or directory .

3. Поскольку вы используете ls с glob ls/* , это означает list me every directory in the location . Может произойти сбой с ошибкой, если каталог пуст. Я предлагаю вам exec исследовать контейнер.

4. В конце концов, это были кавычки, извините! Я не осознавал ls , что у * меня было такое поведение. Действительно ценю ваш вдумчивый ответ и помогу заставить его работать.

5. Пожалуйста. Перед распространением обновления обязательно протестируйте это на базе данных размером более одного гигабайта.