О насБлогКонтакты
DevOps и инфраструктура20 августа 2012 г. 4 мин 112Обновлено: 22 июня 2026 г.

Рождение DevOps: как культ непрерывной интеграции (Jenkins) начался в наших лабах

AunimedaAunimeda
📋 Содержание

До CI/CD наш процесс деплоя в 2010 году был таким:

  1. Открыть FileZilla (FTP-клиент)
  2. Перейти в директорию проекта
  3. Выбрать изменённые файлы (вручную, по памяти)
  4. Загрузить на сервер
  5. Надеяться, что не пропустили файлы
  6. Обновить production-сайт
  7. Обнаружить баг, который внесли
  8. Откатиться загрузкой старых файлов (которые могли и не сохраниться)

Это был отраслевой стандарт. Мы не были исключением. Самым распространённым «улучшением» было использование SSH и rsync вместо FTP, но ручной выбор изменённых файлов и отсутствие автоматизированных тестов сохранялись.

Мы всерьёз приняли Continuous Integration в 2012 году. Это изменило нашу работу фундаментальнее почти любого другого технического решения того десятилетия.


Jenkins: CI-сервер

Jenkins начинался как Hudson в Sun Microsystems. После покупки Sun Oracle в 2010 произошёл форк, и сообщество переименовало его в Jenkins. К 2012 году - доминирующий open-source CI-сервер.

Установка была простой - Jenkins был Java WAR-файлом:

wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -
sudo apt-get update && sudo apt-get install jenkins
# Jenkins запускается на порту 8080 по умолчанию

Конфигурация задачи:

<project>
  <scm class="hudson.plugins.git.GitSCM">
    <userRemoteConfigs>
      <hudson.plugins.git.UserRemoteConfig>
        <url>git@github.com:aunimeda/project.git</url>
      </hudson.plugins.git.UserRemoteConfig>
    </userRemoteConfigs>
    <branches>
      <hudson.plugins.git.BranchSpec><name>*/main</name></hudson.plugins.git.BranchSpec>
    </branches>
  </scm>
  <triggers>
    <hudson.triggers.SCMTrigger>
      <spec>* * * * *</spec> <!-- Проверка изменений каждую минуту -->
    </hudson.triggers.SCMTrigger>
  </triggers>
  <builders>
    <hudson.tasks.Shell>
      <command>
        composer install --no-dev --optimize-autoloader
        npm install
        ./vendor/bin/phpunit tests/
        npm run build
      </command>
    </hudson.tasks.Shell>
  </builders>
</project>

Первый пайплайн: checkout кода, запуск PHPUnit тестов, email при ошибке. Никакого деплоя. Просто «работает ли код?»


Написание первых тестов

До CI мы почти не писали автоматизированных тестов. После установки Jenkins «проходит ли CI-пайплайн?» стало ежедневной частью работы.

class ProductTest extends PHPUnit_Framework_TestCase {
    
    public function testProductCreation() {
        $product = new Product($this->db, ['name' => 'Тест', 'price' => 1500]);
        $id = $product->save();
        $this->assertGreaterThan(0, $id);
        
        $stmt = $this->db->prepare('SELECT * FROM products WHERE id = ?');
        $stmt->execute([$id]);
        $row = $stmt->fetch();
        $this->assertEquals('Тест', $row['name']);
    }
    
    public function testProductPriceValidation() {
        $this->setExpectedException('InvalidArgumentException');
        new Product($this->db, ['name' => 'Неверный', 'price' => -10]);
    }
    
    public function testProductSearch() {
        $this->db->exec("INSERT INTO products (name, price) VALUES ('Виджет А', 500), ('Виджет Б', 1000)");
        $results = (new ProductRepository($this->db))->search('Виджет');
        $this->assertCount(2, $results);
    }
}

Дисциплина написания тестов обнаруживала баги в коде, который мы считали работающим. Тест testProductPriceValidation - мы написали тест до написания валидации, обнаружили, что класс продукта принимал отрицательные цены, и исправили. Тест-ориентированное обнаружение: тесты находили больше багов, чем ручное QA.


Добавление деплоя

После того как тесты стали надёжными (8 недель настройки), добавили автоматический деплой:

