Трансформация DevOps: от хаоса ручных деплоев к автоматизированному пайплайну

Аудит: что мы увидели в «ИнсурТех»

Когда страховая компания «ИнсурТех» обратилась к нам, деплой нового релиза занимал 2 рабочих дня. Не часа — именно дня. Процесс выглядел так: разработчик собирал JAR-файл на своём ноутбуке, заливал по FTP на продакшен-сервер, перезапускал Tomcat руками через SSH, проверял «на глаз» что приложение поднялось, и отправлял в общий чат «задеплоил».

За первую неделю аудита мы зафиксировали:

  • Версионирование: код хранился в общей папке на Windows-сервере. «Бэкапы» — копирование папки с суффиксом даты: project_20250415_v2_final_FINAL.
  • Тестирование: ручное, одним QA-инженером. Регрессия занимала 3 дня. Автотестов ноль.
  • Среды: одна — продакшен. Staging отсутствует. Разработчики тестируют на своих машинах.
  • Мониторинг: лог-файлы на сервере, которые читают через tail -f. Алерты — звонок от клиента.
  • Инциденты: средний MTTR (время восстановления) — 4 часа. Откат — это «найти вчерашний JAR и залить обратно».

Частота деплоев: 1-2 раза в месяц. Каждый деплой — стресс для всей команды. Change failure rate — 35%: каждый третий релиз приводил к инциденту.

Этап 1: Git — фундамент всего

Первый шаг — перенести код из файловой шары в Git. Звучит банально, но для команды, которая 5 лет работала с FTP, это культурный сдвиг.

Мы развернули GitLab CE на отдельном сервере и провели обучение:

# Установка GitLab CE на Ubuntu 22.04
sudo apt update && sudo apt install -y curl openssh-server ca-certificates
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
sudo EXTERNAL_URL="https://gitlab.insurtech.local" apt install gitlab-ce

# Начальная настройка
sudo gitlab-ctl reconfigure
sudo gitlab-rake "gitlab:password:reset[root]"

Правила работы с ветками, которые мы установили:

# .gitlab/merge_request_templates/Default.md
## Что изменено
- [ ] Описание изменений

## Как тестировать
- [ ] Шаги для проверки

## Чек-лист
- [ ] Код прошёл review
- [ ] Нет захардкоженных паролей
- [ ] Миграции БД обратимы
- [ ] Обновлён CHANGELOG

Внедрили trunk-based development: короткие feature-ветки от main, merge request с обязательным code review, запрет push напрямую в main. Первые 2 недели были болезненными — разработчики привыкали к конфликтам и ребейзам. Но уже к концу месяца команда не могла представить, как работала без Git.

Этап 2: CI — автоматическая сборка и тесты

Как только код оказался в GitLab, мы настроили CI-пайплайн. Ключевое правило: каждый коммит собирается и тестируется автоматически.

# .gitlab-ci.yml
stages:
  - build
  - test
  - security
  - deploy-staging
  - deploy-production

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

cache:
  key: maven-cache
  paths:
    - .m2/repository

