Сайты Alawar — это сайты для русского, американского, европейских и других рынков, отдельные сайты для mobile-устройств, сайты партнерских программ и др. Все они развернуты на одном инстансе Yii, о чем мы уже писали в нашем блоге на хабре.
Сегодня я расскажу, как мы организовали хранение, структуру и управление конфигами наших сайтов, какие при этом получили преимущества. А также поведаю, как осуществляется деплой нашего проекта в различных окружениях.
Конфиги
Для осуществления настройки сайтов мы применили следующую структуру конфигов в Yii:
protected/config /console /config.php /import.php /cache.php /log.php … /mobile /config.php /import.php /cache.php /log.php … /sites /alawar.ru.php /iphone.alawar.ru.php /ipad.alawar.ru.php /site.php … /test /config.php /import.php … /web /config.php /import.php /log.php … /~server /amqp.php /crontab.txt /db.php /eauth.php /mongo.php /redis.php /smsgate.php /services.php /comment.php …
Все конфигурационные файлы были разбиты на категории согласно их назначению:
- web/config.php — конфиг, содержащий настройки и параметры общие для всех web-сайтов
<?php return array( 'preload' => array( 'log' ), //список подключаемых файлов 'import' => require(dirname(__FILE__) . '/import.php'), 'components' => array( … //параметры подключения к MySql 'db' => require(dirname(dirname(__FILE__)) . '/server/mysql.php'), //параметры подключения к Redis 'redis' => require(dirname(dirname(__FILE__)) . '/server/redis.php'), //параметры подключения к Mongo 'mongo' => require(dirname(dirname(__FILE__)) . '/server/mongo.php'), //настройки логгирования 'log' => require(dirname(dirname(__FILE__)) . '/web/log.php'), //настройки компонента комментариев 'comment' => require(dirname(dirname(__FILE__)) . '/server/comment.php'), //настройки RabbitMQ 'amqp' => require(dirname(dirname(__FILE__)) . '/server/amqp.php'), //настройки авторизации через соц. сети 'eauth' => require(dirname(dirname(__FILE__)) . '/server/eauth.php'), … ), 'params' => array( //параметры доступа к различным сторонним сервисам 'services' => require(dirname(dirname(__FILE__)) . '/server/services.php'), //параметры доступа к смс-шлюзу 'smsgate' => require(dirname(dirname(__FILE__)) . '/server/smsgate.php'), … ) );
- site/{site.ru}.php — итоговый конфиг для сайта {site.ru} (специфичные настройки + общий конфиг web/config.php):
return CMap::mergeArray( array( 'basePath' => dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'. DIRECTORY_SEPARATOR . '..', 'name' => 'Site', 'theme' => 'site', 'host' => 'site.ru', 'language' => 'ru', //модули site.ru 'modules' => array( … ), //модули site.ru 'controllerMap' => array( … ), //спецефичные компоненты для site.ru 'components' => array( … ), // application-level parameters that can be accessed // using Yii::app()->params['paramName'] 'params' => array( //runtime параметры //например: //Yii::app()->params['runtimeData']['css'] - путь к минифицированному css сайта //Yii::app()->params['runtimeData']['js'] - путь к минифицированному js сайта 'runtimeData' => @include(dirname(__FILE__).'/runtime/sites/site.ru.php'), 'adminEmail' => 'admin@site.ru', ), ), require(dirname(dirname(__FILE__)).'/web/config.php') );
Такой подход к формированию итогового конфига сайта позволяет легко подключать новые сайты и достаточно гибко их настраивать.
- console/config.php — конфиг для консольного приложения, по структуре схож с web/config.php, но он имеет свои импорты, настройки логирования, подключаемые компоненты и др.
- test/config.php — конфиг для тестового окружения
Особенностью структуры конфигов является то, что в protected/~server сосредоточены «сереверозависимые» параметры и настройки, которые хранятся в отдельных репозиториях под каждый сервер(~server — это всего лишь симлинка на чекаут одного из репозиториев). Такая структура позволяет легко, быстро и без костылей разворачивать проект в различном окружении.
Деплой
В данный момент у нас проект может быть развернут на 3-х серверах:
- dev-сервер — сервер, на котором ведется разработка
- test-сервер — сервер, на котором запускаются тесты
- prod-сервер — продакшн
Соответственно, под каждый сервер заведен свой репозиторий с конфигами:
- dev-config
- test-config
- prod-config
При развертывании проекта (мы это делаем средсвами jenkins и phing) мы просто указываем, какую ветку и какой репозиторий с конфигами поднять:
#развертывание ветки task-xx в dev-окружении phing -Dbranch=task-xx -Dconfig=dev-config deploy #развертывание проекта на продакшн сервере phing -Dbranch=prod -Dconfig=prod-config deploy
Вот, что делает при этом phing:
<!-- Таск по развертыванию проекта --> <target name="deploy" depends="-get-properties"> <!-- Путь к директроии, в которой развертывается проект --> <mkdir dir="${deploy.path}" /> <!-- Путь к директроии, в которой будет расчекаучена ветка репозитория с кодом проекта --> <mkdir dir="${deploy.path}/application" /> <!-- Путь к директроии, в которой будет расчекаучена репозиторий с конфигами --> <mkdir dir="${deploy.path}/config" /> <echo msg="checkout application and config..." /> <!-- Чекаут ветки --> <exec command="bzr co ${bzr.branch.path} ./" dir="${deploy.path}" checkreturn="FALSE" returnProperty="bzr.co.return" outputProperty="bzr.co.out" /> <if> <!-- Если ветки не существует, создаем её, пачкую от ветки транк --> <equals arg1="${bzr.co.return}" arg2="3" /> <then> <exec command="bzr co ${bzr.trunk.path} ./" dir="${deploy.path}/application" /> <exec command="bzr switch -b ${bzr.branch.path}" dir="${deploy.path}/application" /> </then> </if> <!-- Чекаут репозитория с конфигами --> <exec command="bzr co ${bzr.config.path} ./" dir="${deploy.path}/config" /> <!-- Настройка прав доступа к папке runtime --> <chmod file="${deploy.path}/application/protected/runtime" mode="0777" /> <!-- Создание симлинки на конфиги --> <exec command="ln -s ${deploy.path}/config/server server" dir="${deploy.path}/application/protected/config/" level="info"/> <!-- Создание симлинки на php error log --> <exec command="ln -s ${php.error.log.path} phplog" dir="${deploy.path}/application/protected/runtime/" level="info"/> <!-- Для каждого сайта генерация минифицированного css и js и прописывание путей к ним в protected/runtime/sites/{site.ru.php} --> <exec command="php ${deploy.path}/application/protected/yiic deploy data=css" /> <exec command="php ${deploy.path}/application/protected/yiic deploy data=js" /> <!-- Генерация карты шардов redis и mysql --> <exec command="php ${deploy.path}/application/protected/yiic deploy data=shardmap" /> </target>
Таким образом, после развертывания структура всего проекта становится следующей:
application/ #чекаут репозитория с кодом проекта protected/ … config/ … ~server/ #симлинка на config/server … … public/ … config/ #чекаут репозитория с конфигами … server/ …
Итого
Используемая нами структура конфигов позволила:
- легко разворачивать и конфигурировать новые сайты
- автоматизировать деплой проекта
- легко разворачивать проект в различных окружениях
- иметь возможность отследить изменения в конфигурационных файлах
Однако, конечно у подхода с различными репозиториями под конфиги есть свои минусы, основной из них — это синхронизация изменений. Приходится руками переносить изменения в одном репозитории во все другие с учетом настроек окружения.
ссылка на оригинал статьи http://habrahabr.ru/company/alawar/blog/186458/
Добавить комментарий