пятница, 27 февраля 2015 г.

Правила iptables

Начальные правила для iptables
# Generated by iptables-save v1.4.21 on Fri Feb 27 19:52:43 2015
*mangle
:PREROUTING ACCEPT [10:660]
:INPUT ACCEPT [10:660]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [7:840]
:POSTROUTING ACCEPT [7:840]
COMMIT
# Completed on Fri Feb 27 19:52:43 2015
# Generated by iptables-save v1.4.21 on Fri Feb 27 19:52:43 2015
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [7:840]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Fri Feb 27 19:52:43 2015

понедельник, 16 февраля 2015 г.

Кеширование в Yii2

После того как поиграл с профайлером захотелось мне немного ускорить генерацию страниц в одном глупом проекте за счет кеширования.
1. Кеширование страницы целиком, реализуется через поведение контроллера
    public function behaviors()
    {
        return [
            [
                'class' => 'yii\filters\PageCache',
                'only' => ['index'],
                'duration' => 3600,
            ],
        ];
    }

тут я кеширую страницу index на один час

2. Кеширование блоков внутри шаблона страницы
<?php if ($this->beginCache('shop' . $shop->id, ['duration' => 3600])) : ?>
    .......

    <?php $this->endCache() ?>
<?php endif ?>
кешируется все что попало между beginCache & endCache



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

До изменений контроллер выглядел примерно так
public function actionShop($id)
{
        $shop = Shop::findOne($id);
        $products= Product::find()->where(['shop_id'=>$shop->id]) ->orderBy(['price'=>SORT_DESC])->all();
        return $this->render('pricelist', ['shop'=>$shop, 'products'=>$products];
}

Однако после того как я кеширование фрагмента - список товаров, пришлось перенести
        $products= Product::find()->where(['shop_id'=>$shop->id]) ->orderBy(['price'=>SORT_DESC])->all();
в модель Shop. Тут многие могут сказать, что так и надо было сделать изначально, но я не считаю нужным делать такие вещи пока проект активно меняется. Если бы я убрал это раньше я мог пропустить очевидность этих изменений.

Вообще все закончилось хорошо. Скорость отдачи увеличилась, спасибо Redis, а я получил прекрасный опыт, что:
1. преждевременная оптимизация - хуже отсутствия её вообще
2. кеширование нужно использовать с умом

Подключение профайлера XHProf

Сегодня потребовалось заняться профилированием приложения, написанного на Yii2. Для этого будем использовать замечательный инструмент от Facebook - xhprof Большим преимуществом данного профайлера является возможность работы на боевом сервере. И так начнем.

Устанавливаем профайлер и инструмент для графа вызова функций следующей командой
sudo apt-get install php5-xhprof graphviz

Подключаем расширение xhprof к php-fpm.
Далее необходимо разместить папки xhprof_lib & xhprof_html и поместить их рядом с точкой входа в приложение index.php и подключить сборщик вызовов в index.php

<?php
// Начинаем сбор информации, дополнительно будем собирать информацию о  использовании оперативной памяти и процессоре
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);

// отключаем отладочный режим
define('YII_DEBUG', false);
define('YII_ENV', 'prod');

require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');

$config = require(__DIR__ . '/../config/web.php');

(new yii\web\Application($config))->run();

// останавливаем сбор информации о вызовах
$xhprof_data = xhprof_disable();

include_once __DIR__ . '/xhprof_lib/utils/xhprof_lib.php';
include_once __DIR__ . '/xhprof_lib/utils/xhprof_runs.php';

$xhprof_runs = new XHProfRuns_Default();

// save the run under a namespace "xhprof_foo"
$run_id = $xhprof_runs->save_run($xhprof_data, 'xhprof_foo');

// внизу страницы отобразим ссылку на просмотр
echo "<a href='/xhprof_html/index.php?run={$run_id}&source=xhprof_foo' target='_blank'>profile</a>";

пятница, 13 февраля 2015 г.

Teamcity

Хорошая статья по установке TeamCity на CentOS https://plone.lucidsolutions.co.nz/software-development/continuous-integration/teamcity/teamcity-v9.x-on-centos-v7.x-with-mariadb/view


Мне была поставлена задача - внедрить систему непрерывной интеграции, которая выполняла следующие задачи:
  1. забирала новую ветку из системы контроля версий git
  2. подгружала все зависимые библиотеки используя composer
  3. создавала/пересоздавала базу данных и применяла миграции
  4. выполняла все тесты
  5. в случае успешного выполнения всех пунктов, тестируемая ветка вливалась в ветку для разработчиков devel
Процедуру установки Teamcity я пока пропущу, начну сразу с настройки. Я использовал версию TeamCity Professional 8.1.5 (build 30240). 

1. Пользователи и уведомления

Для каждого пользователя, который будет работать с CI необходимо завести учетную запись и обязательно сделать сопоставление с именем пользователя из системы контроля версии. Только тогда пользователи будут получать уведомления.
Идем Administration > Users > Create user account, заполняем Username, Name, Email address (куда будут приходить уведомления), Password, Confirm password и нажимаем Create User. Находим пользователя в списке Administration > Users и открываем на редактирование. В разделе Version Control Username Settings нажимаем edit. В этом разделе настраивается сопоставление пользователя Teamcity и пользователя VCS. Можно указать одно правило для всех через запись Default for all of the VCS roots, а можно настроить для каждого типа или даже репозитория отдельно. В качестве имени я использовал email.
Если в качестве имени используется email, в настройках VCS Root нужно указать следующее:
Тогда Teamcity будет извлекать email из коммитов и сравнивать их с email'ами которые иказали в разделе Version Control Username Settings.

2. Настройка проекта

Идем в раздел Administration > Projects и нажимаем Create Project. Заполняем имя и описание, Project ID пускай присваивается автоматически и нажимаем Create.

2.1 Репозиторий исходного кода

Заходим в раздел VCS Roots и добавляем новый репозиторий.

Docker

Docker - интересная технология. Основное предназначение - стабилизация окружения выполнения программ, легкий перенос программ (вместе с окружением) на новый сервер, быстрое развертывание. Я довольно долго разбирался с Docker, все пытался сам понять как бы его можно было использовать. В своей практике я не сталкивался с deploy hell, когда имеются взаимоисключающие условия на окружение программ, но именно эту проблему с легкостью помогает решить docker. И все же я нашел для себя пример его использования - развертывание TeamCity и его агентов. Собственно мною было сделаны 2 контейнера:
  1. TeamCity сервер
  2. TeamCity build agent