#!/bin/bash
set -e

SERVER="deployer@production.example.com"
APP_DIR="/var/www/application"
RELEASE_DIR="$APP_DIR/releases/$(date +%Y%m%d%H%M%S)"
CURRENT_LINK="$APP_DIR/current"

echo "=== Деплой в production ==="
ssh $SERVER "mkdir -p $RELEASE_DIR"
rsync -avz --exclude='.git' --exclude='vendor' ./ $SERVER:$RELEASE_DIR/
ssh $SERVER "cd $RELEASE_DIR && composer install --no-dev"
ssh $SERVER "cd $RELEASE_DIR && php artisan migrate --force"

# Атомарное переключение симлинка (zero-downtime деплой)
ssh $SERVER "ln -sfn $RELEASE_DIR $CURRENT_LINK"
ssh $SERVER "sudo service php5-fpm reload"

echo "=== Деплой завершён ==="
ssh $SERVER "ls -dt $APP_DIR/releases/*/ | tail -n +6 | xargs rm -rf" # 5 последних релизов

Переключение симлинка ln -sfn - техника деплоя без downtime. nginx/apache обслуживали из current/, указывающей на последний релиз. Переключение симлинка было атомарным на уровне файловой системы. Текущие запросы завершались против старого релиза; новые попадали в новый.


Пайплайн как барьер

Более глубокое культурное изменение - отношение к пайплайну как к барьеру.

До: «Задеплою и исправлю проблемы по мере возникновения.» После: «Не могу деплоить, пока пайплайн не зелёный.»

Это казалось тривиальным. Не было. Это означало:

  • Мерж сломанного кода в main неприемлем
  • Машина каждого разработчика должна запускать полный набор тестов перед пушем
  • Изменения инфраструктуры (миграции БД, конфиги) скриптованы и протестированы, не применены вручную

Что DevOps означал в 2012

Трение «Dev» (разработки) и «Ops» (системных администраторов) существовало всегда: разработчики быстро выпускали код; ops-команды отвечали за стабильность и противились быстрым изменениям.

Идея движения DevOps: сделать деплой настолько автоматизированным и надёжным, чтобы он перестал быть пугающим событием. Если деплой - нажатие кнопки на 5 минут с автоматическим откатом при ошибке, можно деплоить 10 раз в день вместо одного раза в месяц. 10 деплоев в день - меньше изменений, меньше риска на деплой, более быстрое обнаружение багов.

Установка Jenkins 2012 года примитивна по стандартам 2024 (GitHub Actions или GitLab CI значительно мощнее). Но основная идея - автоматизированные тесты, автоматизированный деплой, пайплайн как барьер - неизменна. Мы до сих пор работаем по той же схеме, просто с лучшими инструментами.

Читайте также

Мониторинг Node.js в production: Prometheus, Grafana и OpenTelemetryaunimeda
DevOps и инфраструктура

Мониторинг Node.js в production: Prometheus, Grafana и OpenTelemetry

Как понять что ваш Node.js сервер падает ещё до того как пользователи начали жаловаться. Настройка метрик с Prometheus, дашборды в Grafana, трейсинг с OpenTelemetry - полная конфигурация для production.

Хостинг для сайта в Кыргызстане: VPS, shared или облако - что выбрать в 2026aunimeda
DevOps и инфраструктура

Хостинг для сайта в Кыргызстане: VPS, shared или облако - что выбрать в 2026

Разбираем типы хостинга для сайтов в Кыргызстане: shared, VPS, облачный и выделенный сервер. Реальные цены в сомах, рейтинг провайдеров и когда стоит апгрейдиться.

DevOps для малого бизнеса в Бишкеке: зачем нужен и как внедрить в 2026 годуaunimeda
DevOps и инфраструктура

DevOps для малого бизнеса в Бишкеке: зачем нужен и как внедрить в 2026 году

DevOps - не только для корпораций. Разбираем, как CI/CD, контейнеризация и мониторинг помогают малому бизнесу в Бишкеке выпускать продукты быстрее и с меньшими рисками.

Нужна IT-разработка для вашего бизнеса?

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

DevOps и инфраструктура

Получить консультацию Все статьи