Всем веб-разработчикам так или иначе нужен какой-то сервер для разработки своих веб-приложений. Кто-то использует «Денвер», кто-то OpenServer, более продвинутые берут виртуальный сервер (полу-демон, который запускает первый сценарий после запуска перед остановкой системы и реализует интерфейс демона.
В качестве гостевой операционной системы был выбран дистрибутив линукса CentOS 6.5, в качестве веб-сервера — Apache 2.2.15.
Сразу оговорюсь: описание установки и настройки LAMP-сервера описывать не буду ибо манов в интернетах полно.
Самый первый вариант скрипта выглядел примерно так:
#!/bin/sh
mount -t vboxsf $1 $2
Постепенно он разросся в следующий скрипт:
#!/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 f in $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$hn/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 f in $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 f in $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 argument one of:
mount : for mounting all 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
Что необходимо и как работает
- Необходимо установить на гостевеой машине веб-сервер (я выбрал apache).
- Для корректного монтирования расшаренных папок на гостевой ОС необходимо установить Guest Additions.
- Папку, которую мы монтируем следует назвать коротко, но уникально — это название будет поддоменом домена нашего сервера.
- В корень расшариваемой папки необходимо положить обязательно шаблон конфига виртуального хоста для веб-сервера.
Приблизительный конфиг виртуального хоста для веб-сервера
<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%> — маска, которая заменяется на домен для веб-приложения, файлы логов и папки для профилирования и трейсов (если необходимо). Все остальное по вкусу в зависимости от того, что необходимо в приложении.
-
Папки необходимо расшаривать с автомаунтом и желательно с правом на запись в нее — мы же можем что-то и заливать через это наше приложение и потому файлы должны сохраняться. А кто-то может что-то и кеширует в файлы. Право на запись не помешает. Автомаунт важен — скрипт выбирает нужные папки по списку уже подмонтированных папок в /media/sf_* — именно поэтому папки должни монтироваться с автомаунтом. Должно выглядеть приблизительно так, как на скриншоте.
- На гостевой машине должен быть отключен SELinux. С включенным SELinux веб-сервер не видит, подмаунченых в /var/www/html/, папок — они маунтятся в контексте vbox, а не httpd. Я пока не нашел как это подправить и поэтому подпер костылем — отключил SELinux.
- Хостнейм у гостевой машины должен иметь вид домена. У меня это natty.nat и в итоге все веб-приложения, которые я маунчу в эту гостевую машину, будут иметь такой вид: [имя папки, которую расшариваем].[hostname]. например test.natty.nat. Лично мне удобно было вешать на такие домены.
- Необходимо создать папочку /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
#!/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-сервер и перед тем, как произойдет демонтирование, сливаю базу обратно в дамп. Таким образом, мы имеем актуальный дамп базы после того, как выключим машину и имеем актуальную базу после включения машины.
Вот эти скрипты:
#!/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, который используется в нашем монтируемом разрабатываемом веб-приложении.
Что делает этот скрипт:
- Создает пользователя;
- Создает БД;
- Заливает содержимое нашего дампа в эту базу<./li>
, которое позволяет включать/отключаться остановку на брейкпоинтах, профилирование и трейс.
Я все создавал в сети 192.168.191.0/24 и потом, мои IP из этой подсети. Если у вас другая подсеть — изменяйтесь как вам удобно.
Автор: