Лінь - двигун прогресу чи мій варіант створення оточення для веб-розробки на основі VirtualBox



Всім веб-розробникам так чи інакше потрібен якийсь сервер для розробки своїх веб-додатків. Хтось використовує «Денвер», хтось OpenServer, більш просунуті беруть віртуальний сервер (VPS), а ще більш просунуті використовують Vagrant, а хтось просто ледачий. Під катом я розповім, як розгортаю веб-додаток для розробки за допомогою VirtualBox, баша і кой-яких милиць. Для тих, хто лінивий і не хоче дивитися під кат: описаний один баш-сценарій, який монтує расшареные папки в гостьову ОС і підлозі-демон, який запускає перший сценарій після запуску перед зупинкою системи і реалізує інтерфейс демона.

В якості гостьової операційної системи був вибраний дистрибутив linux CentOS 6.5, в якості веб-сервера Apache 2.2.15.

Відразу обмовлюся: опис установки і налаштування LAMP-сервера описувати не буду бо манів в інтернетах повно.

Найперший варіант скрипта виглядав приблизно так:

#!/bin/sh
mount-t vboxsf $1 $2


Поступово він розрісся в наступний скрипт:
Скрипт перший — робоча конячка — /root/scripts/vbox-sf.sh
#!/bin/sh

# Author: Dmitry Vapelnik
# Email: dvapelnik@gmail.com

