Тема оформления
CI/CD автоматизация (Jenkins)
1. Концепция непрерывной интеграции и доставки
В производственном контуре платформы «UrFU HeatBalance» развёрнута автоматизированная система непрерывной интеграции и непрерывной доставки (CI/CD) на базе сервера автоматизации Jenkins.
Главные цели внедрения конвейера автоматизации:
- Исключение влияния человеческого фактора: автоматизация всех рутинных операций компиляции, сборки контейнеров и обновления серверов.
- Непрерывный контроль качества (Quality Gates): обязательный прогон набора модульных тестов математических моделей перед допуском изменений к контейнеризации.
- Иммутабельность артефактов: контейнерные образы собираются один раз с уникальным версионным идентификатором
${BUILD_NUMBER}и развёртываются без промежуточных ручных модификаций. - Минимизация времени простоя (Downtime): оркестрация обновления микросервисов средствами Docker Compose с сохранением состояния постоянных томов баз данных и брокера сообщений.
2. Архитектура и разбор пайплайна (Jenkinsfile)
Сценарий автоматизации зафиксирован в корне репозитория в файле Jenkinsfile. Ниже приведён построчный анализ ключевых блоков декларативного конвейера.
2.1. Инициализация и переменные окружения
groovy
pipeline {
agent any
triggers {
githubPush()
}
environment {
// Теги для Docker образов на основе монотонно возрастающего номера сборки
DOCKER_TAG = "${env.BUILD_NUMBER}"
}agent any: выполнение этапов конвейера на любом доступном исполнителе Jenkins (по умолчанию локальный рабочий узел хоста).triggers { githubPush() }: автоматический запуск сборки при поступлении входящего вебхука от сервиса GitHub о появлении новых коммитов.DOCKER_TAG = "${env.BUILD_NUMBER}": генерация уникального строкового тега для формируемых контейнеров. Это предотвращает коллизии версий и обеспечивает возможность точного аудита запущенного кода.
2.2. Стадия 1: Клонирование исходного кода (Checkout)
groovy
stage('Checkout') {
steps {
checkout scm
}
}На этой стадии Jenkins обращается к системе управления версиями Git, загружает дерево каталогов репозитория и переключает рабочее пространство на целевой коммит.
2.3. Стадия 2: Сборка и тестирование бэкенда (Build & Test Backend)
groovy
stage('Build & Test Backend') {
steps {
dir('backend/HeatBalanceSystem2') {
echo 'Restoring backend dependencies...'
sh 'dotnet restore HeatBalanceSystem.sln'
echo 'Building C# backend solution...'
sh 'dotnet build HeatBalanceSystem.sln --configuration Release --no-restore'
echo 'Running backend unit tests...'
sh 'dotnet test HeatBalance.Math.Tests/HeatBalance.Math.Tests.csproj --configuration Release --no-build'
}
}
}Назначение операций стадии:
dotnet restore: загрузка всех внешних NuGet-пакетов (OpenIddict, YARP, MassTransit, QuestPDF, Npgsql, xUnit) в локальный кэш сборщика.dotnet build --configuration Release --no-restore: компиляция всех микросервисов и разделяемых библиотек платформы с оптимизацией компилятора Roslyn. Флаг--no-restoreускоряет процедуру за счёт повторного использования кэшированных зависимостей.dotnet test ... --no-build: запуск набора модульных тестов теплотехнического ядраHeatBalance.Math.Tests.
IMPORTANT
Модульные тесты HeatBalance.Math.Tests проверяют корректность термодинамических формул для камерных, конвейерных, электрических печей и сушильных барабанов. В случае падения хотя бы одного теста (например, превышение невязки баланса свыше 0.01% или некорректный расчёт энтальпии) сборка аварийно прерывается, и некорректный код ни при каких обстоятельствах не попадёт в продакшен.
2.4. Стадия 3: Сборка клиентского интерфейса (Install & Build Frontend)
groovy
stage('Install & Build Frontend') {
steps {
dir('frontend') {
echo 'Installing frontend dependencies...'
sh 'npm ci --silent'
echo 'Running linter...'
sh 'npm run lint || true'
echo 'Building React production bundle...'
sh 'npm run build'
}
}
}npm ci --silent: чистая детерминированная установка клиентских npm-зависимостей строго по файлуpackage-lock.jsonс подавлением избыточного вывода в лог.npm run lint || true: проверка соответствия стилистическим стандартам ESLint. Конструкция|| trueпредотвращает падение пайплайна на минорных предупреждениях форматирования.npm run build: транспиляция исходных файлов JSX/ES6, минификация JavaScript, упаковка CSS-стилей и генерация финального дистрибутива в директорииfrontend/dist/.
2.5. Стадия 4: Сборка Docker-образов (Docker Build Services)
Сборка образов выполняется только при слиянии изменений в основную производственную ветку main:
groovy
stage('Docker Build Services') {
when {
expression { env.GIT_BRANCH?.contains('main') || env.BRANCH_NAME == 'main' }
}
steps {
echo 'Building container images for all services...'
// Сборка веб-интерфейса (Nginx со статическим бандлом)
sh "docker build -t heatbalance-frontend:${DOCKER_TAG} -t heatbalance-frontend:latest ./frontend"
// Сборка портала документации
sh "docker build -t heatbalance-docs:${DOCKER_TAG} -t heatbalance-docs:latest ./docs"
// Сборка бэкенд-микросервисов с контекстом корневой директории бэкенда
dir('backend/HeatBalanceSystem2') {
sh "docker build -t heatbalance-auth:${DOCKER_TAG} -t heatbalance-auth:latest -f src/Auth/HeatBalance.Auth/Dockerfile ."
sh "docker build -t heatbalance-gateway:${DOCKER_TAG} -t heatbalance-gateway:latest -f src/Gateway/HeatBalance.Gateway/Dockerfile ."
sh "docker build -t heatbalance-dataset:${DOCKER_TAG} -t heatbalance-dataset:latest -f src/Services/HeatBalance.DatasetService/Dockerfile ."
sh "docker build -t heatbalance-conveyor:${DOCKER_TAG} -t heatbalance-conveyor:latest -f src/Services/HeatBalance.ConveyorKilnService/Dockerfile ."
sh "docker build -t heatbalance-chamber:${DOCKER_TAG} -t heatbalance-chamber:latest -f src/Services/HeatBalance.ChamberKilnService/Dockerfile ."
sh "docker build -t heatbalance-electric:${DOCKER_TAG} -t heatbalance-electric:latest -f src/Services/HeatBalance.ElectricKilnService/Dockerfile ."
sh "docker build -t heatbalance-drum:${DOCKER_TAG} -t heatbalance-drum:latest -f src/Services/HeatBalance.DrumDryerService/Dockerfile ."
sh "docker build -t heatbalance-run:${DOCKER_TAG} -t heatbalance-run:latest -f src/Services/HeatBalance.RunService/Dockerfile ."
sh "docker build -t heatbalance-report:${DOCKER_TAG} -t heatbalance-report:latest -f src/Services/HeatBalance.ReportService/Dockerfile ."
sh "docker build -t heatbalance-iot:${DOCKER_TAG} -t heatbalance-iot:latest -f src/Services/HeatBalance.IoTService/Dockerfile ."
sh "docker build -t heatbalance-analytics:${DOCKER_TAG} -t heatbalance-analytics:latest -f src/Services/HeatBalance.AnalyticsService/Dockerfile ."
}
}
}Каждый образ собирается с двумя тегами:
heatbalance-<service>:${DOCKER_TAG}: постоянный версионный тег, соответствующий порядковому номеру билда в Jenkins.heatbalance-<service>:latest: указатель на последнюю актуальную стабильную версию, используемую оркестратором Docker Compose при запуске.
2.6. Стадия 5: Развёртывание стека (Deploy)
groovy
stage('Deploy') {
when {
expression { env.GIT_BRANCH?.contains('main') || env.BRANCH_NAME == 'main' }
}
steps {
echo 'Copying Nginx configuration to permanent location...'
sh 'mkdir -p /var/lib/jenkins/app-config/nginx'
sh 'cp -rf nginx/nginx.conf /var/lib/jenkins/app-config/nginx/nginx.conf'
echo 'Ensuring environment configuration (.env)...'
sh '''
mkdir -p /var/lib/jenkins/app-config
if [ -f /var/lib/jenkins/app-config/.env ]; then
echo "Applying persistent environment from /var/lib/jenkins/app-config/.env..."
cp /var/lib/jenkins/app-config/.env .env
elif [ -f .env ]; then
echo "Using existing workspace .env..."
else
echo "WARNING: /var/lib/jenkins/app-config/.env not found! Creating default .env template..."
cp .env.example /var/lib/jenkins/app-config/.env
sed -i 's/generate_a_secure_db_password_here/hb_secure_pass_2026/g' /var/lib/jenkins/app-config/.env
sed -i 's/Generate_A_Strong_Admin_Password_123!/Admin123$/g' /var/lib/jenkins/app-config/.env
sed -i 's/generate_random_m2m_secret_token_here/run-service-secret-dev/g' /var/lib/jenkins/app-config/.env
sed -i 's/put_your_secure_smtp_app_password_here//g' /var/lib/jenkins/app-config/.env
cp /var/lib/jenkins/app-config/.env .env
fi
'''
echo 'Deploying application stack via Docker Compose...'
withEnv([
"NGINX_CONF_PATH=/var/lib/jenkins/app-config/nginx/nginx.conf",
"NGINX_SSL_PATH=/var/lib/jenkins/app-config/nginx/ssl"
]) {
sh "docker compose down --remove-orphans || true"
sh "docker compose up -d"
echo '=== POST-DEPLOY DEBUG ==='
sh "docker ps -a || true"
}
}
}Порядок выполнения деплоя:
- Синхронизация конфигурации Nginx: обновлённый файл
nginx/nginx.confкопируется в персистентную системную директорию/var/lib/jenkins/app-config/nginx/nginx.conf. - Монтирование постоянных переменных окружения (
.env): подтягивание файла секретов из постоянной хостовой директории/var/lib/jenkins/app-config/.envв сборочное пространство. - Передача системных путей (
withEnv): определение переменныхNGINX_CONF_PATHиNGINX_SSL_PATH, указывающих на постоянные места хранения конфигурации и сертификатов SSL на хосте. - Остановка и очистка (
docker compose down --remove-orphans): остановка предыдущих версий контейнеров с автоматическим удалением сервисов, исключённых из конфигурации. - Запуск обновлённого стека (
docker compose up -d): фоновый запуск всех 14 контейнеров с подтягиванием свежесобранных локальных образов:latest. - Диагностический листинг (
docker ps -a): фиксация в консоли сборки Jenkins текущего статуса всех запущенных сервисов.
2.7. Секция Post-Actions: Очистка ресурсов и логирование
groovy
post {
success {
echo 'HeatBalance pipeline completed successfully! All microservices built and deployed.'
}
failure {
echo 'Pipeline failed.'
}
always {
echo 'Cleaning up workspace and unused Docker images...'
sh 'docker image prune -f || true'
cleanWs()
}
}docker image prune -f: автоматическое удаление промежуточных слоёв и безымянных образов («dangling images»), образующихся в процессе сборки multi-stage Dockerfile. Это предотвращает переполнение дискового пространства хоста.cleanWs(): удаление временных файлов сборки из рабочей директории Jenkins после завершения работы конвейера.
3. Настройка сервера Jenkins и интеграция с GitHub
3.1. Системные зависимости узла Jenkins
Для корректного выполнения конвейера на хост-сервере должны быть установлены следующие пакеты:
bash
# Проверка наличия .NET 10 SDK
dotnet --version
# Проверка наличия Node.js и npm
node -v
npm -v
# Проверка доступа демона Jenkins к сокету Docker
sudo usermod -aG docker jenkins
sudo systemctl restart jenkins3.2. Настройка Webhook в репозитории GitHub
- Перейдите в репозиторий GitHub: Settings -> Webhooks -> Add webhook.
- Укажите параметры входящего хука:
- Payload URL:
https://ci.heatbalance.online/github-webhook/ - Content type:
application/json - Secret: секретная строка для проверки подлинности запроса (настраивается в Jenkins).
- Which events would you like to trigger this webhook?:
Just the push event.
- Payload URL:
- Нажмите кнопку Add webhook.
4. Регламент аварийного отката версий (Rollback Strategy)
В случае обнаружения скрытого дефекта в логике микросервисов после успешного прохождения конвейера администратор может выполнить откат платформы к предыдущему стабильному номеру сборки без перекомпиляции исходного кода:
bash
# 1. Просмотр доступных версий локальных образов
docker images | grep heatbalance
# 2. Выбор целевого стабильного номера сборки (например, 42)
TARGET_TAG=42
# 3. Перетегирование стабильных образов как :latest
docker tag heatbalance-frontend:${TARGET_TAG} heatbalance-frontend:latest
docker tag heatbalance-auth:${TARGET_TAG} heatbalance-auth:latest
docker tag heatbalance-gateway:${TARGET_TAG} heatbalance-gateway:latest
docker tag heatbalance-dataset:${TARGET_TAG} heatbalance-dataset:latest
docker tag heatbalance-conveyor:${TARGET_TAG} heatbalance-conveyor:latest
docker tag heatbalance-chamber:${TARGET_TAG} heatbalance-chamber:latest
docker tag heatbalance-electric:${TARGET_TAG} heatbalance-electric:latest
docker tag heatbalance-drum:${TARGET_TAG} heatbalance-drum:latest
docker tag heatbalance-run:${TARGET_TAG} heatbalance-run:latest
docker tag heatbalance-report:${TARGET_TAG} heatbalance-report:latest
docker tag heatbalance-iot:${TARGET_TAG} heatbalance-iot:latest
docker tag heatbalance-analytics:${TARGET_TAG} heatbalance-analytics:latest
# 4. Перезапуск контейнеров с откаченными версиями
cd /opt/UrFU-HeatBalance-Microservices
docker compose down --remove-orphans
docker compose up -dПроцедура отката занимает менее 30 секунд, не требует повторной сборки и восстанавливает работоспособность системы с сохранением всех пользовательских данных в PostgreSQL.