Речь пойдет не о настройке денвера и не о том, как поставить LAMP-стек. Я решил рассказать о том, какое мы в своей команде используем окружение для разработки. Мы разрабатываем Web-сервисы и ERP-системы, но всё это, в сущности, ничто иное, как сайты. Просто сложные внутри и порой не такие красивые снаружи.
Сразу хочу сказать, что я не претендую на описание идеального окружения для Web-разработки. С удовольствием послушаю критику, приглашаю всех поделиться своими подходами в комментариях. В общем, поехали.
Основной недостаток денвера состоит в том, что проекты в production не работают на денвере. А значит мы не можем гарантировать, что тщательно отлаженные на компьютере разработчика скрипты не начнут «чудить», когда попадут в production. В production проекты обычно работают в Linux (в нашем случае это CentOS или Amazon Linux). Кроме того, работая на денвере, мы не сможем использовать различные утилиты и средства, которые нам нужны в проекте (например, catdoc, поиск sphinx и многое другое).
Разрабатывать прямо в Linux, конечно круто, но правда жизни такова, что большинство разработчиков пользуются Windows в качестве основной OC на компьютере. Поэтому дальше я опишу наш рецепт, как работая в Windows, разрабатывать сайты в Linux.
Мы используем CentOS 7, но думаю, без существенных изменений все будет работать и на других дистрибутивах.
Ок. Первое, что нужно сделать — это поставить на компьютер гипервизор (VmWare Workstation, Oracle VirtualBox или может какой-то другой по вкусу). Мы используем VmWare. После этого создаем виртуальную машину и разворачиваем в ней тот образ Linux, на котором будут работать наши проекты в production. Устанавливаем Web-сервер, СУБД, в общем все, что нам нужно для запуска проекта. Кстати, если есть образ виртуалки для production, то еще лучше — можно его и взять за основу.
Виртуалку удобнее всего подключить через bridged-сетевой интерфейс. Так она будет полноценным участником сети и можно будет легко показывать результаты коллегам или заказчикам, если пробросить порт из внешнего мира.
Первый вопрос, который у нас встал на этом этапе. Нам теперь что, скрипты проекта через putty редактировать?! И очевидное решение, которое мы нашли, было удивительно простым. В Windows-машине нужно завести отдельную папку, в которой будут лежать все наши проекты. Эту папку нужно расшарить для доступа по сети и примонтировать в корневую директорию, с которой работает Web-сервер.
Чтобы все это работало надежнее, я написал скриптик cifs_mount.sh, буквально из 2 строчек кода, который поставил в виртуалке на запуск раз в 5 минут.
Скрипт проверяет, не отвалилась ли шара (простите мой французский). И если отвалилась, обратно ее монтирует.
Файл /root/file_server
Файл /root/.cifscreds
В целом, это решение работает надежно, как утюг.
Не стоит пугаться этих нюансов! Они накопились у нас почти за 10 лет разработки с использованием этого подхода.
Итак, что мы имеем. Теперь мы можем работать со скриптами в привычном нам редакторе кода в Windows. А результаты смотреть в браузере, заходя на нашу виртуальную машину. Идем дальше.
А что если у нас больше 1 проекта. Каждый раз поднимать новую виртуалку!? Нам на помощь приходят виртуальные хосты. Придется опять написать небольшой скриптик flush_vhosts.sh (сугубо для удобства работы).
Вот что он делает:
1. Очищает конфигурацию виртуальных хостов.
2. Очищает /etc/hosts.
3. Дальше он проходится по всем подкаталогам нашей примонтированной папки и создает для каждого каталога новый виртуальный хост Apache. Если в названии каталога находится страшное слово bitrix, то он добавляет в конфиг виртуального хоста несколько специфических настроек для этой замечательной CMS. Добавляет в /etc/hosts новые записи для созданных виртуальных хостов.
4. Перезапускает Apache.
Мы использует в адресах проектов для разработки условный домен первого уровня wde (web developer environment). Можно использовать local или кому что нравится. У нас разрабатываемые проекты доступны по адресам project1.wde, project2.wde и так далее. При этом виртуальные хосты создаются с директивой ServerAlias *.your-folder-name.wde, то есть все поддомены будут также обрабатываться созданным для папки виртуальным хостом.
Таким образом, если нам нужно начать работу над новым проектом, достаточно создать новую папку в общей папке проектов. Выполнить скрипт flush_vhosts.sh. А в Windows прописать адрес для нового проекта в файле C:\Windows\System32\drivers\etc\host.
Звездочки файл hosts к великому сожалению, не поддерживает. Надо прописывать каждый адрес, с которым будем работать. Вместо 192.168.1.166 нужно указать ip, который вы присвоили виртуальной машине. После этого соответствующий проект будет открываться в браузере по адресам site1.wde или site2.wde и так далее.
Для удобства, если вы пользуетесь, phpMyAdmin, его можно настроить дефолтным хостом. Тогда при обращении по любому адресу, когда Apache не будет находить соответствующую папку проекта, он будет открывать phpMyAdmin. Главное не забыть прописать этот адрес (например, просто wde) в файле hosts в Windows.
Чтобы было совсем удобно. И не приходилось новым членам команды объяснять, как обновить конфигурацию виртуальных хостов, настроить сетевую папку и т.д. Я написал еще несколько скриптов для вывода и запуска частых действий через меню. В них нет ничего сверхестественного, прикладываю — может быть кому-то тоже пригодятся.
Собственно скрипт, выводящий меню. Его нужно прописать в файле .bash_profile домашней директории пользователя, под которым мы входим на виртуалку. Для виртуалки, на которой ведется разработка, я считаю можно входить под root, соответственно добавляем в файл /root/.bash_profile строчку ./menu.sh. Теперь сразу после входа в систему будет запускаться наше меню. При необходимости из него всего можно выйти, нажав Ctrl+C.
Дальше остается настроить любимую систему контроля версий. Можно пользоваться desktop-приложением для Windows, можно работать через командную строку в putty прямо на нашей виртуальной машине. Кому, как удобнее.
PS. Кстати, одно из величайших открытий для меня было, что можно поставить git или svn непосредственно на production сервере. Когда я в свое время это понял, это ощущение было сравнимо, наверное, с тем чувством, которое испытал Архимед, когда сел в ванную. Ведь больше не надо мучиться с синхронизацией файлов по ftp\sftp, достаточно ввести svn up или git pull origin master!
Сразу хочу сказать, что я не претендую на описание идеального окружения для Web-разработки. С удовольствием послушаю критику, приглашаю всех поделиться своими подходами в комментариях. В общем, поехали.
Подождите, а чем плох денвер?
Основной недостаток денвера состоит в том, что проекты в production не работают на денвере. А значит мы не можем гарантировать, что тщательно отлаженные на компьютере разработчика скрипты не начнут «чудить», когда попадут в production. В production проекты обычно работают в Linux (в нашем случае это CentOS или Amazon Linux). Кроме того, работая на денвере, мы не сможем использовать различные утилиты и средства, которые нам нужны в проекте (например, catdoc, поиск sphinx и многое другое).
Ок, но ведь не все готовы работать в Linux!
Разрабатывать прямо в Linux, конечно круто, но правда жизни такова, что большинство разработчиков пользуются Windows в качестве основной OC на компьютере. Поэтому дальше я опишу наш рецепт, как работая в Windows, разрабатывать сайты в Linux.
Мы используем CentOS 7, но думаю, без существенных изменений все будет работать и на других дистрибутивах.
Создаем образ виртуальной машины
Ок. Первое, что нужно сделать — это поставить на компьютер гипервизор (VmWare Workstation, Oracle VirtualBox или может какой-то другой по вкусу). Мы используем VmWare. После этого создаем виртуальную машину и разворачиваем в ней тот образ Linux, на котором будут работать наши проекты в production. Устанавливаем Web-сервер, СУБД, в общем все, что нам нужно для запуска проекта. Кстати, если есть образ виртуалки для production, то еще лучше — можно его и взять за основу.
Виртуалку удобнее всего подключить через bridged-сетевой интерфейс. Так она будет полноценным участником сети и можно будет легко показывать результаты коллегам или заказчикам, если пробросить порт из внешнего мира.
Сетевая папка
Первый вопрос, который у нас встал на этом этапе. Нам теперь что, скрипты проекта через putty редактировать?! И очевидное решение, которое мы нашли, было удивительно простым. В Windows-машине нужно завести отдельную папку, в которой будут лежать все наши проекты. Эту папку нужно расшарить для доступа по сети и примонтировать в корневую директорию, с которой работает Web-сервер.
Чтобы все это работало надежнее, я написал скриптик cifs_mount.sh, буквально из 2 строчек кода, который поставил в виртуалке на запуск раз в 5 минут.
#!/bin/sh
if ! mount -t cifs | grep -q `cat /root/file_server`
then mount -t cifs -o uid=apache,gid=apache,iocharset=utf8,noserverino,credentials=/root/.cifscreds `cat /root/file_server` /var/www
fi
Скрипт проверяет, не отвалилась ли шара (простите мой французский). И если отвалилась, обратно ее монтирует.
Файл /root/file_server
//192.168.0.2/Projects
Файл /root/.cifscreds
username=developvm
password=secretpass
В целом, это решение работает надежно, как утюг.
Но тем не менее есть один небольшой нюанс.
Иногда бывает, что при копировании больших файлов, вылетает ошибка cifs. Как правило, это связано с тем, что в Windows не хватает выделенной памяти для шары. Вылеты происходят из-за того, что Win7 настроена по умолчанию на экономию памяти для сетевых подключений, в частности, размер выделяемого для этих целей пула памяти ограничен, и если для обработки файла требуется больше, то Win7 шлет Linux фатальную ошибку интерфейса и CIFS падает.
Также бывает наблюдаются периодические проблемы с неполной загрузкой страниц (не подгружаются CSS или вообще ошибки при попытке Apache прочитать файл). Причем это возникает время от времени без какой-либо системы.
При этом в логе ошибок Apache следующие ошибки:
Чтобы ликвидировать все эти проблемы разом, нужно подредактировать реестр Win7, а именно:
1. У HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\LargeSystemCache установить значение 1
2. У HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters\size установить значение 3
После этого перезапустить LanmanServer. “net stop srv”/“net start srv”. На виртуалке перемонтировать шару.
Также бывает наблюдаются периодические проблемы с неполной загрузкой страниц (не подгружаются CSS или вообще ошибки при попытке Apache прочитать файл). Причем это возникает время от времени без какой-либо системы.
При этом в логе ошибок Apache следующие ошибки:
[Tue Oct 20 10:44:28.417589 2015] [core:crit] [pid 9632] (5)Input/output error: [client 192.168.1.5:60666] AH00529: /var/www/project/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable and that '/var/www/project/' is executable, referer: http://192.168.1.102/script.php
[Tue Oct 20 10:44:28.418762 2015] [core:error] [pid 9555] (5)Input/output error: [client 192.168.1.5:60670] AH00132: file permissions deny server access: /var/www/project/css/main/layout-main.css, referer: http://192.168.1.102/script.php
Чтобы ликвидировать все эти проблемы разом, нужно подредактировать реестр Win7, а именно:
1. У HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\LargeSystemCache установить значение 1
2. У HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters\size установить значение 3
После этого перезапустить LanmanServer. “net stop srv”/“net start srv”. На виртуалке перемонтировать шару.
И еще один нюанс касается опции noserverino
В свое время он породил этот мой вопрос на stackoverflow. Если кратко, эта опция нужна. Подробнее можно почитать по ссылке.
Не стоит пугаться этих нюансов! Они накопились у нас почти за 10 лет разработки с использованием этого подхода.
Итак, что мы имеем. Теперь мы можем работать со скриптами в привычном нам редакторе кода в Windows. А результаты смотреть в браузере, заходя на нашу виртуальную машину. Идем дальше.
Подпапки для проектов.
А что если у нас больше 1 проекта. Каждый раз поднимать новую виртуалку!? Нам на помощь приходят виртуальные хосты. Придется опять написать небольшой скриптик flush_vhosts.sh (сугубо для удобства работы).
#!/bin/sh
rm /etc/httpd/conf.d/vhosts/*
rm /etc/hosts
echo '127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4' >> /etc/hosts
echo '::1 localhost localhost.localdomain localhost6 localhost6.localdomain6' >> /etc/hosts
for D in `find /var/www -maxdepth 1 -mindepth 1 -type d -printf '%f\n'`
do
echo '<VirtualHost *:80>' >> /etc/httpd/conf.d/vhosts/$D.conf
echo "ServerName $D.wde" >> /etc/httpd/conf.d/vhosts/$D.conf
echo "ServerAlias *.$D.wde" >> /etc/httpd/conf.d/vhosts/$D.conf
echo "DocumentRoot /var/www/$D" >> /etc/httpd/conf.d/vhosts/$D.conf
if [[ $D == *"bitrix"* ]]
then
echo 'php_admin_value mbstring.func_overload 2' >> /etc/httpd/conf.d/vhosts/$D.conf
echo 'php_admin_value mbstring.internal_encoding UTF-8' >> /etc/httpd/conf.d/vhosts/$D.conf
echo 'php_admin_value max_input_vars 10001' >> /etc/httpd/conf.d/vhosts/$D.conf
echo 'php_admin_value pcre.recursion_limit 1000' >> /etc/httpd/conf.d/vhosts/$D.conf
fi
echo "</VirtualHost>" >> /etc/httpd/conf.d/vhosts/$D.conf
echo "127.0.0.1 $D.wde" >> /etc/hosts
done
systemctl restart httpd.service
Вот что он делает:
1. Очищает конфигурацию виртуальных хостов.
2. Очищает /etc/hosts.
3. Дальше он проходится по всем подкаталогам нашей примонтированной папки и создает для каждого каталога новый виртуальный хост Apache. Если в названии каталога находится страшное слово bitrix, то он добавляет в конфиг виртуального хоста несколько специфических настроек для этой замечательной CMS. Добавляет в /etc/hosts новые записи для созданных виртуальных хостов.
4. Перезапускает Apache.
Мы использует в адресах проектов для разработки условный домен первого уровня wde (web developer environment). Можно использовать local или кому что нравится. У нас разрабатываемые проекты доступны по адресам project1.wde, project2.wde и так далее. При этом виртуальные хосты создаются с директивой ServerAlias *.your-folder-name.wde, то есть все поддомены будут также обрабатываться созданным для папки виртуальным хостом.
Таким образом, если нам нужно начать работу над новым проектом, достаточно создать новую папку в общей папке проектов. Выполнить скрипт flush_vhosts.sh. А в Windows прописать адрес для нового проекта в файле C:\Windows\System32\drivers\etc\host.
192.168.1.166 wde
192.168.1.166 site1.wde
192.168.1.166 site2.wde
...и т.д.
Звездочки файл hosts к великому сожалению, не поддерживает. Надо прописывать каждый адрес, с которым будем работать. Вместо 192.168.1.166 нужно указать ip, который вы присвоили виртуальной машине. После этого соответствующий проект будет открываться в браузере по адресам site1.wde или site2.wde и так далее.
Для удобства, если вы пользуетесь, phpMyAdmin, его можно настроить дефолтным хостом. Тогда при обращении по любому адресу, когда Apache не будет находить соответствующую папку проекта, он будет открывать phpMyAdmin. Главное не забыть прописать этот адрес (например, просто wde) в файле hosts в Windows.
Организация загрузочного меню
Чтобы было совсем удобно. И не приходилось новым членам команды объяснять, как обновить конфигурацию виртуальных хостов, настроить сетевую папку и т.д. Я написал еще несколько скриптов для вывода и запуска частых действий через меню. В них нет ничего сверхестественного, прикладываю — может быть кому-то тоже пригодятся.
Собственно скрипт, выводящий меню. Его нужно прописать в файле .bash_profile домашней директории пользователя, под которым мы входим на виртуалку. Для виртуалки, на которой ведется разработка, я считаю можно входить под root, соответственно добавляем в файл /root/.bash_profile строчку ./menu.sh. Теперь сразу после входа в систему будет запускаться наше меню. При необходимости из него всего можно выйти, нажав Ctrl+C.
menu.sh
#!/bin/sh
SCRIPT_DIR=`dirname $0`
source $SCRIPT_DIR/utils.sh
#menu actions
act_net () {
nmtui ;
}
act_folder () {
$SCRIPT_DIR/mount_cfg.sh ;
}
act_flushvhosts () {
$SCRIPT_DIR/flush_vhosts.sh ;
}
act_reboot () {
read -p "System is going to reboot, are u sure? (y/N) " key ;
if [ $key = "y" ]; then
systemctl reboot ;
exit
fi
key=
}
act_shutdown () {
read -p "System is going down, are u sure? (y/N) " key ;
if [ $key = "y" ]; then
systemctl halt ;
exit
fi
key=
}
themenu () {
clear
server_uptime
mnt_detect
echo "===================================================================="
echo "======================= WELCOME to CENTOS WDE!!! ==================="
echo "===================================================================="
echo "======================== wish you happy coding ====================="
echo "===================================================================="
echo -e "System time: "$curtime"\tUptime:"$uptime;
echo ;
echo -e "Mounted folder: "$MNT;
echo ;
echo "=========================== network info ==========================="
echo "`ifconfig -a`"
echo ;
echo `grep nameserver /etc/resolv.conf`
echo ;
echo "`route -n`"
echo ;
echo "====================== current vhosts configs ======================"
echo "`ls -1 /etc/httpd/conf.d/vhosts/`"
echo ;
echo "===================================================================="
echo "========================= Available actions: ======================="
echo -e "\t\tConfigure ${FG_UN}net${NORM}"
echo -e "\t\tConfigure mounted ${FG_UN}folder${NORM}";
echo -e "\t\t${FG_UN}Flush${NORM} virtual hosts";
echo -e "\t\t${FG_UN}Reboot${NORM}";
echo -e "\t\t${FG_UN}Shutdown${NORM}";
echo
echo "Type underlined chars(lowercase) and press ENTER or just ENTER to refresh";
echo "Type Ctrl+C to exit to shell";
echo "====================================================================";
}
while true
do
themenu
read answer
case $answer in
"net") act_net;;
"folder") act_folder;;
"flush") act_flushvhosts;;
"reboot") act_reboot;;
"shutdown") act_shutdown;;
*) echo 'No action found! Refreshing...'; sleep 1; continue;;
esac
done
utils.sh - содержит функции и переменные, используемые в других скриптах
#!/bin/sh
set -o pipefail
mnt_dir="/var/www"
if [ "$interactive" != 'no' ]; then
#cursor movements
CU_RIGHT=$(tput hpa $(tput cols))$(tput cub 7)
#background colors
BG_BLACK=$(tput setab 1)
BG_RED=$(tput setab 1)
BG_GREEN=$(tput setab 2)
BG_YELLOW=$(tput setab 3)
BG_BLUE=$(tput setab 4)
BG_PURPLE=$(tput setab 5)
BG_CYAN=$(tput setab 6)
BG_WHITE=$(tput setab 7)
#foreground colors
FG_RED=$(tput setaf 1)
FG_GREEN=$(tput setaf 2)
FG_YELLOW=$(tput setaf 3)
FG_BLUE=$(tput setaf 4)
FG_PURPLE=$(tput setaf 5)
FG_CYAN=$(tput setaf 6)
FG_WHITE=$(tput setaf 7)
#text-decoration
FG_BOLD=$(tput bold)
FG_HB=$(tput dim)
FG_UN=$(tput smul)
FG_REVERSE=$(tput rev)
#back to defaults
NORM=$(tput sgr0)
fi
#functions to display progress
dots () {
if [ "$interactive" != 'no' ]; then
while true; do
echo -n "."; sleep 0.5
done
fi
}
estart(){
if [ "$interactive" != 'no' ]; then
echo -n "$1"
dots &
dots_pid=$!
fi
}
efinish(){
estatus=$?
if [ "$interactive" != 'no' ]; then
if [ "$estatus" -eq 0 ];then
echo "[ ${FG_GREEN}OK${NORM} ]"
else
echo "[ ${FG_RED}FAIL${NORM} ]"
fi
kill $dots_pid
wait $dots_pid 2>/dev/null
fi
}
#detect server uptime
server_uptime () {
uptime=$(</proc/uptime)
uptime=${uptime%%.*}
s=$(( uptime%60 ))
m=$(( uptime/60%60 ))
h=$(( uptime/60/60%24 ))
d=$(( uptime/60/60/24 ))
uptime=$d'd '$h'h '$m'm '$s's '
curtime=$(date +'%Y-%m-%d %H:%M:%S')
}
#detect cifs mount
mnt_detect () {
MNT=$(mount -l | grep $mnt_dir)
if [ ! -z "$MNT" ]; then
MNT=$FG_GREEN$MNT$NORM
else
MNT=$FG_RED"error(not found)"$NORM
fi
}
mount_cfg.sh - настройка параметров сетевой папки
#!/bin/sh
SCRIPT_DIR=`dirname $0`
source $SCRIPT_DIR/utils.sh
clear
echo "========================================="
echo " Mounted folder configuration"
echo " (/var/www)"
echo "========================================="
echo
old_address=$(cat /root/file_server)
old_username=$(grep 'username=' /root/.cifscreds | awk -F '=' '{ print $2 }')
old_password=$(grep 'password=' /root/.cifscreds | awk -F '=' '{ print $2 }')
echo "Type new value and press ENTER or just press ENTER to leave current value.";
echo ;
read -p "Address of fileserver, type like //ip/folder (current value $FG_YELLOW$old_address$NORM): " address ;
read -p "Username (current value $FG_YELLOW$old_username$NORM): " username ;
read -p "Password (current value $FG_YELLOW$old_password$NORM): " password ;
if [ -z "$address" ]; then
address=$old_address; fi
if [ -z "$username" ]; then
username=$old_username; fi
if [ -z "$password" ]; then
password=$old_password; fi
echo "======================================="
echo " New parameters"
echo "======================================="
echo -e "IP address of fileserver: "$address
echo -e "Username: "$username
echo -e "Password: "$password
echo "======================================="
echo
read -p "Save changes? (y/N) " key ;
if [ $key == "Y" -o $key == "y" ]; then
echo "username=$username
password=$password" > /root/.cifscreds
echo "$address" > /root/file_server
estart "Unmounting..."
umount /var/www
efinish
estart "Mounting..."
/root/cifs_mount.sh
efinish
echo ;
read -p "Done. Press any key" key ;
else
echo ;
read -p "Nothing was changed. Press any key" key ;
fi
Система контроля версий
Дальше остается настроить любимую систему контроля версий. Можно пользоваться desktop-приложением для Windows, можно работать через командную строку в putty прямо на нашей виртуальной машине. Кому, как удобнее.
PS. Кстати, одно из величайших открытий для меня было, что можно поставить git или svn непосредственно на production сервере. Когда я в свое время это понял, это ощущение было сравнимо, наверное, с тем чувством, которое испытал Архимед, когда сел в ванную. Ведь больше не надо мучиться с синхронизацией файлов по ftp\sftp, достаточно ввести svn up или git pull origin master!