[Из песочницы] Лень — двигатель прогресса или мой вариант создания окружения для веб-разработки на основе VirtualBox

2633fb78ba79451e86eb32bd8ff44287.jpgВсем веб-разработчикам так или иначе нужен какой-то сервер для разработки своих веб-приложений. Кто-то использует «Денвер», кто-то OpenServer, более продвинутые берут виртуальный сервер (VPS), а еще более продвинутые используют Vagrant, а кто-то просто ленивый. Под катом я расскажу, как разворачиваю веб-приложение для разработки с помощью VirtualBox, баша и кой-каких костылей. Для тех, кто ленив и не хочет смотреть под кат: описан один баш-сценарий, который монтирует расшареные папки в гостевую ОС и полу-демон, который запускает первый сценарий после запуска перед остановкой системы и реализует интерфейс демона.В качестве гостевой операционной системы был выбран дистрибутив линукса 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 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. Папку, которую мы монтируем следует назвать коротко, но уникально — это название будет поддоменом домена нашего сервера. В корень расшариваемой папки необходимо положить обязательно шаблон конфига виртуального хоста для веб-сервера.Приблизительный конфиг виртуального хоста для веб-сервера DocumentRoot /var/www/html/<%domain%> ServerName <%domain%> ServerAlias www.<%domain%> DirectoryIndex index.php

> AllowOverride All php_admin_value open_basedir /var/www/html/<%domain%>:/tmp:/usr/share:/var/lib

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%> Сам конфиг может изменяться, но основные моменты нужно сохранить: <%domain%> — маска, которая заменяется на домен для веб-приложения, файлы логов и папки для профилирования и трейсов (если необходимо). Все остальное по вкусу в зависимости от того, что необходимо в приложении. 95140c0c72a8477faeaba5c2191e5f0c.pngПапки необходимо расшаривать с автомаунтом и желательно с правом на запись в нее — мы же можем что-то и заливать через это наше приложение и потому файлы должны сохраняться. А кто-то может что-то и кеширует в файлы. Право на запись не помешает. Автомаунт важен — скрипт выбирает нужные папки по списку уже подмонтированных папок в /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Скрипт второй — демон — /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 Если все хорошо, нам должно показать, на каких уровнях будет запускаться наш скрипт.

b164a7d9ac5f4c64a90bc81610468567.png

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

# 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, который используется в нашем монтируемом разрабатываемом веб-приложении.

Что делает этот скрипт:

Создает пользователя; Создает БД; Заливает содержимое нашего дампа в эту базу<./li>, которое позволяет включать/отключаться остановку на брейкпоинтах, профилирование и трейс.Я все создавал в сети 192.168.191.0/24 и потом, мои IP из этой подсети. Если у вас другая подсеть — изменяйтесь как вам удобно.

© Habrahabr.ru