Настройка среды разработки: кружок рукоделия (Часть 1)

    Настройка среды разработки
    Привет, дорогой читатель!
    Сегодня я хочу поделиться своим опытом настройки персонального окружения для работы с различными PHP-based проектами. В данной статье описывается опыт ручной настройки окружения.

    Данная статья написана для меня любимого с целью показать то, как можно упростить или усложнить себе жизнь. Я не хочу призывать к действию, а только делюсь тем, с чем я столкнулся и что сделал.

    Автоматизацию процесса развертывания среды я напишу в одной из следующих статей.

    Статья будет очень длинной с уклоном в техническую сторону. Прошу под «кат».

    Предыстория


    Прежде чем начать, хочу поделиться небольшой историей о том, как все начиналось.

    Долгое время, процесс разработки велся в основном на одном проекте, с упором на долгосрочные перспективы (работы было много: на 1 год вперед). И так было от компании к компании. Так что мне не составляло особого труда добавить пару «конфигов» и перезагрузить сервисы на локальной машине, чтобы добавить новый проект. При смене компании я просто настраивал все с нуля подстраиваясь под проект.

    В конце 2016 года мне пришлось перейти с одного проекта на другой в связи с чередой очень неприятных событий. Перейдя на новый проект столкнулся с тем, что архитектура проекта была построена так, что нужно одновременно поддерживать минимум 5 web-сервисов, работающих в связке. Так же мне все еще приходится время от времени поддерживать предыдущие проекты. Да и, не забывать об R&D проектах, Open Source проектах, “халтурке”, семье и детях.

    Такое стечение обстоятельств повлияло на дальнейшую историю моей среды разработки и все что с этим связано.

    Цель: гибкая среда разработки для PHP-based проектов


    Мне нужно получить рабочее окружение, позволяющее вести разработку, отладку и исследования во множественных PHP-based проектах с привязкой к инфраструктуре компании.
    Примечание: дальнейшее описание относится к двум проектам, которые сейчас находятся в моей зоне ответственности: Warface Hub — то, что от него осталось, и CryEngine Hub — результат молниеносной реализации, “удачной” архитектуры и “правильного” планирования.

    Таким образом я получил следующее

    • Windows 10 — Host с VMWare или VitrualBox
    • Ubuntu — Guest c:
      • Samba — для работы с файлами проектов
      • Bind9 — локальный DNS сервер
      • Nginx, PHP FPM, MySQL и все остальное

    • Другие виртуальные машины

    Ресурсы


    В крупных компаниях очень часто используют решения от компании Microsoft для обеспечения работы внутренней связи между сотрудниками (Outlook, Lync, AD) и еще кучи «самописных» приложений. Так как лень мне не позволяет искать и настраивать клиенты под Linux или использовать Wine, то я успешно начал использовать “гибрид” двух OS и виртуализацию:

    • Windows 10 (Host OS)
    • Ubuntu 16.04 (Guest OS — VM)
    • SSD — максимально быстрый. При данной реализации очень важно иметь быстрый диск.
    • 16Gb ram — Чем больше, тем лучше. Мне приходится выделять до 12Gb для всех гостевых OS, так как приходится решать cross-browser проблемы, которые на эмуляторах не воспроизводятся.

    Установка сервисов, приложений и компонентов.


    На этом этапе устанавливаем все (Guest OS), что может нам понадобится для того чтобы поднять простой стек из Nginx, PHP и MySQL, а также все остальное, что может пригодится в проектах (NPM, Yarn, Composer). Не забываем про нашу среду разработки и добавляем туда Samba и Bind9.

    Для меня это выглядит так
    $ sudo add-apt-repository ppa:ondrej/php
    $ sudo apt-get install php5.6 php7.0 php7.1 php7.1-fpm
    $ sudo apt-get install php-bcmath php-curl php-dev php-fpm php-gd php-intl php-json php-mbstring php-mcrypt php-mysql php-readline php-soap php-sqlite3 php-tidy php-xml php-zip php-codecoverage php-codesniffer php-common php-geoip php-igbinary php-imagick php-memcache php-memcached php-redis php-ssh2 php-xdebug php-xhrpof
    $ sudo apt-get install php5.6-bcmath php5.6-curl php5.6-dev php5.6-fpm php5.6-gd php5.6-intl php5.6-json php5.6-mbstring php5.6-mcrypt php5.6-mysql php5.6-opcache php5.6-readline php5.6-soap php5.6-sqlite3 php5.6-tidy php5.6-xml php5.6-zip
    $ sudo apt-get install php7.0-bcmath php7.0-curl php7.0-dev php7.0-fpm php7.0-gd php7.0-intl php7.0-json php7.0-mbstring php7.0-mcrypt php7.0-mysql php7.0-opcache php7.0-readline php7.0-soap php7.0-sqlite3 php7.0-tidy php7.0-xml php7.0-zip
    $ sudo apt-get install php7.1-opcache
     
    $ sudo apt-get install memcached redis-server redis-tools nginx mysql-server-5.7 mysql-client-5.7 composer npm curl nodejs nodejs-legacy ruby-full
     
    $ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
    $ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
    $ sudo apt-get update && sudo apt-get install yarn
    
    $ sudo gem update --system
    $ sudo gem install compass
    $ composer global require hirak/prestissimo
    $ sudo npm install -g grunt-cli
    
    $ sudo apt-get install bind9 samba
    

    Samba-сервер


    Samba-сервер Первое, к чему я потянулся — Samba-сервер, который настроил для того, чтобы моя IDE могла работать непосредственно с файловой системой гостевой OS.

    Все мои проекты будут находится по пути /var/www/{project-name}.
    Так же в процессе настройки гостевой ОС я принудительно настроил DHCP сервер так, чтобы у нее был статический IP и пряталось все за NAT: 172.16.126.130.

    $ cat /etc/samba/smb.conf
    [global]
    workgroup = WORKGROUP
    server string = %h server (Samba, Ubuntu)
    dns proxy = no
    
    # few changes to speed up smbd
    strict allocate = Yes
    read raw = Yes
    write raw = Yes
    strict locking = No
    socket options = TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=131072 SO_SNDBUF=131072
    min receivefile size = 16384
    use sendfile = true
    aio read size = 16384
    aio write size = 16384
    
    max log size = 1000
    syslog only = no
    syslog = 0
    server role = standalone server
    
    usershare allow guests = yes
    
    [www]
        path = /var/www
        available = yes
        valid users = oxcom
        read only = no
        browsable = yes
        public = yes
        writable = yes
        executable = yes
    
    

    Чтобы IDE могла работать с этим ресурсом я монтирую эту Netbios папку как удаленный локальный диск.

    Mount local drive on Windows
    @echo off
    @title Local UBUNTU Network Drive

    net use q: \\172.16.126.130\www {user-password} /USER:oxcom

    Unmount local drive
    Unmount local drive
    @echo off
    @title Local UBUNTU Network Drive

    net use q: /delete


    Почему я стал использовать Samba, а не Shared Folders?
    На то время, когда я этим вопросом задался получалось так, что Shared Folders являлись монтируемой директорией, а NGINX не хотел их использовать как root директорию проекта. Второй причиной стало то, что время от времени у меня Shared Folders отваливались без видимой на то причины и без возможности быстро все восстановить. А также нет возможности работать с симлинками, которые необходимы для некоторых пакетов npm и не только.

    Есть ли какие-то проблемы с IDE?
    Да и разные, но SSD спасает:

    • иногда индексирование проектов происходит долго
    • при быстром изменении большого количества файлов (merge, rebase, смена бранча) не сразу подхватываются изменения. Смотрю в сторону rsync.
    • Если отключить диск раньше, чем закрыть IDE, то, при закрытии проекта, IDE зависнет
    • Если отвалится сеть, то проект скорее всего нужно будет открыть еще раз

    DNS-сервер


    Bind9Дорогой читатель может представить насколько трудно в большой компании запросить небольшие изменения в настройках сети. И даже если вы успешно пройдете первый этап объяснения для чего вам это нужно, то второй этап (реализация) может затянуться на очень большой срок, что проще все сделать самому.

    Так как я очень ленивый, то через какое-то время мне надоело добавлять в hosts файл записи вида:
    172.16.126.130 project1.lo
    172.16.126.130 project2.lo


    Было решено, что нужен локальный DNS-сервер, который можно настроить быстрее, чем я смогу выпить бутылку немецкого крепкого пива. После чего был послан запрос в лигу лени. Результат не заставил себя долго ждать: BIND9

    Настройка очень проста: описываем конфигурации прямого и обратного пула доменов, а также не забываем их подключить:

    $ cat /etc/bind/db.lo
    ;
    ; BIND data file for local loopback interface
    ;
    $TTL 604800
    @ IN SOA lo. root.lo. (
    0000119 ; Serial
    604800 ; Refresh
    86400 ; Retry
    2419200 ; Expire
    604800 ) ; Negative Cache TTL
    ;
    @ IN NS lo.
    @ IN A 172.16.126.130
    @ IN AAAA ::1
    * IN CNAME @

    $ cat /etc/bind/db.126.16.172
    ;
    ; BIND data file for local loopback interface
    ;
    $TTL 604800
    ;
    ; BIND reverse data file for local loopback interface
    ;
    $TTL 604800
    @ IN SOA ns.lo. root.lo. (
    0000112 ; Serial
    604800 ; Refresh
    86400 ; Retry
    2419200 ; Expire
    604800 ) ; Negative Cache TTL
    ;
    @ IN NS lo.

    $ cat /etc/bind/named.conf.local
    zone "lo" {
    type master;
    file "/etc/bind/db.lo";
    check-names ignore;
    allow-query { any; };
    allow-transfer { any; };
    };

    zone "126.16.172.in-addr.arpa" {
    type master;
    file "/etc/bind/db.126.16.172";
    allow-query { any; };
    allow-transfer { any; };
    };

    $ cat /etc/bind/named.conf.options
    options {
    directory "/var/cache/bind";

    forwarders {
    8.8.8.8;
    8.8.4.4;
    };

    recursion yes;
    listen-on { any; };

    auth-nxdomain no; # conform to RFC1035

    listen-on-v6 { any; };
    };


    Сервер настроен. Теперь, для полной радости осталось решить еще несколько задач:

    • заставить Host систему использовать наш DNS-сервер для домена .lo. Поэтому меняем на Host машине параметры виртуальной сети так, чтобы первым был наш DNS-сервер, и чистим DNS-кеш.
    • заставить Guest систему тоже использовать наш DNS-сервер. Тут проще: редактируем сетевой интерфейс и прописываем туда наш DNS-сервер

    Результат не заставляет себя ждать:

    $ dig example.lo
    ; <<>> DiG 9.10.3-P4-Ubuntu <<>> example.lo
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32204
    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 1, ADDITIONAL: 2

    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 4096
    ;; QUESTION SECTION:
    ;example.lo. IN A

    ;; ANSWER SECTION:
    example.lo. 604800 IN CNAME lo.
    lo. 604800 IN A 172.16.171.130

    ;; AUTHORITY SECTION:
    lo. 604800 IN NS lo.

    ;; ADDITIONAL SECTION:
    lo. 604800 IN AAAA ::1

    ;; Query time: 0 msec
    ;; SERVER: 172.16.171.130#53(172.16.171.130)
    ;; WHEN: Mon Jul 17 11:09:52 CEST 2017
    ;; MSG SIZE rcvd: 111

    ping example.lo
    Pinging lo [172.16.171.130] with 32 bytes of data:
    Reply from 172.16.171.130: bytes=32 time<1ms TTL=64
    Reply from 172.16.171.130: bytes=32 time<1ms TTL=64


    Вот только «nslookup example.lo» не работает. Почему — не знаю, но любой браузер на Host машине будет нормально ходить на соответствующий сервер.

    PHP-FPM и Pools


    PHP Вроде все работает. Теперь необходимо приступить к настройке PHP для каждого из проектов.
    Работая над последними проектами у меня получилось так, что один проект может состоять из различных сервисов или собирать в себе многие другие проекты. По-этому у меня получилась следующая структура:

    • warface.com
    • cryengine.com
    • shop.cryengine.com
    • forum.cryengine.com

    В процессе работы приходится использовать API вызовы между проектами и было бы очень хорошо уметь «дебажить» это все с помощью XDebug и любимой IDE. При попытках использовать один PHP Pool я сталкивался со следующими проблемами:

    • при отладке на одном домене с общей сессией PHP-FPM блокирует исполнение остальных запросов с такой же сессий (как смог так и описал :)). Таким образом останавливаясь где-то на cryengine.com я не смогу работать с forum.cryengine.com, пока не завершится предыдущий запрос.
    • неудобно проводить отладку двух проектов одновременно с разными ключами XDebug. Да-да, я стараюсь максимально избегать изменения настроек среды из PHP

    Чтобы это решить, я создал свой PHP Pool по шаблону для каждого проекта под каждую версию PHP. И подключаю их 'include=/etc/php/7.0/fpm/pool.d/*.d/*.conf'

    Шаблон
    $ cat /etc/php/{php-version}/fpm/pool.d/{project-name}.d/{project-subname}.conf
    ; Start a new pool
    ; the variable $pool can we used in any directive and will be replaced by the
    ; pool name ('www' here)
    [{project-name}-{project-subname}]
    
    user = www-data
    group = www-data
    
    listen = /run/php/php7.0-$pool-fpm.sock
    
    listen.owner = www-data
    listen.group = www-data
     
    pm = dynamic
    pm.max_children = 20
    pm.start_servers = 5
    pm.min_spare_servers = 3
    pm.max_spare_servers = 7
    
    php_admin_value[xdebug.idekey] = key-$pool
    


    Выглядит это примерно так:

    $ ls -la /etc/php/7.0/fpm/pool.d/
    cryengine.d/www.conf
    cryengine.d/shop.conf
    cryengine.d/forum.conf
    warface.d/www.conf
    www.conf
    Список PHP-Sockets
    php5.6-cryengine-www-fpm.sock
    php5.6-cryengine-shop-fpm.sock
    php5.6-cryengine-forum-fpm.sock
    php5.6-warface-www-fpm.sock
    php5.6-fpm.sock
    php7.0-cryengine-www-fpm.sock
    php7.0-cryengine-shop-fpm.sock
    php7.0-cryengine-forum-fpm.sock
    php7.0-warface-www-fpm.sock
    php7.0-fpm.sock


    Теперь каждый проект имеет свой PHP Pool и проставленным xdebug.idekey, что позволяет проводить непрерывную отладку между несколькими проектами (не забывайте настроить php.ini)

    NGINX


    NginxНастройка сервера довольно проста. Для каждого проекта создается отдельный файл конфигурации в 'sites-available', который описывает конфигурацию vhost. В конфигурации мы подключаем соответствующие файлы конфигурации для каждого проекта.

    Основываясь на указанной выше архитектуре я реализовал вот такую структуру:

    $ ls -la /etc/nginx/
    cryengine.d/
    - www.conf
    - forum.conf
    - shop.conf
    - ssl.conf
    warface.d/
    - www.conf
    - ssl.conf

    sites-available/
    - www.cryengine.conf
    - forum.cryengine.conf
    - shop.cryengine.conf
    - www.warface.conf

    nginx.conf

    $ cat /etc/nginx/sites-available/{project-subname}.{project-name}.conf
    server {
        listen 443 ssl http2;
        server_name {project-subname}.{project-name}.lo;
    
        root /var/www/{project-subname}.{project-name}.com/wwwroot;
        index           index.php;
    
        error_log  /var/www/{project-subname}.{project-name}.com/log/nginx.error.log error;
        access_log /var/www/{project-subname}.{project-name}.com/log/nginx.access.log;
    
        # configuration related to sub-project
        include {project-name}.d/www.conf;
        # global configuration for projects
        include {project-name}.d/ssl.conf;
    }


    Таким образом в /etc/nginx/{project-name}.d/ хранятся все конфигурации, которые относятся к проекту, а также сопутствующим под проектам. Каждый проект имеет свой PHP Pool пока каждую версию PHP, что позволяет быстро переключаться между версиями и только для одного проекта.

    Итоги


    Спасибо, что дочитали до конца. Я искренне надеюсь, что ручной труд еще не вымер, ибо разработчик должен уметь настроить среду сам и без автоматизации.
    В итоге я получил гибрид между двумя ОС, который позволяет полностью использовать все внутренние сервисы компании, а также вести разработку и отладку в среде, максимально приближенной к LIVE.

    Я понимаю, что это не идеальное решение, но это один из способов, как можно за короткий промежуток времени подготовить среду разработки.

    Минусы:

    • Долгая индексация в IDE
    • При переустановке/переносе виртуальной машины нужно изменять конфигурацию для Bind9 и скрипт подключения диска
    • Это все не автоматизировано

    Плюсы:

    • рабочую среду можно переносить с машина на машину
    • разработчик остается в Windows окружении и есть возможность использовать MS сервисы, которые установлены в компании.
    • разработчик работает с Linux окружением, которое может быть легко настроено как LIVE среда.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 11
    • 0
      Какой смысл использовать ВМ, в то время как в самой винде есть ubuntu bash на которой можно развернуть все тоже самое?!
      • 0
        Так уж случилось, что у меня еще есть Win7, в которой этого нет, но я работаю в ней с тем же подходом.
        Я сомневаюсь, что до текущего момента все компании поголовно перешли на Win10.
      • 0

        используйте vagrant например для подобных историй.


        настройку машины можно сложить в provision

        • 0
          smple
          Спасибо за совет! Планирую все это завернуть в Vagrant + Chef, и возможно что-то завернуть Docker.
          • 0

            docker прикольная вещь и она довольно быстро стартует, по сравнению со связкой vagrant + virtualbox только там всякие забавы идут с windows и mac и есть подход в котором докер крутится внутри виртуалки.


            Поэтому все же проще vagrant + virtualbox
            У него есть минусы:


            1. Потребляет лишнюю память и cpu (в среднем 1gb ram и проц)
            2. Разворачивается не быстро (в среднем 1 минута).
            3. На больших проектах синхронизация файлов по умолчанию тормозит (обычно используют rsync или nfs что выливается в пляски с windows хорошо если лицензия корпоративная или проффесиональная)

            Но есть и огромное количество плюсов
            по поводу provision, не обязательно использовать что то типо chef, ansible или puppet, можно просто использовать bash script в простых случаях как вы описали выше.


            Вообщем если есть на это спрос могу написать конечно статью на хабр на эту тему как я разворачиваю окружение ну и конфиг соответственный.

            • 0
              Мне будет очень интересно посмотреть, как это реализовали другие люди, так как от DevOps я относительно далеко, но уж очень интересно посмотреть.
              • 0

                дело в том что я не devops а обычный разработчик, просто люблю комфортную работу и хорошо умею настрайвать всякие штуки.

                • 0
                  я например использую docker так:

                  1) в системе крутится DNS docker контейнер tonistiigi/dnsdock

                  2) через docker-compose.yml описываю проект
                  например
                  version: '2'
                  services:
                     project_db:
                        image: mysql:{версия}
                     ....
                        environment:
                           DNSDOCK_NAME: project
                           DNSDOCK_IMAGE: db
                     project_php:
                        build: ./php{версия}
                     ....
                     project_nginx:
                        depends_on:
                           - project_php
                        image: nginx
                     ....
                        environment:
                           DNSDOCK_NAME: project
                           DNSDOCK_IMAGE: site
                  


                  3) кастую docker-compose up -d

                  получаю проект mysql + php-fpm + nginx

                  в итоге на хост машине
                  mysql доступен по адресу project.db.docker например для workbench
                  nginx доступен по адресу http://project.site.docker

                  могу остановить в любой момент, поднять несколько разных проектов с разными версиями БД и php.

                  на самой хост машине mysql снес, php только версии 7.1
            • 0
              Про Shared Folders хочу добавить — адски тормозят на hdd. То что должно происходить 30 мс может длиться 2.5 сек, зависит от количества операций с файлами. Года полтора-два промучился, выяснилось что это из-за них, проблема известна и нерешаема. Решил уйти от этой схемы и первым делом попробовал через самбу примонтировать. PhpStorm впадает в практически бесконечную переиндексацию. Переключение ветки может всё повесить на несколько минут, поиск по всем файлам невозможен, хоть на ночь оставляй. Да и просто тормозит при навигации по проекту, выдаче подсказок и т. д. Начал искать еще варианты и нашел вот это: https://habrahabr.ru/post/139348/. Очень хорошо работает, за время перехода в браузер и нажатие ф5 на сервере уже будет всё как надо. Единственное неудобство это то, что синхронизация односторонняя и сгенерированные на сервере файлы приходится скачивать вручную.
              • 0
                Интересный подход. Несколько раз смотрел в эту сторону, но нет. Мне действительно нужна двусторонняя синхронизация. Одна из причин — как ни крути, но в unix консоль более удобна и приятная в использовании чем cmd и windows решение для GIT.

                Еще я рассматривал монтирование с использованием SSHFS for Win, но PHPStorm постоянно засыпал меня уведомления, что GIT «упал» и все. Попытки решить проблему не увенчались успехом. Возможно нужно ждать обновлений.
                • 0
                  Решение проблемы нашел сегодня:
                  неправильный права доступа
                  $ find <somerepo>/.git -ls | grep 'r--r--r--'
                  $ chmod 0644 {file-path}
                  

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.