Comments 49
Именно так работает сайт erlyvideo.ru/ (он же и erlyvideo.org/)
Из одной папки в гите берутся файлы, выбирается русский или английский вариант и смотрим.
Из одной папки в гите берутся файлы, выбирается русский или английский вариант и смотрим.
Спасибо, хороший пост. Отличная идея: хранить рабочую копию сайта и bare-репозиторий отдельно. Применяли ли вы ваш метод на практике?
Да, так работает webstandardsdays.ru, например.
Я как раз на прошлой сделал что-то похожее на Mercurial.
Смысл такой: к существующей системе контроля версий добавился репозиторий на тестовом сервере, в котором стоит хук на пуш. Поэтому для обновления версии достаточно выбрать удалённый репозиторий и ввести логин-пароль (отличающийся от пароля в рабочем репозитории, чтобы избежать случайного пуша куда не надо).
Смысл такой: к существующей системе контроля версий добавился репозиторий на тестовом сервере, в котором стоит хук на пуш. Поэтому для обновления версии достаточно выбрать удалённый репозиторий и ввести логин-пароль (отличающийся от пароля в рабочем репозитории, чтобы избежать случайного пуша куда не надо).
У меня в кроне стоит так:
* * * * * cd /home/project/project/ && /usr/bin/hg -q pull && /usr/bin/hg update production | grep -v «0 files updated, 0 files merged, 0 files removed, 0 files unresolved» && /bin/touch web/django.wsgi
Причем на разных нодах разное время запуска крона. Это делалось специально, что б перезапуск серверов на нодах не происходил одновременно, т.е. достигается нулевой общий даунтайм. Ну и еще пара нод обновляется раз в полчаса, что б если все-таки было накосячено, успеть за мат-ожидание исправить проблему.
Не делал хуков на push (или всякие fabric'и) именно по причине требования к нулевому общему даунтайму.
Ну а само обновление продакшн-нод досигается просто перемещением метки production на нужную ревизию.
* * * * * cd /home/project/project/ && /usr/bin/hg -q pull && /usr/bin/hg update production | grep -v «0 files updated, 0 files merged, 0 files removed, 0 files unresolved» && /bin/touch web/django.wsgi
Причем на разных нодах разное время запуска крона. Это делалось специально, что б перезапуск серверов на нодах не происходил одновременно, т.е. достигается нулевой общий даунтайм. Ну и еще пара нод обновляется раз в полчаса, что б если все-таки было накосячено, успеть за мат-ожидание исправить проблему.
Не делал хуков на push (или всякие fabric'и) именно по причине требования к нулевому общему даунтайму.
Ну а само обновление продакшн-нод досигается просто перемещением метки production на нужную ревизию.
А зачем закрывать через .htaccess папку .git когда можно использовать detached рабочий каталог и хранить сам репозиторий в недоступном для веб-сервера месте?
Опция --work-tree служит для этой цели. www.kernel.org/pub/software/scm/git/docs/
Опция --work-tree служит для этой цели. www.kernel.org/pub/software/scm/git/docs/
Зачем?! Зачем использовать систему контроля версия для деплоя?!
Вас ничему история не учит? http://habrahabr.ru/blogs/infosecurity/70330/
Нет, я, конечно, прочитал, что в статье есть предложение по закрытию доступа к .git директории, но что, если админ ошибется и не сможет правильно настроить mod_rewrite (или правила nginx)?
Почему для деплоя не пользоваться утилитами, специально для этого предназначенными? К примеру, тот же Capistrano (а еще лучше capistrano-ext со стейджингом, чтобы случайно не деплойнуть на продакшн неподготовленный код).
Вас ничему история не учит? http://habrahabr.ru/blogs/infosecurity/70330/
Нет, я, конечно, прочитал, что в статье есть предложение по закрытию доступа к .git директории, но что, если админ ошибется и не сможет правильно настроить mod_rewrite (или правила nginx)?
Почему для деплоя не пользоваться утилитами, специально для этого предназначенными? К примеру, тот же Capistrano (а еще лучше capistrano-ext со стейджингом, чтобы случайно не деплойнуть на продакшн неподготовленный код).
Ну… с гитом подобной проблемы, как у svn, нет. Достаточно только, чтобы DocumentRoot хоста находился внутри каталога проекта, или вообще в отдельном каталоге.
Все свои потроха гит содержит аккуратно, не разбрасывая их по подпапкам проекта.
Все свои потроха гит содержит аккуратно, не разбрасывая их по подпапкам проекта.
Для небольших проектов специальные утилиты потребуют слишком много лишних и непонятных телодвижений. Вариант с --work-tree мне нравится намного больше.
А в статье где-нибудь указано, что данный подход желательно применять только на небольших проектах?
И еще, настройка репозиториев, хуков, mod_rewrite, а также системы сообщения между prime и hub репозиториями затмит собой настройку скрипта для capistrano и пробросу пары ключей между машинами :)
И еще, настройка репозиториев, хуков, mod_rewrite, а также системы сообщения между prime и hub репозиториями затмит собой настройку скрипта для capistrano и пробросу пары ключей между машинами :)
я в отличие от автора с двумя репами, сделал один реп с бранчами мастер (в который пушу) и продакшн (который чекаутнут на сервере). далее deploy.sh:
а сколько строк в вашем капистрано-конфиге?
git checkout master
git merge newfeature
git merge bugfix
git push server master
ssh xxx@librapost.ru "cd /xxx/xxx/librapost && git merge master"
а сколько строк в вашем капистрано-конфиге?
ах да. public-папка проектов всегда внутри репа (не корневая), поэтому никаких мод-реврайтов не нужно
Поищите на гитхабе строчку «git ftp»
как-то не правильно. Лучше использовать capistrano или подобное, ну на крайний случай делать экспорт в нужный каталог по hook'у.
я свои рельсы уже пару лет деплою через гит, и мне, честно говоря, пользователей капистраны немного жалко.
Откатите продакшен на 1 версию назад находясь на рабочей машине. Через git деплоить хорошо, да, но не так как это сделал автор, зачем второй репозиторий? Делать экспорт прямо из bare в нужный каталог.
> пользователей капистраны немного жалко.
Вы просто не умеете ее готовить. Тоже самое говорят хомячки про пользователей unix like os и эникейщики про сервера на unix like.
> пользователей капистраны немного жалко.
Вы просто не умеете ее готовить. Тоже самое говорят хомячки про пользователей unix like os и эникейщики про сервера на unix like.
Вы кажется не поняли метафору…
> выше я написал, что в отличие от автора у меня один реп, да.
Тоже как-то не так вас…
git archive master | tar -x -C /somewhere/else
ну или так:
git-archive --format=tar --remote=ssh://remote_server/remote_repository master | tar -xf — в пост-апдейт хук и все.
> deploy.sh:
git checkout master
git merge newfeature
git merge bugfix
git push server master
git алисы вы не осилили, ога.
> выше я написал, что в отличие от автора у меня один реп, да.
Тоже как-то не так вас…
git archive master | tar -x -C /somewhere/else
ну или так:
git-archive --format=tar --remote=ssh://remote_server/remote_repository master | tar -xf — в пост-апдейт хук и все.
> deploy.sh:
git checkout master
git merge newfeature
git merge bugfix
git push server master
git алисы вы не осилили, ога.
зачем мне алиасы там, где я не ввожу команды руками?
ваш вариант с гит-архивом я вообще понять не могу. зачем мне делать на сервере отдельно папку с репом (в который всё равно для деплоя надо будет пушить), и отдельно папку, в которую будет разархивироваться деплой? и что мне делать, если у меня в свежем деплое найдётся критикал баг, и надо будет срочно откатиться назад? иметь в продакшене рабочий реп тоже полезно.
метафору я понял. только вот не понял, зачем вы её здесь привели. удобство капистраны настолько субъективная вещь, что сравнивать её с *nix системами — как сравнивать тех, кто не любит анчоусы с теми, кто не ест жирное.
ваш вариант с гит-архивом я вообще понять не могу. зачем мне делать на сервере отдельно папку с репом (в который всё равно для деплоя надо будет пушить), и отдельно папку, в которую будет разархивироваться деплой? и что мне делать, если у меня в свежем деплое найдётся критикал баг, и надо будет срочно откатиться назад? иметь в продакшене рабочий реп тоже полезно.
метафору я понял. только вот не понял, зачем вы её здесь привели. удобство капистраны настолько субъективная вещь, что сравнивать её с *nix системами — как сравнивать тех, кто не любит анчоусы с теми, кто не ест жирное.
А как производите обновление БД?
UFO just landed and posted this here
С моей точки зрения это очень не правильный подход. При данном подходе все новые изменения сразу попадут на продакшн сервер. А если в этих изменениях будет регрессионные ошибки? Они сразу положат продакшн сервер… Для того что бы изменения не убили продакшн сервер, умные люди придумали вехи и версии, которые в репозитории будут отмечены тэгами. Продакшн сервер нужно обновлять только на определенный тэг, содержащий фиксированное число изменений проверенных тестировщиками. Таким образом вы сможете более менее гарантировать качество кода и сайта в целом. Описанный у вас способ подходит для деплоя на девелопмент сервер и в меньшей мере на стэйджинг сервер.
да, согласен, так и надо делать, но статья предлагает другой подход, который заключается в моментальном обновлении продакшн сервера при любом пуше.
промазал, этот комментарий — ответ на http://habrahabr.ru/blogs/Git/127213/#comment_4200113
как разрешаются конфликты при git pull?
этой проблемы не возникает, если с девелоперского сайта делать git push на продакшн.
этой проблемы не возникает, если с девелоперского сайта делать git push на продакшн.
#!/bin/bash
txtrst='\e[0m' # Text Reset
txtred='\e[0;31m' # Red
txtgrn='\e[0;32m' # Green
WORK_TREE='/some/path/on/dev/server/'
while read oldrev newrev ref
do
case $ref in
refs/heads/dev )
echo "========================================"
git --work-tree=$WORK_TREE checkout -f dev
if [ $? -eq 0 ]; then
echo -e "${txtgrn}DEVELOPER SERVER successfully updated${txtrst}"
else
echo -e "${txtred}Failed to checkout DEVELOPER SERVER!${txtrst}"
fi
;;
refs/heads/master )
echo "========================================"
git push gsl master:master
if [ $? -eq 0 ]; then
echo -e "${txtgrn}PRODUCTION SERVER successfully updated${txtrst}"
else
echo -e "${txtred}Failed to push to PRODUCTION SERVER!${txtrst}"
fi
;;
* )
echo "NO UPDATES FOR $1"
;;
esac
done
echo "========================================"
вот мой post-receive hook на девелоперском сервере.
принцип работы: есть две ветки — master и dev. изменения в ветке dev checkout'ятся в DOCUMENT_ROOT девелопеского сервера. А изменения в ветке master push'атся в bare-репозиторий на продакшн-сервере, а оттуда уже аналогичным образом chekout'ятся в его DOCUMENT_ROOT
Деплоить должен человек. Руками. Если оставить это на хук то в один прекрасный момент вы получите неработающий продакшн. А делать исправления на работающем сервере и заливать их в репозиторий — это вообще за гранью добра и зла! Вы там что, на Друпале пишете??
Пытаюсь найти еще информацию по теме выкладывания новой версии на продакшен, но не могу найти.
Подскажите ключевые слова :)
Подскажите ключевые слова :)
Я как-то пока что не особо с джитом, поэтому вопрос: операция деплоя в данном случае атомарна? Если нет, тогда не вижу смысла в ней принципе, не говоря уже об habrahabr.ru/blogs/Git/127213/#comment_4200454
а у вас что, часто соединение обрывается во время деплоя? при чём здесь атомарность?
Не, меня интересует, на новые исходники сайт переключается атомарно или в какой-то момент времени половина сырцов предыдущей ревизии, а половина — новой ревизии.
Мы себе не можем позволить обновлять файлы прямо в живом каталоге проекта на сервере.
Поэтому у нас сначала льется на сервер архив, который распаковывается в новую папку и потом производится переключение на эту папку.
Кроме того, не можем себе позволить удалить старые файлы, потому что на них еще могут какие-то кроны работать.
Мы себе не можем позволить обновлять файлы прямо в живом каталоге проекта на сервере.
Поэтому у нас сначала льется на сервер архив, который распаковывается в новую папку и потом производится переключение на эту папку.
Кроме того, не можем себе позволить удалить старые файлы, потому что на них еще могут какие-то кроны работать.
у меня несколько сотен файлов в гите меняется за доли секунды. но тут же зависит от языка и фреймворка. и такой вопрос, а нельзя отрубать сервер и кроны на секунды во время деплоя? zero-downtime-deploy в конце концов?
ну и последний вопрос: а где вы вообще нашли такой инструмент, который моментально атомарно несколько сотен файлов может заменить? на это как-то даже и современные файловые системы не способны. да одновременно сменить сотни записей даже совеменные БД не очень умеют атомарно
ну и последний вопрос: а где вы вообще нашли такой инструмент, который моментально атомарно несколько сотен файлов может заменить? на это как-то даже и современные файловые системы не способны. да одновременно сменить сотни записей даже совеменные БД не очень умеют атомарно
У нас за доли секунды несколько сотен запросов на сервера приходит…
Во время деплоя ничего отрубать нельзя.
В нашем случае не нужно заменять атомарно несколько сотен файлов, нужно просто переключить проект на другую папку после того, как в этой папке есть всё нужное для работы проекта. И это происходит вполне себе атомарно. Кроны остаются работать в старых каталогах, но в следующий раз уже запустятся из нового каталога.
В общем, мы сейчас о немного разных вещах говорим… Наверное, нужно было просто разобраться немного в джите и не задавать того вопроса :)
Во время деплоя ничего отрубать нельзя.
В нашем случае не нужно заменять атомарно несколько сотен файлов, нужно просто переключить проект на другую папку после того, как в этой папке есть всё нужное для работы проекта. И это происходит вполне себе атомарно. Кроны остаются работать в старых каталогах, но в следующий раз уже запустятся из нового каталога.
В общем, мы сейчас о немного разных вещах говорим… Наверное, нужно было просто разобраться немного в джите и не задавать того вопроса :)
Вообще-то речь не про «одновременно», а про «атомарно». Вариант с изменением рабочего каталога — операция хоть и атомарная, но не решает проблему атомарного обновления частей проекта, которые находятся вне рабочего каталога (база данных, настройки cron, почтовые хуки в ~/.qmail, etc.).
Наша deploy-система блокирует проект, обновляет файлы, структуру базы, настройки cron, перезапускает отдельные сервисы, etc. а потом снимает блокировку. Это гарантирует, что в процессе обновления не получится так, что часть файлов/базы уже обновилась, часть ещё нет, и тут приходит запрос пользователя и он обрабатывается смесью старого и нового кода с в принципе непредсказуемыми последствиями. Кроме того, это гарантирует, что если обновление затянется или сломается в процессе, то пользователь получит статическую страничку «server maintenance, please try again later».
Системы контроля версий всё это делать не умеют и они вообще не предназначены для реализации deploy. Можно, конечно, навесить на них сложные системы хуков и получить почти то, что требуется, но это сложно и не правильно. Для deploy нужно использовать предназначенные для этого системы. И выкатывать новую версию на production сервер нужно ручками, а не автоматически (не в том смысле, что файлы/базу ручками обновлять, а в том смысле, что во-первых желательно перед обновлением глазками просмотреть все изменения — т.е. patch/sql/etc.-файлы — и во-вторых присутствовать при установке этих изменений на сервере на случай если что-то пойдёт не так).
Единственная сложность такого надёжного подхода в том, что все приложения проекта (cgi-шки, fastcgi-сервер, сервисы, cron-скрипты, qmail-скрипты, консольные утилиты) должны поддерживать единую систему блокировок, чтобы было возможно их всех одним махом заблокировать на время обновления системы (все приложения ставят shared-lock в процессе работы, а при обновлении ставится exclusive-lock). Но при наличии таких блокировок решается не только проблема атомарного обновления проекта, но и консистентного бэкапа.
Наша deploy-система блокирует проект, обновляет файлы, структуру базы, настройки cron, перезапускает отдельные сервисы, etc. а потом снимает блокировку. Это гарантирует, что в процессе обновления не получится так, что часть файлов/базы уже обновилась, часть ещё нет, и тут приходит запрос пользователя и он обрабатывается смесью старого и нового кода с в принципе непредсказуемыми последствиями. Кроме того, это гарантирует, что если обновление затянется или сломается в процессе, то пользователь получит статическую страничку «server maintenance, please try again later».
Системы контроля версий всё это делать не умеют и они вообще не предназначены для реализации deploy. Можно, конечно, навесить на них сложные системы хуков и получить почти то, что требуется, но это сложно и не правильно. Для deploy нужно использовать предназначенные для этого системы. И выкатывать новую версию на production сервер нужно ручками, а не автоматически (не в том смысле, что файлы/базу ручками обновлять, а в том смысле, что во-первых желательно перед обновлением глазками просмотреть все изменения — т.е. patch/sql/etc.-файлы — и во-вторых присутствовать при установке этих изменений на сервере на случай если что-то пойдёт не так).
Единственная сложность такого надёжного подхода в том, что все приложения проекта (cgi-шки, fastcgi-сервер, сервисы, cron-скрипты, qmail-скрипты, консольные утилиты) должны поддерживать единую систему блокировок, чтобы было возможно их всех одним махом заблокировать на время обновления системы (все приложения ставят shared-lock в процессе работы, а при обновлении ставится exclusive-lock). Но при наличии таких блокировок решается не только проблема атомарного обновления проекта, но и консистентного бэкапа.
У нас вот SQL база особо часто не обновляется да и вообще, по большей части, уходим от SQL решений в последнее время, так что проект не приходится останавливать по причине обновления. Да и даже если обновляется, то обычно это добавление поля в табличку или новой таблички, а значит можно сначала базу обновить, не останавливая или, в крайнем случае, блокируя по частям (а значит проект будет работать, максимум какое-то относительно небольшое количество пользователей получит информацию о server maintenance), а уже потом можно и код, работающий с БД, обновить.
на мой вкус я бы при ините добавил shared,
если предполагается, что пушить в bare будут несколько человек:
или даже сделать так после init:
еще обновить server-info лучше сразу после первого пуша руками так:
а в post-receive делать так:
если предплолагается, что в репозитории есть субмодули.
если предполагается, что пушить в bare будут несколько человек:
git --bare init --shared
или даже сделать так после init:
cd ..
sudo chown -R www-data:www-data site_hub.git
sudo chmod -R g+wX,o= site_hub.git
sudo find site_hub.git -type d -exec chmod g+s '{}' ';'
еще обновить server-info лучше сразу после первого пуша руками так:
git update-server-info
а в post-receive делать так:
cd /home/okertanov/public_html/html-templates.espectrale.com/public || exit
#unset GIT_DIR
#unset GIT_WORK_TREE
env -i git pull origin #or whatever
env -i git update-server-info
env -i git submodule init
env -i git submodule update
если предплолагается, что в репозитории есть субмодули.
Прошу при первом упоминании слова bare, упомянуть в скобочках, что это «репозиторий без собственной рабочей копии»
У нас на «prime» заливается по ftp с помощью модуля ftp для hg. Хук на «hub» у всех репов такой: changegroup = hg update -C; hg ftp -r tip -u. Заливаются не все файлы, а только изменившиеся (это и делает модуль ftp).
Тут чуть подробнее: edhel.krasu.ru/node/328
Тут чуть подробнее: edhel.krasu.ru/node/328
Извините, возможно мой вопрос покажется странным, но я пока не могу управиться с правами на директории/файлы при работе через гит.
Например у меня есть сайт который разрабатывается через гит. Над сайтом работают 3 разработчика, все ходят по ssh.
Ситуация:
Первый разработчик изменяет/создает файл в своем локальном репозитории, коммитит, пушит в bare репозиторий, идет на рабочий сайт и делает pull в результате первый разработчик становится хозяином файла. Потом надо второму разработчику работать с этим же файлом, но он не может его править, т.к. он не хозяин. Можно добавить разработчиков в одну группу, но гит вроде бы создает файлы с правами 644. Плюс ко всему файлы могут создаваться апачем. Может кто нибудь подскажет как решить этот вопрос? Может я что-то упускаю?
Например у меня есть сайт который разрабатывается через гит. Над сайтом работают 3 разработчика, все ходят по ssh.
Ситуация:
Первый разработчик изменяет/создает файл в своем локальном репозитории, коммитит, пушит в bare репозиторий, идет на рабочий сайт и делает pull в результате первый разработчик становится хозяином файла. Потом надо второму разработчику работать с этим же файлом, но он не может его править, т.к. он не хозяин. Можно добавить разработчиков в одну группу, но гит вроде бы создает файлы с правами 644. Плюс ко всему файлы могут создаваться апачем. Может кто нибудь подскажет как решить этот вопрос? Может я что-то упускаю?
Вам надо пулить от имени веб-сервера.
Как лучше это сделать зависит от вашей ситуации.
Можно на веб-сервере скрипт сделать, можно по задачке в кроне отслеживать, можно еще вариантов придумать.
Как лучше это сделать зависит от вашей ситуации.
Можно на веб-сервере скрипт сделать, можно по задачке в кроне отслеживать, можно еще вариантов придумать.
Дело в том, что в некоторых директориях апач не должен иметь право на изменение файлов, а разработчики наоборот должны иметь право на изменение файлов в этих директориях. Пока решение такое — использовать setfacl и определять через него кто будет писать, а кто нет. С помощью setfacl для файла/директории можно будет указать сразу несколько хозяев и несколько групп. И ночью в определенное время, по крону, восстанавливать права на файлы.
Sign up to leave a comment.
Git и публикация сайта