build:
  stage: build
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn clean package -DskipTests
  artifacts:
    paths:
      - target/*.jar
    expire_in: 1 hour

unit-tests:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn test
  artifacts:
    reports:
      junit: target/surefire-reports/TEST-*.xml
    when: always

integration-tests:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  services:
    - postgres:15
    - redis:7
  variables:
    POSTGRES_DB: test_db
    POSTGRES_USER: test
    POSTGRES_PASSWORD: test
    SPRING_DATASOURCE_URL: "jdbc:postgresql://postgres:5432/test_db"
  script:
    - mvn verify -Pintegration-tests

sast-scan:
  stage: security
  image: semgrep/semgrep:latest
  script:
    - semgrep --config auto --json --output semgrep-results.json .
  artifacts:
    paths:
      - semgrep-results.json
  allow_failure: true

Параллельно мы написали первые автотесты. За 3 недели покрыли критические бизнес-сценарии: расчёт страховой премии, создание полиса, обработка выплат. 87 unit-тестов и 23 интеграционных теста — минимум, который ловит 80% регрессий.

Этап 3: Docker — воспроизводимые среды

Главная проблема «ИнсурТех» — «у меня на машине работает». Каждый разработчик имел свою версию JDK, свои переменные окружения, свою PostgreSQL. Мы стандартизировали среду через Docker:

# Dockerfile — multi-stage build
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests

FROM eclipse-temurin:17-jre-alpine
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
RUN chown app:app app.jar
USER app

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "-XX:+UseG1GC", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]

Docker Compose для локальной разработки — каждый разработчик поднимает идентичную среду одной командой:

# docker-compose.dev.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=dev
      - DB_HOST=postgres
      - REDIS_HOST=redis
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: insurtech
      POSTGRES_USER: app
      POSTGRES_PASSWORD: dev_password
    volumes:
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

Эффект был моментальный: онбординг нового разработчика сократился с 2 дней до 30 минут. git clone + docker compose up — и работаешь.

Этап 4: CD — автоматический деплой

Продолжение .gitlab-ci.yml — стадии деплоя:

build-image:
  stage: deploy-staging
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE

deploy-staging:
  stage: deploy-staging
  image: alpine:3.19
  needs: [build-image, unit-tests, integration-tests]
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
  script:
    - ssh -o StrictHostKeyChecking=no deploy@staging.insurtech.local "
        docker pull $DOCKER_IMAGE &&
        docker compose -f /opt/app/docker-compose.yml up -d --no-deps app &&
        docker compose -f /opt/app/docker-compose.yml exec app
          wget -qO- --timeout=30 http://localhost:8080/actuator/health"
  environment:
    name: staging
    url: https://staging.insurtech.local

deploy-production:
  stage: deploy-production
  needs: [deploy-staging]
  script:
    - ssh -o StrictHostKeyChecking=no deploy@prod.insurtech.local "
        docker pull $DOCKER_IMAGE &&
        docker compose -f /opt/app/docker-compose.yml pull &&
        docker compose -f /opt/app/docker-compose.yml up -d --no-deps app"
  environment:
    name: production
    url: https://app.insurtech.ru
  when: manual  # Продакшен — только ручное подтверждение
  only:
    - main

Ключевое решение: деплой на staging — автоматический, на продакшен — по кнопке. Это дало команде уверенность: код проверен на staging, и деплой — это нажатие одной кнопки в GitLab, а не двухдневный ритуал.

Этап 5: Infrastructure as Code и мониторинг

Серверы «ИнсурТех» настраивались вручную — классические «снежинки». Мы описали инфраструктуру через Ansible:

# ansible/playbooks/setup-server.yml
---
- hosts: all
  become: true
  roles:
    - common          # обновления, NTP, firewall
    - docker           # Docker + Docker Compose
    - node-exporter    # метрики для Prometheus
    - promtail         # логи в Loki

- hosts: app_servers
  become: true
  roles:
    - app-deploy       # деплой приложения
    - nginx-proxy      # reverse proxy + TLS

- hosts: monitoring
  become: true
  roles:
    - prometheus
    - grafana
    - loki
    - alertmanager
# ansible/roles/common/tasks/main.yml
---
- name: Set timezone
  timezone:
    name: Europe/Moscow

- name: Install base packages
  apt:
    name:
      - curl
      - htop
      - iotop
      - fail2ban
      - unattended-upgrades
    state: present

- name: Configure firewall
  ufw:
    rule: allow
    port: "{{ item }}"
    proto: tcp
  loop:
    - '22'
    - '80'
    - '443'

- name: Enable firewall
  ufw:
    state: enabled
    default: deny

Мониторинг подняли на Prometheus + Grafana с алертами в Telegram:

# prometheus/alerts/app.yml
groups:
  - name: insurtech-app
    rules:
      - alert: HighErrorRate
        expr: rate(http_server_requests_seconds_count{status=~"5.."}[5m]) > 0.5
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Высокий процент ошибок 5xx"
          description: "Более 0.5 req/sec с ошибками 500 в течение 5 минут"

      - alert: SlowResponses
        expr: histogram_quantile(0.95, rate(http_server_requests_seconds_bucket[5m])) > 2
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "P95 латентность выше 2 секунд"

Теперь о проблемах узнаём из Telegram за секунды, а не от клиентов через часы.

Культурные изменения: самое сложное

Технические инструменты — это 30% работы. Остальные 70% — изменение привычек людей. Вот что мы сделали:

  • Code review стал обязательным — каждый merge request проверяет минимум один коллега. Первый месяц были конфликты («зачем мне ждать, я и так знаю что правильно»), но после того, как code review поймал критический баг в расчёте премии — сопротивление исчезло.
  • Blameless postmortems — после каждого инцидента пишем разбор без обвинений. Фокус на системных причинах: «почему система позволила этому произойти?» вместо «кто виноват?»
  • Метрики вместо ощущений — вместо «кажется, стало лучше» — конкретные цифры DORA-метрик на дашборде.
  • Еженедельные демо — каждую пятницу команда показывает, что сделано. Это мотивирует и создаёт прозрачность.

Один из разработчиков сказал через 2 месяца: «Раньше деплой был как русская рулетка. Теперь я деплою 3 раза в день и не нервничаю».

Результаты трансформации

Через 3 месяца после начала трансформации DORA-метрики «ИнсурТех» изменились радикально:

МетрикаДоПослеИзменение
Частота деплоев1-2 раза/мес3-5 раз/день×75
Lead time (код → прод)2 дня15 минут×192
MTTR4 часа12 минут×20
Change failure rate35%4%×8.7
Время онбординга2 дня30 минут×96
Покрытие тестами0%68%

Стоимость трансформации: 3 месяца работы двух наших инженеров + сервер GitLab (8 vCPU, 16 ГБ RAM) + сервер мониторинга (4 vCPU, 8 ГБ RAM). Окупилось за первый же квартал за счёт сокращения простоев и ускорения вывода фичей на рынок.

Если ваша команда всё ещё деплоит руками и «боится пятницы» — напишите нам на itfresh.ru. DevOps-трансформация не требует революции — достаточно последовательных шагов.

Часто задаваемые вопросы

Минимальный результат (Git + CI/CD + Docker) достижим за 4-6 недель. Полная трансформация с IaC, мониторингом и культурными изменениями занимает 3-6 месяцев в зависимости от размера команды и технического долга.
На этапе внедрения — нет, достаточно внешней команды. После настройки пайплайнов их поддержкой может заниматься один из разработчиков (20% рабочего времени). Выделенный DevOps-инженер нужен при команде от 15+ разработчиков или при использовании Kubernetes.
GitLab CI, если используете GitLab для хранения кода: единый интерфейс, встроенный container registry, нативная интеграция. Jenkins — если уже есть инвестиции в Jenkins-плагины или нужна поддержка экзотических пайплайнов. Для новых проектов в 2026 году рекомендуем GitLab CI или GitHub Actions.
Считайте деньги: стоимость часа простоя, стоимость рабочего времени на ручной деплой, упущенная выгода от задержки фичей. В случае «ИнсурТех» один инцидент стоил компании 180 000 рублей в потерянных продажах — это больше, чем месячная стоимость всей DevOps-инфраструктуры.
Не просто можно — нужно. Начните с Git (1 неделя), затем базовый CI (2 недели), потом Docker (2 недели), потом CD и мониторинг. Каждый этап приносит измеримую пользу и создаёт фундамент для следующего. Big bang внедрение провалится из-за сопротивления команды.

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#devops#ci/cd#gitlab ci#docker#автоматизация#pipeline#infrastructure as code#terraform
Комментарии 0

Оставить комментарий

загрузка...