Безопасен ли этот процесс? Я могу без проблем запускать многоконтейнерную настройку в среде разработки, но если я начну использовать её в производственной среде, пока пользователи обращаются к старому контейнеру, а новый контейнер проходит этап загрузки и выполняет миграцию базы данных, запросы к старому контейнеру всё ещё будут использовать старую логику бэкенда и сохранять данные согласно предыдущей версии, даже после завершения этапа миграции базы данных (но до завершения всего процесса загрузки).
Хотя я понимаю, что это не проблема, специфичная для Discourse (в среде с несколькими репликами такая проблема может возникнуть, если одна реплика обновляется раньше другой, если только вы не остановите все реплики перед обновлением, но это вряд ли возможно, если вы хотите обеспечить высокую доступность), безопасен ли описанный вами процесс в общем смысле?
Одно из решений, которое я могу предложить, — это всегда поддерживать Discourse в актуальном состоянии, чтобы минимизировать миграции базы данных между сборками. Но в любом случае это всё ещё не идеально, и даже в этом случае могут возникнуть проблемы.
Настройка с несколькими контейнерами кажется одним из рекомендуемых подходов (хотя и не стандартным, где используется всего один контейнер), поэтому я думаю, что она должна быть безопасной, и я просто слишком много думаю.
Вы знаете, работает ли это без проблем на производственных сайтах (когда загрузка выполняется в одном контейнере, даже если другой уже работает)? Я спрашиваю просто чтобы узнать мнение людей, которые уже применяли это в производственной среде, чтобы получить обратную связь и понять, работает ли это стабильно даже после нескольких сборок, есть ли какие-то подводные камни и т. д. Как я уже говорил, в среде разработки всё работает отлично.
Если вы хотите избежать простоя, необходимо выполнить несколько дополнительных шагов: отключить «post-migrations» на новых контейнерах, полностью развернуть новый контейнер, включить post-migrations, а затем снова выполнить развертывание. Это предотвратит выполнение миграций, удаляющих столбцы, до тех пор, пока старый код не перестанет работать.
Пока нет инструкции по этому вопросу; документация доступна только здесь:
Однако в большинстве случаев форумы могут обойтись минутой или тремя минутами простоя в месяц.
Затем мы выбираем контейнер, который должен быть активным, создавая символическую ссылку на соответствующий сокет, вот так:
Допустим, мы хотим, чтобы контейнер socket2 был активным:
ls -sf /var/discourse/shared/socket2/nginx.http.sock /var/run/nginx.http.sock
Допустим, мы хотим внести изменения в socket1 и сделать его активным:
cd /var/discourse
./launcher rebuild socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock
Обратите внимание: нет необходимости запускать bootstrap только для контейнера socket1, поскольку контейнер доступен через unix-доменный сокет в своей собственной общей директории/томе. Поэтому оба этих контейнера «веб-приложения» могут работать одновременно:
Здесь нет конфликта привязки портов, как в случае с портами TCP/IP контейнеров. По этой причине я использую только unix-доменные сокеты на продакшн-окружении (не порты TCP/IP).
Конечно, вы можете запустить bootstrap, если хотите:
cd /var/discourse
./launcher bootstrap socket1
./launcher start socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock
Это ваш выбор, но имейте в виду: если запустить оба контейнера одновременно, в обоих будет работать sidekiq и выполняться запланированные задачи. Наш опыт показывает, что поэтому мы периодически синхронизируем загруженные файлы в обоих контейнерах.
Для нас это работает безупречно: мы можем пересобрать контейнер веб-приложения и сделать его активным практически без простоя. Мы очень серьёзно относимся к простоям на продакшн-окружении и избегаем их всякий раз, когда это возможно.
Примечание:
Этот метод (описанный выше) предназначен для части решения, связанной с веб-приложением, а не для контейнера данных. Я не создавал аналогичного решения для контейнера данных, но кто знает — возможно, когда-нибудь я потрачу время и разработаю что-то похожее (но, разумеется, отличающееся) для контейнера данных (некий метод с «двумя контейнерами данных и синхронизацией БД», пока это полностью не определено в моих планах).
Таким образом, я на самом деле делаю обратное этому:
Как я уже говорил, в среде разработки всё работает отлично.
Обычно я не настраиваю это в среде разработки, так как это занимает больше времени, и это не обязательно, поскольку небольшой простой допустим. Ведь это «только я и код» (нет живых пользователей и ботов, обращающихся к сайту). Кроме того, я не использую Docker в разработке** (на рабочем столе).
Надеюсь, это поможет.
Под «разработкой» я имею в виду разработку программного обеспечения (например, плагинов), а не просто «подготовку к запуску» установки Discourse, которую я называю «staging», а не «разработка» (чтобы было совершенно ясно).
Спасибо, я об этом не знал. Это отличная функция, и я вижу, как она может избежать проблем, подобных той, о которой я упоминал ранее (хотя это не защитит от изменений логики, использующей уже существующие столбцы, но такие случаи должны быть более редкими).
Спасибо за ответ. Параметр SKIP_POST_DEPLOYMENT_MIGRATIONS, похоже, соответствует тому, о чём говорил @riking, и именно это я искал, чтобы миграции не ломали работу запущенного контейнера.
Спасибо за объяснение. Мне кажется, это хороший подход: переключение между двумя контейнерами (чтобы один работал, пока другой проходит инициализацию).
Под «средой разработки» я имел в виду удалённую среду разработки, которую я использовал для тестирования настройки с несколькими контейнерами (как на одной машине, так и с контейнерами на разных машинах).
Я сказал «dev», а не «staging», потому что в среде staging я бы использовал файлы yml с теми же плагинами и тестировал бы на резервной копии продакшен-базы данных. Но верно, что если мне просто нужно настроить среду разработки, то в большинстве случаев я бы использовал подход с одним контейнером.
Насколько я понимаю, эта инструкция содержит много словесных оборотов вокруг:
резервного копирования
создания совершенно нового экземпляра Discourse с большим количеством слов, но теми же результатами, что и просто запуск discourse_setup 2container
восстановления
Поч бы не просто переместить или скопировать /var/discourse/shared/standalone/{postgres,redis}* в /var/discourse/shared/data после корректного завершения работы и перед запуском двух новых контейнеров из отдельных файлов containers/*.yml? Резервное копирование и восстановление кажутся чрезмерно громоздким способом переноса всех этих данных, необоснованно увеличивая процесс на несколько часов. Не упускаю ли я что-то очевидное?
Я только что протестировал этот процесс на своём тестовом экземпляре Discourse и, раз уж зашёл так далеко, также разделил Redis, чтобы убедиться, что учтены все аспекты. Редакция: Я перенёс описание в новую тему:
Сайт, похоже, функционирует нормально без цикла резервного копирования и восстановления. Есть ли что-то неочевидное, что мне следует проверить?
Я провёл тот же процесс для относительно крупного экземпляра Discourse, и он работает исправно. Я решил, что в продакшн-среде назову свой новый контейнер web_only как app, чтобы мои пальцы автоматически выполняли нужные действия. После написания новых файлов container/*.yml время простоя при всей миграции составило 12 минут — значительно быстрее, чем при цикле резервного копирования и восстановления.
Полагаю, нам просто стоит согласиться не соглашаться. Я думаю, что если кто-то компетентен в управлении несколькими контейнерами, он сможет выполнить несколько команд. Мне не кажется, что эти команды сложнее ввести, чем bin/rails c и набор команд Ruby здесь, или что они требуют значительно больше или иных навыков, чем работа с несколькими контейнерами в целом. Но я перенесу этот контент в отдельный новый пост, чтобы не оставлять его затерянным в комментариях здесь.
И если они допустят ошибку, нет ничего лучше резервной копии перед миграцией! Надеюсь, я это четко объяснил в своей статье, ссылка на которую приведена выше!
Вот и слабое место в вашей аргументации. Добавление 2container в ./discourse-setup не свидетельствует о какой-либо компетентности. Многие люди запускают два контейнера просто потому, что видят подобные темы и предполагают, что есть какой-то секретный рецепт или что это «то, что нужно делать».
Тема про PostgreSQL 12 должна служить предостережением относительно добавленной сложности. Использование резервной копии как шага между состояниями позволяет пользователю вернуться к одному контейнеру, просто переименовав один файл; как только вы начнете перемещать папки, эта простота теряется.
@Stephen В вашем аргументе есть изъян: описание мультиконтейнерной архитектуры изобилует предупреждениями о том, что вы несёте ответственность за обновления и должны понимать, как всё работает, а длинное описание выше настолько запутано, что, вероятно, любой, кто на него посмотрит, просто сдастся. Прочитайте мою статью Migrate quickly to separate web and data containers и скажите, что она не отпугнёт тех, кому будет трудно её понять, или что в ней недостаточно подчёркивается необходимость резервного копирования и возможности отката к резервной копии в случае сбоя!
Я был крайне недоволен, когда сразу после миграции на более мощный сервер (для установки исправления безопасности) выполнил команду ./launcher rebuild app, и мой сайт оставался недоступным неоправданно долгое время, значительная часть которого ушла на пересборку частей контейнера, связанных с PostgreSQL. Именно тогда я нашёл документацию о двух контейнерах и эту документацию, и мне совсем не хотелось снова терять 4 часа на миграцию, поэтому я продолжал мириться с длительными простоями из-за ./launcher rebuild app, чтобы избежать 4 часов простоя, необходимых для восстановления из резервной копии. Как человек с определённой компетентностью, я долгое время был очень раздражён тем, что такая конфигурация фактически скрыта.
Тема о PostgreSQL 12 — отличный справочник, потому что люди в итоге сталкиваются с ещё большим временем простоя, так как им приходится пересобирать всё приложение несколько раз, хотя можно было бы пересобрать только контейнер PostgreSQL дважды. Не могу сказать, что я прочитал всю ветку из-за автоматического удаления через 6 дней, но мне совершенно не очевидно, что некомпетентные развёртывания мультиконтейнерных систем являются там главной или даже одной из главных проблем.
(Извините, иногда я немного устаю от того, что здесь всех пользователей считают некомпетентными.)
Возможно, для вас это не имеет смысла, но для тех из нас, кто уже шесть-семь лет находится на meta и оказывает помощь людям в канале Support, всегда имеет смысл иметь стратегию отката.
Баги действительно просачиваются даже после прохождения тестов; иногда ограничения скорости API RubyGems влияют на пересборки, и даже у GitHub случались отдельные сбои. По этой одной причине я не вижу никакой пользы в изменении состояния, которое усложнит простое переименование файла и запуск команды ./launcher start app.
Ваша готовность к риску может быть иной, и в таком случае вы можете выбрать другой путь. Для тех, кто регулярно помогает устранять последствия, текущее руководство работает хорошо.
Мне кажется, вы на самом деле не прочитали процесс, который я описал, поскольку пишете так, будто я не подчеркнул необходимость возможности восстановления. Пожалуйста, прочитайте его, а затем вернитесь и подумайте о том, чтобы отредактировать написанное вами, чтобы оно стало правдивым утверждением относительно моих инструкций. В текущем виде мне кажется, что вы ведёте со мной снисходительный разговор, не удосужившись прочитать то, что я написал.
Тем не менее, я добавил множество дополнительных предупреждений, включая одно в самом верху, превышающее количество предупреждений в этом посте, который уже пять лет является и продолжает оставаться каноническим местом для инструкций по этому процессу миграции.
Прежде всего, спасибо за то, что пытаетесь расчистить для нас, искателей приключений, этот «джунгли» , я, наверное, последую вашему примеру через несколько дней…
Что находится в файле multisite.yml?
Недавно я настроил самостоятельно размещённый форум Discourse на VPS. Файлы загружаются и хранятся на Wasabi. То же самое касается резервных копий. Всё размещено на Linode.
Я использовал шаблон standalone и обнаружил, что процесс настройки — это глоток свежего воздуха по сравнению с другим ПО. Это было превосходно! Чистое удовольствие. Желаю, чтобы каждый проект с открытым исходным кодом уделял столько же внимания установке и настройке, как Discourse.
Однако есть одна загвоздка. У меня есть выделенный сервер PostgreSQL, работающий на отдельной машине, доступный только по адресу RFC-1918, который не доступен из интернета, и я хотел бы, чтобы Discourse использовал его. Мне не очень нравится, когда серверы баз данных работают на том же сервере, что и веб- или приложение-сервер.
Так есть ли способ отделить встроенную базу данных и перенести её в мой выделенный кластер баз данных?
Я предполагаю, что мне нужно будет сделать дамп базы данных Discourse с помощью pgdump, перенести его на выделенный сервер баз данных и восстановить, а затем выполнить вакуумирование и анализ всех таблиц после восстановления/импорта, после чего просто указать приложению Discourse на новую базу данных по сети?
Но я не могу найти, где хранятся учётные данные базы данных. Я посмотрел в app.yml, но там, похоже, нет записей о базе данных, и когда я заглянул в папку ../templates/, ни один из файлов yml не содержал учётных данных базы данных, по крайней мере, на первый взгляд.