Деплой с помощью Mercurial

Новости сообщества
Итак, я все мучаю бедный сервер. Дальше — очередная, никому кроме меня не нужная стена текста про развертывание сайта с помощью mercurial. Если кратко, это поможет очень быстро вносить изменения в сайтик, и сильно ускорит его допиливание.

Mercurial

Зачем?
Я давно хотел, чтобы изменения на сайтик выкладывались как можно проще, потому, что сейчас это происходит так:
  • Я модифицирую код
  • Вспоминаю, в каких файлах что сделал
  • Перекидываю файлы по FTP
  • Сношу три кэша (да, в лайвстрите аж 3 кэша)
  • Бинго

Это не красиво и долго. Самый простой выход — использовать для этого систему контроля версий (я привык к mercurial). Она сама будет смотреть за изменениями и перемещать только изменившиеся файлы. Да и мне будет легко видеть что поменялось от ревизии к ревизии.

Сказано-сделано.

Ставим mercurial на сервер.

apt-get install mercurial


создаем каталог для репозиториев:
mkdir /var/repos


Добавляем под домен для mercurial (/etc/nginx/conf.d/):

upstream hg_backend {
    server 127.0.0.1:8245;
}

server {
    listen       80;
    server_name  hg.tqfp.org;

    access_log  /var/log/nginx/hg_access.log;
    error_log   /var/log/nginx/hg_error.log warn;

    client_max_body_size 100m;

    location / {
        auth_basic           "Restricted";
        auth_basic_user_file /etc/nginx/hg.htpasswd;
        proxy_pass           https://hg_backend;
    }
}


То есть, при обращении к hg.tqfp.org, просим пароль, если все хорошо, соединяем с сервером mercurial'а на локалхосте.

перезапускаем nginx:
service nginx restart


теперь нужно бы добавить пользователей. Для этого используются утилиты от apache:
apt-get install apache2-utils


добавляем пользователя:
htpasswd -m hg.htpasswd bsvi


Добавляем файлик, который указывает, где искать репозитории (/etc/hgweb.conf):
[collections]
/var/repos/ = /var/repos/


А в /etc/mercurial/hgrc:
[web]
style = gitweb
allow_push = *
push_ssl = false
baseurl =/.


Теперь нужно запустить сам mercurial. Самое интересное, что готового скрипта для авто-запуска mercurial я не нашел (точнее, что-то нашел, но оно было нерабочим). Пришлось писать по аналогии с nginx'ом:


#!/bin/sh
### BEGIN INIT INFO
# Provides:          hg
# Required-Start:    $remote_fs
# Required-Stop:     $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Mercurial VCS
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Mercurial VCS"
NAME=hg
HOME=/var/$NAME
DAEMON=/usr/bin/$NAME
PIDFILE=/var/run/$NAME.pid
DAEMON_ARGS="serve --webdir-conf /etc/mercurial/hgweb.conf \
                   --address 127.0.0.1 --port 8085 --encoding utf8 --daemon --pid-file $PIDFILE"
                   
SCRIPTNAME=/etc/init.d/$NAME

[ -x "$DAEMON" ] || exit 0
. /lib/init/vars.sh
. /lib/lsb/init-functions

do_start()
{
	touch $PIDFILE
	chown hg $PIDFILE
	start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON \
		--chuid hg:hg -- $DAEMON_ARGS || return 2
}

do_stop()
{
	start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
		--pidfile $PIDFILE --name $NAME
	RETVAL="$?"
	[ "$RETVAL" = 2 ] && return 2
	start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 \
		--exec $DAEMON
	[ "$?" = 2 ] && return 2
	rm -f $PIDFILE
	return "$RETVAL"
}

case "$1" in
  start)
	[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
	do_start
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
  stop)
	[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
	do_stop
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
  restart|force-reload)
	log_daemon_msg "Restarting $DESC" "$NAME"
	do_stop
	case "$?" in
	  0|1)
		do_start
		case "$?" in
			0) log_end_msg 0 ;;
			1) log_end_msg 1 ;; # Old process is still running
			*) log_end_msg 1 ;; # Failed to start
		esac
		;;
	  *)
	  	# Failed to stop
		log_end_msg 1
		;;
	esac
	;;
  *)
	echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
	exit 3
	;;
esac

:


теперь его можно установить (предварительно, скопировав в /etc/init.d):
update-rc.d hg defaults


Позже я решил, что я буду включать mercurial только когда работаю над сайтом — на одну возможность хакнуть сайт будет меньше :)

ну, и запускаем сам mercurial:
./hg start


Деплой
Теперь нужно решить, как мы будем разворачивать наш сайтик. Я для этого решил использовать немного небезопасный метод (привет, паранойя). Идея вот в чем: при пуше, вызывается скрпт, который создает симлинк из /var/repos/tqfp.org/.hg в chroot самого сайта (/var/www/tqfp.org/.hg). Там делается hg update и симлинк уничтожается. Если за пару секунд, за которые происходит это действо, кто-то успеет получить root'а и прицепить хук к окончанию апдейта mercurial, то он получит доступ ко всему серверу. Ничего лучше я не придумал (точнее, придумал, но получилось бы не так круто), поэтому — рискнем.

Итак, создаем /var/repos/tqfp.org/.hg/hgrc:
[hooks]
changegroup = /var/repos/tqfp.org/hg_sync.sh


Ну, и сам hg_sync.sh:
#!/bin/sh

REPO_DIR=/var/repos/tqfp.org
DEST_DIR=/var/www/tqfp.org

if [ `whoami` = root ]; then
   echo "root shall do su hg!"
   exit 1
fi

ln -s $REPO_DIR/.hg $DEST_DIR/.hg

cd $DEST_DIR
hg update --clean
rm .hg
echo "flush_all" | /bin/netcat -q 2 127.0.0.1 11211
rm -rf templates/compiled/bsvi/*
rm -rf templates/cache/bsvi/*


Вуаля!

Теперь мне на локалке достаточно написать:
hg push


и все изменения отправятся на сервер, сбросятся кэши и вы увидите обновленный сайтик :)

1 комментарий

avatar
Вах! какой старый, но какой своевременный статья!
По методу — хитро — и деплой есть, и дыры (папка .hg) нет :)
Хотя тема деплоя раскрыта не полностью. Ведь можно(а лучше нужно) делать деплой определенной ветки.
Раздумываю еще… Abricos, к примеру, любит модернизировать базу данных при обновлении. Как бы так витиевато иметь возможность отката не из ночных бэкапов и привязать базу к меркуралу, причем содержимое базы категорически не должно быть в репо.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.