Мой опыт настройки окружения для Web-разработки

от автора

Речь пойдет не о настройке денвера и не о том, как поставить LAMP-стек. Я решил рассказать о том, какое мы в своей команде используем окружение для разработки. Мы разрабатываем Web-сервисы и ERP-системы, но всё это, в сущности, ничто иное, как сайты. Просто сложные внутри и порой не такие красивые снаружи.

Сразу хочу сказать, что я не претендую на описание идеального окружения для 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 следующие ошибки:
[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!

ссылка на оригинал статьи https://habrahabr.ru/post/282884/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *