Как да използваме git, github и ssh за да имаме синхронизиран код на test и prod на различни сървъри

Използването на git е незаменимо. Освен да имаме на едно и също място различни варианти на един и същи код (приложение, сайт), ние може да използваме git за синхронизиране на приложението на различни сървъри с прости команди като "git push test v2.x", "git push prod 2.0" примерно. Това се извършва от локалната машина, на която разработваме приложението и без използването на други начини като ftp например, да качим направените промени на различните сървъри, където се намира нашето приложение за тестване, и живия сайт например. Като се разбере тази схема, може лесно да бъде модифицирана за различни схеми. Така например може да се ползва един и същ сървър, на който се намират тест сайта и живия сайт, като с различни branches ги актуализираме по отделно. Или тест сайта и живия сайт са на различни сървъри. За всички тези схеми може да се ползват различни branches за актуализиране на различни версии на сайта.

За целта е необходимо да знаем:

  • да ползваме git и github.com (или друго място),
  • да правим branch и merge,
  • да се свързваме по ssh,
  • да можем да създадем и настроим виртуален хост на уеб сървъра който ползваме (без значение apache, nginx или друг).

Предполага се, че използваме:

  • git за version control
  • http://github.com за съхраняване на кода
  • имаме ssh достъп до сървърите, на които са сайтовете
  • test сървър, на който е сайта за тестване
  • prod сървър, на който е "живия" сайт

под "сървър" по-горе се има предвид отделна машина/виртуална машина на различно ip или домейн.

След като имаме акаунт на github, създаваме едно repo. Клонираме го на локалната машина, и добавяме кода и актуализираме repo-то. За какво ни е репото в github? За да може и другите колеги от екипа да имат актуалния код на приложението.

На test сървъра:

mkdir ~/repos/
cd ~/repos/
GIT_DIR=myproject.git git init
cd myproject.git
git --bare update-server-info
cp hooks/post-update.sample hooks/post-update

Трябва да можем да държим актуално копие на кода на test сървъра в така създаденото репо. За това изпълняваме на локалната машина от директорията на проекта

git remote add test user@server:~/repos/myproject.git/

Това ще ни позволи с

git push test

да качваме промените на test сървъра.

Дотук имаме актуален код на тест сървъра, но все още нямаме работещ сайт за тестване.

Създаваме такъв във /var/www/vhosts/myproject.test. Създаваме и настройки за него на използвания уеб сървър - apache, nginx, или друго, каквото използваме за това.

Сега идва ред на магията - автоматично да се актуализира кода на сайта във /var/www/vhosts/myproject.test след като актуализираме кода в ~/repos/myproject.git с "git push test" от локалната машина.

Създаваме файл в~/repos/myproject.git/hooks/post-receive със съдържание

#!/bin/bash
 
while read oldrev newrev ref
do
branch=`echo $ref | cut -d/ -f3`
if [[ "master" == "$branch" ]]; then
git --work-tree=/var/www/vhosts/myproject.test/ checkout -f $branch
echo 'Changes pushed master, myproject.test.'
fi
 
if [[ "2.x" == "$branch" ]]; then
git --work-tree=/var/www/vhosts/myproject2.test/ checkout -f $branch
echo 'Changes pushed to 2.x myproject2.test.'
fi
done

Кода в този hook ни позволява също така да имаме няколко branch-а на този сървър, които актуализират различни сайтове - master за myproject.test и 2.x за myproject2.test. За тази цел е нобходимо да направим още един сайта в уеб сървъра - /var/www/vhosts/myproject2.test

Така, когато правим

push test master

ще обновим remote branch master, той ще обнови /var/www/vhosts/myproject.test
и с

push test 2.x

ще обновим remote branch 2.x, той ще обнови /var/www/vhosts/myproject2.test

С "push origin" актуализираме в github.

За да игнорираме постоянното въвеждане на парола на потребителя при push за отдалечения хост може да добавим нашата машина в отдалечения хост в ~/.ssh/authorized_keys

You should never add the file with the contents starting with -----BEGIN RSA PRIVATE KEY-----, that's your private key. You must put the public key in the ~/.ssh/authorized_keys file.
This public key has the .pub extension when generated using ssh-keygen and the contents of the public key begins with ssh-rsa AAAA3B. (The binary format is describes in the answers to this question).
The permissions of ~/.ssh on the server should be 700. ~/.ssh/authorized_keys on the server are supposed to be set to 600. The permissions of the key on the client-side should be 600.
http://askubuntu.com/questions/46424/adding-ssh-keys-to-authorized-keys

В тази статия са използвани още материали от
http://www.mindfuzz.net/?p=250 - за ssh актализиране но кода на отдалечен сървър и
http://www.ekynoxe.com/git-post-receive-for-multiple-remote-branches-and... - за модифициране на hook за поддържане на multiple branches.

Comments

По гореописания начин кода на сайта ще се обновява при всеки push. Това е проблем за settings.php. Той обикновено е описан в .gitignore, което е добре. Ако го качим с ftp (или го създадем директно в sites/default на сайта) при следващия push ще бъде изтрит. Един от начините да се реши това е да направим постоянна директория извън сайта, в която да поставим settings.php и да добавим в update-receive hook команда, която да направи символична връзка (symlink) до файла в sites/default. Така настройките в settings.php на test сървъра за сайта ще останат перманентни и автоматично ще се създава връзка към него при ъпдейт на кода с git.

Например:

file="/var/www/proud2bme.95/sites/default/settings.php"
if [ ! -f $file ]; then
ln -s /home/sve/drupal-settings/proud2bme/settings.php /var/www/proud2bme.95/sites/default/settings.php
fi
if [ -f $file ]; then
echo 'Symlink to settings.php - Done.'
fi

Така целия файл post-receive изглежда така:

#!/bin/bash

while read oldrev newrev ref
do
branch=`echo $ref | cut -d/ -f3`
if [[ "master" == "$branch" ]]; then
git --work-tree=/var/www/proud2bme.95/ checkout -f $branch
echo 'Changes pushed master.'
fi
 
if [[ "2.x" == "$branch" ]]; then
git --work-tree=/var/www/proud2bme.95/ checkout -f $branch
echo 'Changes pushed 2.x'
# create symlink to settings.php
file="/var/www/proud2bme.95/sites/default/settings.php"
if [ ! -f $file ]; then
ln -s /home/sve/drupal-settings/proud2bme/settings.php /var/www/proud2bme.95/sites/default/settings.php
fi
if [ -f $file ]; then
echo 'Symlink to settings.php - Done.'
fi
fi
done