Pull to refresh

Comments 49

Именно так работает сайт erlyvideo.ru/ (он же и erlyvideo.org/)

Из одной папки в гите берутся файлы, выбирается русский или английский вариант и смотрим.
Спасибо, хороший пост. Отличная идея: хранить рабочую копию сайта и bare-репозиторий отдельно. Применяли ли вы ваш метод на практике?
Я как раз на прошлой сделал что-то похожее на 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 на нужную ревизию.
А зачем закрывать через .htaccess папку .git когда можно использовать detached рабочий каталог и хранить сам репозиторий в недоступном для веб-сервера месте?
Опция --work-tree служит для этой цели. www.kernel.org/pub/software/scm/git/docs/
Зачем?! Зачем использовать систему контроля версия для деплоя?!

Вас ничему история не учит? http://habrahabr.ru/blogs/infosecurity/70330/

Нет, я, конечно, прочитал, что в статье есть предложение по закрытию доступа к .git директории, но что, если админ ошибется и не сможет правильно настроить mod_rewrite (или правила nginx)?

Почему для деплоя не пользоваться утилитами, специально для этого предназначенными? К примеру, тот же Capistrano (а еще лучше capistrano-ext со стейджингом, чтобы случайно не деплойнуть на продакшн неподготовленный код).
Ну… с гитом подобной проблемы, как у svn, нет. Достаточно только, чтобы DocumentRoot хоста находился внутри каталога проекта, или вообще в отдельном каталоге.

Все свои потроха гит содержит аккуратно, не разбрасывая их по подпапкам проекта.
Для небольших проектов специальные утилиты потребуют слишком много лишних и непонятных телодвижений. Вариант с --work-tree мне нравится намного больше.
А в статье где-нибудь указано, что данный подход желательно применять только на небольших проектах?

И еще, настройка репозиториев, хуков, 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-папка проектов всегда внутри репа (не корневая), поэтому никаких мод-реврайтов не нужно
как-то не правильно. Лучше использовать capistrano или подобное, ну на крайний случай делать экспорт в нужный каталог по hook'у.
я свои рельсы уже пару лет деплою через гит, и мне, честно говоря, пользователей капистраны немного жалко.
Откатите продакшен на 1 версию назад находясь на рабочей машине. Через git деплоить хорошо, да, но не так как это сделал автор, зачем второй репозиторий? Делать экспорт прямо из bare в нужный каталог.

> пользователей капистраны немного жалко.

Вы просто не умеете ее готовить. Тоже самое говорят хомячки про пользователей unix like os и эникейщики про сервера на unix like.
> Тоже самое говорят хомячки про пользователей unix like os и эникейщики про сервера на unix like
я работаю на Ubuntu 11.04, продакшн-сервера все на Ubuntu. и капистрано тем не менее для меня монструозен.

выше я написал, что в отличие от автора у меня один реп, да.
Вы кажется не поняли метафору…

> выше я написал, что в отличие от автора у меня один реп, да.

Тоже как-то не так вас…

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 системами — как сравнивать тех, кто не любит анчоусы с теми, кто не ест жирное.
А как производите обновление БД?
я работаю с mongodb, поэтому миграции мне не нужны. а менять схему (к примеру перекидывать одно поле в другое) нужно нечасто, в этих случаях захожу через ssh
UFO just landed and posted this here
С моей точки зрения это очень не правильный подход. При данном подходе все новые изменения сразу попадут на продакшн сервер. А если в этих изменениях будет регрессионные ошибки? Они сразу положат продакшн сервер… Для того что бы изменения не убили продакшн сервер, умные люди придумали вехи и версии, которые в репозитории будут отмечены тэгами. Продакшн сервер нужно обновлять только на определенный тэг, содержащий фиксированное число изменений проверенных тестировщиками. Таким образом вы сможете более менее гарантировать качество кода и сайта в целом. Описанный у вас способ подходит для деплоя на девелопмент сервер и в меньшей мере на стэйджинг сервер.
Ничего не мешает пушать на сервер тэг, который перед тем был на стейджинге и на тестинге.
видимо, так и появилась возможность пушить коммиты из prime в hub — вполне себе решение, если нет возможности содержать процесс с блэк^H^H^H^H стэйджингом и тестировщиками)
да, согласен, так и надо делать, но статья предлагает другой подход, который заключается в моментальном обновлении продакшн сервера при любом пуше.
как разрешаются конфликты при git pull?

этой проблемы не возникает, если с девелоперского сайта делать 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). Но при наличии таких блокировок решается не только проблема атомарного обновления проекта, но и консистентного бэкапа.
У нас вот SQL база особо часто не обновляется да и вообще, по большей части, уходим от SQL решений в последнее время, так что проект не приходится останавливать по причине обновления. Да и даже если обновляется, то обычно это добавление поля в табличку или новой таблички, а значит можно сначала базу обновить, не останавливая или, в крайнем случае, блокируя по частям (а значит проект будет работать, максимум какое-то относительно небольшое количество пользователей получит информацию о server maintenance), а уже потом можно и код, работающий с БД, обновить.
на мой вкус я бы при ините добавил shared,
если предполагается, что пушить в 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, упомянуть в скобочках, что это «репозиторий без собственной рабочей копии»
и фразу «Одно из основных правил при работе с Git — никогда не делайте push в репозтирий, у которого есть рабочая копия.» куда-нибудь во вступление бы поместить, ибо она — ключевая.
У нас на «prime» заливается по ftp с помощью модуля ftp для hg. Хук на «hub» у всех репов такой: changegroup = hg update -C; hg ftp -r tip -u. Заливаются не все файлы, а только изменившиеся (это и делает модуль ftp).

Тут чуть подробнее: edhel.krasu.ru/node/328

Минус в том, что используется нешифрованный протокол (ftp), а hg-модуль ftp по ssh/sftp заливать изменения не умеет. Но у нас заливка идёт по локалке, поэтому не критично. И ftp-порт на «prime» открыт только для «hub», поэтому и утечка логина-пароля от ftp не критична.
Извините, возможно мой вопрос покажется странным, но я пока не могу управиться с правами на директории/файлы при работе через гит.
Например у меня есть сайт который разрабатывается через гит. Над сайтом работают 3 разработчика, все ходят по ssh.
Ситуация:
Первый разработчик изменяет/создает файл в своем локальном репозитории, коммитит, пушит в bare репозиторий, идет на рабочий сайт и делает pull в результате первый разработчик становится хозяином файла. Потом надо второму разработчику работать с этим же файлом, но он не может его править, т.к. он не хозяин. Можно добавить разработчиков в одну группу, но гит вроде бы создает файлы с правами 644. Плюс ко всему файлы могут создаваться апачем. Может кто нибудь подскажет как решить этот вопрос? Может я что-то упускаю?
Вам надо пулить от имени веб-сервера.
Как лучше это сделать зависит от вашей ситуации.
Можно на веб-сервере скрипт сделать, можно по задачке в кроне отслеживать, можно еще вариантов придумать.
Дело в том, что в некоторых директориях апач не должен иметь право на изменение файлов, а разработчики наоборот должны иметь право на изменение файлов в этих директориях. Пока решение такое — использовать setfacl и определять через него кто будет писать, а кто нет. С помощью setfacl для файла/директории можно будет указать сразу несколько хозяев и несколько групп. И ночью в определенное время, по крону, восстанавливать права на файлы.
Sign up to leave a comment.

Articles