Развертывание нового кода в реальном времени

29

Какова лучшая практика для развертывания нового кода на сайте (электронной коммерции)?

На данный момент я остановил apache на +/- 10 секунд при переименовании директории public_html_newв public_htmlи старой в public_html_old. Это создает короткое время простоя, прежде чем я снова запускаю Apache.

Тот же вопрос возникает, если с помощью Git вытащить новый репозиторий в директорию live. Можно ли вытащить репо, пока сайт активен? А как насчет того, если мне нужно скопировать БД?

Во время сжатия tar (резервное копирование) живого сайта я заметил, что в каталоге media произошли изменения. Это указывало на то, что файлы периодически меняются. И если эти изменения могут помешать, если Apache не остановлен во время развертывания.

NicOx
источник

Ответы:

13

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

Кроме того, если это в системе UNIX, вы можете приостановить работу Apache во время переименования (или обновления символической ссылки и т. Д.):

killall -STOP httpd  # Pause all httpd processes
mv public_html public_html_orig
mv public_html_new public_html
killall -CONT httpd  # Resume all httpd processes

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

killall -STOP httpd  # Pause all httpd processes
rm /var/www/html
ln -s /var/www/version/03 /var/www/html
killall -CONT httpd  # Resume all httpd processes

Обратите внимание, что любые ожидающие соединения или пакеты будут поставлены в очередь в ОС. Для чрезвычайно загруженного сайта рассмотрите возможность настройки ListenBacklog, если это соответствует вашему рабочему типу httpd, и проверьте настройки ОС, связанные с журналом ожидания прослушивания TCP.

Вы также можете изменить DocumentRoot в httpd.conf и выполнить аккуратный перезапуск ( apachectl graceful). Недостатком здесь является повышенный риск ошибок, так как вам также придется обновить любую Directoryконфигурацию.

GargantuChet
источник
Будет ли на этом сеансе приостановлена ​​работа сайта?
nicoX
4
Он перестает давать процессорное время Apache. Если вы попытались получить доступ к сайту в браузере, когда Apache приостановлен, браузер будет ожидать подключения, пока Apache не будет возобновлен (или не истечет время ожидания, если Apache приостановлен дольше, чем период ожидания). Если кто-то находится в процессе загрузки файла, Apache прекратит отправку данных, пока он находится в режиме паузы, опять же, потому что он не получает никакого процессорного времени. Опять же, это вызовет проблемы только в том случае, если Apache остановлен так долго, что время передачи истекло.
GargantuChet
5
Иными словами, сайт будет не отвечать, пока Apache находится в режиме паузы, но ожидающие операции завершатся после его возобновления. Пользователи не получат «отказано в соединении», и загрузки не прервутся, но операции продолжатся только после возобновления Apache. Это обеспечит завершение существующих транзакций, но новые запросы будут обрабатываться только после того, как ваш новый контент будет перемещен на место.
GargantuChet
1
Обратите внимание, что на любом веб-сайте с высоким трафиком это может очень легко убить вашу службу Apache. 200 rq / s очень легко очистят ваш пул соединений, как только вы «разблокируете» свой процесс Apache после перемещения (если перемещение займет некоторое время)
CloudWeavers
1
На сайте с большим трафиком будет много запросов на выполнение, когда Apache будет возобновлен. Это приведет к потере обработки новых запросов. Это также хороший аргумент для того, чтобы убедиться, что ваши настройки Apache (максимальное количество потоков / серверов / клиентов) разумны, и соответствующим образом настроить резервирование TCP. Хотя я не совсем понимаю, что вы имеете в виду под «убийством» сервиса. Апач очень настраиваемый.
GargantuChet
32

Самый быстрый и простой способ - использовать каталог версий, такой как

/var/www/version/01
/var/www/version/02

и использовать текущую символическую ссылку в качестве html_root:

/var/www/html -> /var/www/version/02

Этот метод прекрасно интегрируется в систему контроля версий (svn, git, mercurial, ...), так как вы можете извлекать ветки и теги, изменять символическую ссылку и перезагружать Apache. Время простоя при использовании этой техники минимально и позволяет очень легко выполнить откат .

Он также хорошо интегрируется с более сложной системой развертывания, такой как RPM-пакеты, или инфраструктурой управления изменениями конфигурации (chef, puppet и т. Д.).

CloudWeavers
источник
4
Самое простое решение - всегда лучшее ... :-) Конечно, не забудьте упомянуть, что могут потребоваться некоторые FollowSymlinks и такие флаги apache в конфигах.
Петер говорит восстановить Монику
Будьте особенно внимательны к тому, что сказал @PeterHorvath. Apache может стать очень раздражительным при работе с символьными DocumentRoots. Обязательно проверяйте внимательно!
mhutter
@mhutter Спасибо :-) Что действительно проблематично, так это то, что включение FollowSymlinks на apache может вызвать проблемы с безопасностью ...
говорит Петер, восстановите Monica
Обновление символической ссылки не является атомарной операцией. Даже используя что-то похожее ln -snfна исходную символическую ссылку, основная операция - это unlinkи symlink. У пользователей есть шанс получить 404 во время обновления. Это не лучше, чем просто переименовать исходный каталог и переименовать новый на место (при условии, что вы не пересекаете файловые системы). См. Ответ выше с галочкой рядом с ним, которая решает эту проблему.
GargantuChet
14

Переименование каталогов без отключения Apache также должно работать. Это значительно сократит окно. mv public_html public_html_old && mv public_html_new public_htmlдолжно закончиться в доли секунды.

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