# Місцезнаходження лог-файлу
logfile='/var/log/vbox-sf.log'
# Місце, куди ми будемо маунтить папки
mountPrefix='/var/www/html/';
# Хостнейм-суфікс
hn='."hostname`
# Шукаємо всі папки, які були подмаунчены VirtualBox
sharedFolders=`df | egrep "\/media\/sf_\$2[^ ]*" -o | sed-e 's/\/media\/sf_//"
#================ LOG==========================================================#
function log {
echo [`date +"%F %T"`] $1 $2 >> $logfile
}
#================ MOUNTING=====================================================#
function mountFn {
echo "Mounting....";
for in f $sharedFolders; do
mountPath=$mountPrefix$f$hn
if cat /proc/mounts | grep vbox | grep $mountPath &> /dev/null; then
echo Already mounted. Continue..;
else
rm-rf $mountPath 2> /dev/null;
mkdir-p $mountPath;
chown apache:apache $mountPath;
if mount-t vboxsf $f $mountPath-o umask=0022,uid=apache,gid=apache; then
echo Mounted $f
log mounted $mountPath
# Папки для збереження результуючих файлів і профилиования 
# трейсов для XDebug
mkdir-p /var/www/html/$f$hn/xd_profile_$f$hn
mkdir-p /var/www/html/$f$hn/xd_trace_$f$hn
if [ -f $mountPath'/httpd.conf' ]; then
# Формування конфига httpd заздалегідь підготовленого шаблону
cat $mountPath'/httpd.conf' | sed-e "s/<%domain%>/$f$n/g" > /etc/httpd/conf/sf/$f$hn.conf
if [ -f $mountPath'/aftermount.sh' ]; then
# Запуск заздалегідь підготовленого сценарію, який буде
# запускатися відразу після монтування папки
bash $mountPath'/aftermount.sh' $mountPath;
fi
fi
fi
fi
done;
# Перезапускаємо веб-сервер
service httpd restart
}
#================ UNMOUNTING===================================================#
function umountFn {
echo "Unmounting..."
# Зупиняємо веб-сервер
service httpd stop
for in f $sharedFolders; do
mountPath=$mountPrefix$f$hn
# Видаляємо журналів веб-сервера
find $mountPath-type f-name httpd_"$f""$hn"_*.log-exec rm-f {} \;
# Видаляємо папку профілювання і трейсов
rm-rf $mountPath/xd_profile_"$f""$hn"
rm-rf $mountPath/xd_trace_"$f""$hn"
# Виконуємо заздалегідь підготовлений стенарий, який повинен
# бути виконаним перед демонтированием папки
if [ -f $mountPath'/beforeumount.sh' ]; then
bash $mountPath'/beforeumount.sh' $mountPath;
fi
# Демонтуємо папку
umount $mountPath
# Підчищаємо за собою
if [[ $? -eq 0 ]]; then
rm-rf $mountPath 2> /dev/null
rm-f /etc/httpd/conf/sf/$f$hn.conf 2> /dev/null
echo "Unmounted and removed $f"
log umounted $mountPath
else
echo "Not unmounted"
fi
done;
# Запускаємо веб-сервер
service httpd start
}
#================ STATUS=======================================================#
function statusFn {
com=0
for in f $sharedFolders; do
mountPath=$mountPrefix$f$hn
if df | grep $mountPath &> /dev/null; then
com=`expr $com + 1`;
if [ $com-eq 1 ]; then
echo List of mounted resources:
fi
df | grep $mountPath | egrep-o '\/.+$'
fi
done
if [ $com-eq 0 ]; then
echo No shared storage mounted
fi
}
#===============================================================================#
if [ "$1" == "mount" ]; then
mountFn;
exit 0
elif [ "$1" == "umount" ]; then
umountFn;
exit 0
elif [ "$1" == "status" ]; then
statusFn;
exit 0
else
cat << EOF
No arguments supplied
-----------------------------------------------------------------------------
Usage:
-----------------------------------------------------------------------------
Using with single one argument of:
mount : all for mounting shared folders under /var/www/html directory
umount : for unmounting all shared folders under /var/www/html directory
status : for checking mount status
-----------------------------------------------------------------------------
Using with two argument for mounting or unmounting single folder
Example:
vbox-sf mount foo : will mount shared folder /media/sf_foo into /var/www/html/foo.domain.com
vbox-sf umount foo : will umount shared folder /media/sf_foo from /var/www/html/foo.domain.com
EOF
exit 1
fi

exit 0


Що необхідно і як працює

  1. Необхідно встановити на гостевеой машині веб-сервер (я вибрав apache).
  2. Для коректного монтування розшарених папок на гостьової ОС необхідно встановити Guest Additions.
  3. Папку, яку ми монтуємо слід назвати коротко, але унікально — це назва буде поддоменом домену нашого сервера.
  4. корінь расшариваемой папки необхідно покласти обов'язково шаблон конфига віртуального хоста для веб-сервера.
    Приблизний конфіг віртуального хоста для веб-сервера
    <VirtualHost *:80>
    DocumentRoot /var/www/html/<%domain%>
    ServerName <%domain%>
    ServerAlias www.<%domain%>
    DirectoryIndex index.php
    
    <Directory /var/www/html/<%domain%>>
    AllowOverride All
    php_admin_value open_basedir /var/www/html/<%domain%>:/tmp:/usr/share:/var/lib
    </Directory>
    
    CustomLog /var/www/html/<%domain%>/httpd_<%domain%>_access.log combined
    ErrorLog /var/www/html/<%domain%>/httpd_<%domain%>_error.log
    
    php_admin_value xdebug.profiler_output_dir /var/www/html/<%domain%>/xd_profile_<%domain%>
    php_admin_value xdebug.trace_output_dir /var/www/html/<%domain%>/xd_trace_<%domain%>
    </VirtualHost>

    Сам конфіг може змінюватися, але основні моменти потрібно зберегти: <%domain%> — маска, яка замінюється на домен для веб-додатки, лог-файли і папки для профілювання і трейсов (якщо необхідно). Все інше за смаком залежно від того, що необхідно в додатку.


  5. Папки необхідно розшарювати з автомаунтом і бажано з правом на запис в неї — ми ж можемо щось і заливати через це наш додаток і тому файли повинні зберігатися. А хтось може щось і кешує файли. Право на запис не завадить. Автомаунт важливий — скрипт вибирає потрібні папки за списком вже підмонтовані папок /media/sf_* — саме тому папки повинні монтуватися з автомаунтом. Має виглядати приблизно так, як на скріншоті.
  6. На гостьовий машині повинен бути відключений SELinux. З включеним SELinux веб-сервер не бачить, подмаунченых /var/www/html/, папок — вони маунтятся в контексті vbox, а не httpd. Я поки не знайшов як це підправити і тому підпер милицею — відключив SELinux.
  7. Хостнейм у гостьовій машини повинен мати вигляд домену. У мене це natty.nat і в підсумку всі веб-додатки, які я маунчу в цю гостьову машину, будуть мати такий вигляд: [ім'я папки, яку расшариваем].[hostname]. наприклад, test.natty.nat. Особисто мені зручно було вішати на такі домени.
  8. Необхідно створити папку /etc/httpd/conf/sf,
    # mkdir-p /etc/httpd/conf/sf
    в яку будуть складуватися конфіги віртуальних хостів веб-сервера. При цьому в кінці файлу /etc/httpd/conf/httpd.conf необхідно инклудить всі конфіги, які ми будемо складувати у вищезгаданій папці:
    include "conf/sf/*.conf"


Якщо все добре, то тепер ми можемо розшарити папку з нашим проектом на нашу віртуальну машину, запустити її і, виконавши наступну команду, отримати готове місце для розробки:

# /path/to/vbox-sf.sh mount


Так ми подмаунтим всі расшаренные папки. Якщо другим аргументом вказати ім'я нашої папки, то підмонтує або демонтує тільки її:

# /path/to/vbox-sf.sh mount test

# /path/to/vbox-sf.sh umount test


Демон

Але тепер було б непогано ця справа якось автоматизувати. Я вибрав шлях демона і я вважаю, що він буде більш правильним, ніж руцями змінювати /etc/rc.# файли. Був написаний наступний скрипт для /etc/init.d
Скрипт другий — демон — /etc/init.d/vboxsf
#!/bin/bash
#
# Author: Dmitry Vapelnik
# Email: dvapelnik@gmail.com

### BEGIN INIT INFO
# Required-Start: httpd mysqld vboxadd-service vboxadd
# Required-Stop: httpd mysqld vboxadd-service vboxadd
# Default-Start: 3
# Default-Stop: 0 6
# Short Description: Mounting VirtualBox shared folders
# Description: This file should be used to mount and umount 
# VirtualBox shared folders
### END INIT INFO

# Get function from functions library
. /etc/init.d/functions

prog="VBoxSF"
lockfile='/var/lock/subsys/vboxsf'

# Start the service vbox-sf
start() {
# initlog-c "echo-n Starting $prog server: "
/root/bin/vbox-sf mount &> /dev/null && touch $lockfile
success $"$prog: mounted"
echo
}

# Restart the service vbox-sf
stop() {
# initlog-c "echo-n Umounting $prog: "
/root/bin/vbox-sf umount &> /dev/null && rm-f $lockfile
success $"$prog: umounted"
echo
}

status() {
/root/bin/vbox-sf status
}

### main logic ###
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart|reload|condrestart)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
exit 1
esac

exit 0


Цей скрипт необхідно покласти в директорію /etc/init.d і назвати файл vboxsf. Насправді тут назва файлу некритично. Просто коли ми будемо додавати нового демона з допомогою chkconfig, то нам необхідно буде вказати ім'я цього файлика. Далі я буду використовувати саме vboxsf.

Отже, ми додали файл. Тепер нам необхідно облінкований наш скрипт /root/bin:

# mkdir-p /root/bin
# ln-s /root/scripts/vbox-sf.sh /root/bin/vbox-sf


Додаємо в chkconfig:

# chkconfig --add vboxsf


Перевіряємо чи все додалося:

# chkconfig | grep vboxsf


Якщо все добре, нам треба показати, на яких рівнях буде запускатися наш скрипт.



В результаті тепер ми можемо просто використовувати наступні команди:

# service vboxsf start
# service vboxsf stop
# service vboxsf restart
# service vboxsf status


Якщо ні, то дивимося що ми не так зробили. В принципі, на цьому моменті все повинно працювати: монтуватися при запуску і демонтуватися перед вимиканням.

А тепер вкусняшки

Пам'ятайте скрипти, які виконуються після монтування і перед демонтированием папки? Так от, для більш зручної роботи я розгортаю базу з дампа в MySQL сервер і перед тим, як відбудеться демонтування, зливаю базу назад у дамп. Таким чином, ми маємо актуальний дамп бази після того, як вимкнемо машину і маємо актуальну базу після включення машини.

Ось ці скрипти:
Скрипт третій — відновлення БД з дампа aftermount.sh
#!/bin/sh

# Author: Dmitry Vapelnik
# Email: dvapelnik@gmail.com

if [ $# -eq 0 ]; then
echo 'No arguments supplied';
echo 'Exit';
exit 0;
fi
######################################################
dbAdminUser='ourDbAdminLogin'
dbAdminPass='ourDbAdminPassword'

dbName='ourDbName'
dbUser='ourDbUser'
dbPass='ourDbPassword'
dbHost='localhost'
dbDump=$1'/db.sql'
######################################################

queryCreateUser="CREATE USER '$dbUser'@'$dbHost' IDENTIFIED BY '$dbPass';
CREATE DATABASE IF NOT EXISTS \`$dbName\`;
GRANT ALL PRIVILEGES ON \`$dbName\`.* TO '$dbUser'@'$dbHost';
FLUSH PRIVILEGES;"

echo Creating new user...
if mysql-u$dbAdminUser-p$dbAdminPass-e "$queryCreateUser"; then
echo User added
echo Using MySQL dump
if mysql-u$dbAdminUser-p$dbAdminPass $dbName < $dbDump; then
echo MySQL dump loaded into $dbName
else
echo MySQL dump not loaded
fi
else
echo Error: user not added exit
fi


Важливо! Achtung! dbAdminUser і dbAdminPass — це логін і пароль адміністратора БД, який може створити/видалити користувача, створити БД і залити в неї дамп.
ourDbName, ourDbUser і ourDbPassword — ім'я БД та логін та пароль користувача MySQL, який використовується в нашому монтується розробляється веб-додатку.

Що робить цей скрипт:
  1. Створює користувача;
  2. Створює БД;
  3. Заливає вміст нашого дампа в цю базу<./li>
  4. , яке дозволяє включати/відключати зупинку на брейкпоинтах, профілювання і трейс.Я все створював в мережі 192.168.191.0/24 і потім, мої IP з цієї підмережі. Якщо у вас інша підмережа — змінюйтесь як вам зручно.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.