Делать это атомарно с каталогами не поддерживается. Но вы можете сделать это с помощью символических ссылок. Вместо того, чтобы иметь каталог с именем public_html, имейте каталог с именем public_html.version-numberи символическую ссылку, public_htmlуказывающую на этот каталог. Теперь вы можете создать каталог с именем public_html.new-version-numberи новую символическую ссылку public_html.new.

Затем вы можете переименовать public_html.newв public_htmlпереключиться атомарно. Обратите внимание, что mvэто «слишком умно», чтобы выполнить это переименование, но это можно сделать с помощью os.renamepython или чего-нибудь еще, что вызовет renameсистемный вызов, не пытаясь быть умным.

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

kasperd
источник
1
В моей системе Debian mvесть -Tопция, которая не позволяет ему следовать символической ссылке. Это позволит вам атомарно переименовать public_html.newболее public_html, если предположить , как мягкие ссылки.
GargantuChet
11

Симлинки и mv - ваши друзья, однако, если вам действительно нужно, чтобы конечные пользователи не получали страницу с ошибкой при развертывании новой версии, у вас должен быть обратный прокси-сервер или балансировщик нагрузки, по крайней мере, перед двумя бэкэнд-серверами (apache в твоем случае).

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

Конечные пользователи всегда будут перенаправлены на хороший сервер.

Джованни Торальдо
источник
4
Я просто работал над этим ответом, когда увидел, что вы уже опубликовали его. Сервер Balancer + 2 делает процесс незаметным и облегчает восстановление после неудачного обновления ...
Барт Сильверстрим,
9

Если вы регулярно вносите изменения в производственную систему, я бы позаботился о структурированном жизненном цикле. Хорошей практикой является Capistrano http://capistranorb.com/ . Это решение с открытым исходным кодом для развертывания программного обеспечения на одном или нескольких серверах на нескольких платформах и в разных конфигурациях.

Для Magento есть даже плагин: https://github.com/augustash/capistrano-ash/wiki/Magento-Example

Для одного сервера и практически бесшовных переходов я рекомендую использовать символические ссылки.

Skiaddict
источник
4

То, как я это делаю, это фиксирует мои изменения из локальной среды разработки в онлайн-хранилище Git, таком как Github. Моя производственная среда запускается из удаленного репозитория, поэтому все, что мне нужно, это подключиться к серверу по ssh и запустить его, git pullчтобы отключить последние изменения. Не нужно останавливать ваш веб-сервер.

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

harryg
источник
3

Моя первая идея:

# deploy into public_html_new, and then:
rsync -vaH --delete public_html_new/ public_html/

Хорошим решением было использовать rsync. Это изменило только действительно измененные файлы. Осторожно, косые черты в конце дорожек здесь важны.

Обычно apache не требует перезагрузки, это не мир Java. Он проверяет изменения каждого php-файла по запросу и автоматически перечитывает (и повторно токенизирует) изменения.

Git Pull были похожи эффективны, хотя это было немного сложнее для сценария. Конечно, это позволило широкий спектр различных возможностей обнаружения слияния / изменения.

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

Если есть большие изменения, мое предложение было вашим первоначальным решением (два переименовать).


Вот немного хардкорное, но 100% атомное решение:

(1) сделайте альтернативное монтирование вашей файловой системы, где находится ваше magento:

mount /dev/sdXY /mnt/tmp

(2) выполните --bindмонтирование вашего public_html_new в public_html:

mount --bind /path/to/public_html_new /path/to/public_html

С этого момента apache увидит ваше новое развертывание. Любое изменение 404 невозможно.

(3) выполнить синхронизацию с rsync, но в альтернативной точке монтирования):

rsync -vaH --delete /mnt/tmp/path/to/public_html_new/ /mnt/tmp/path/to/public_html/

(4) снять крепление

umount /path/to/public_html
Петер говорит восстановить Монику
источник
Будет ли команда удалять public_html и развертывать в ней public_html_new?
nicoX
@nicoX Нет, он будет копировать только изменения.
Петер говорит восстановить Монику
@nicoX Проходит через обе структуры каталогов, и, если он обнаруживает разницу (новый файл, измененный файл, удаленный файл), он изменяет второй каталог так, чтобы он соответствовал первому по мере необходимости. Результат, если вы удалили public_html, а затем переместили public_html_new на свое место, но без какой-либо возможности временной проблемы 404.
Петер говорит восстановить Монику
1
Нет, это не очень хорошая идея. В зависимости от изменений у вас может быть короткий промежуток времени, когда код public_htmlнаходится в несогласованном состоянии, и вы не хотите использовать этот шанс.
Свен
@SvW Вы правы, моя идея верна только в случае незначительных изменений. Я расширил свой ответ соответственно.
Петер говорит восстановить Монику
1

Перемещение / замена http_publicпапки может быть достигнуто с помощью простых mvили ln -sкоманд или эквивалентных, пока ваш http-сервер продолжает работать. Вы можете сделать некоторые сценарии, чтобы значительно сократить время простоя, но тщательно проверяйте коды возврата ваших команд в сценарии, если вы автоматизируете процесс.

Тем не менее, если вы хотите избежать простоя, ваше приложение также должно его поддерживать. Большинство приложений использует базу данных для постоянства. Использование версии N вашего приложения в сочетании с версией N + 1 (или наоборот) вашей модели данных может привести к поломке, если это не предусмотрено командой разработчиков.

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

Уриэль
источник