Сервис развивается: тестируем формат, собираем идеи, улучшаем сервис. Есть идеи?

Написать
Войти
Дайджесты
Модернизация Jenkins: перенос сборщиков в динамические поды Kubernetes

Модернизация Jenkins: перенос сборщиков в динамические поды Kubernetes

Традиционные статические агенты Jenkins вызывают простои серверов, конфликты версий и трудности с учетом затрат. Перенос рабочих агентов в динамические поды Kubernetes обеспечивает изоляцию процессов сбора, автоматическое масштабирование ресурсов и прозрачный финансовый учет по командам.

Модернизация Jenkins: перенос сборщиков в динамические поды Kubernetes

Во многих инжиниринговых компаниях и IT-департаментах сервера автоматизации сборки Jenkins остаются ключевым фундаментом конвейеров непрерывной интеграции и поставки ПО (CI/CD). Однако традиционная схема развертывания с постоянными выделенными агентами — когда для сборок выделяются статические виртуальные машины или физические сервера, работающие в режиме 24 часа в сутки и 7 дней в неделю — создаёт серьезные операционные и экономические проблемы.

В периоды высокой нагрузки и перед крупными релизами разработчики сталкиваются с длинными очередями запускных задач. В то же время по ночам и в выходные дни выделенная инфраструктура простаивает, продолжая потреблять ресурсы. Дополнительно возникают конфликты системных зависимостей, когда разным проектам требуются отличающиеся версии окружений (например, Java 11 и Java 17, либо различные версии Node.js), а также возникают серьезные сложности с точным распределением затрат на серверные мощности между продуктовыми командами.

Перевод исполнительных агентов Jenkins на динамические поды Kubernetes решает эти инфраструктурные ограничения. В такой архитектуре центральный управляющий узел (Jenkins Controller) создает изолированный под в кластере под конкретную задачу, выполняет шаги сборки внутри целевых контейнеров и полностью удаляет под сразу после завершения пайплайна.

Архитектура решения и взаимодействие с Kubernetes API

В динамической модели управляющий узел Jenkins подключается к API-серверу Kubernetes через специализированный плагин kubernetes-plugin. Когда в очередь задач поступает новая сборка, контроллер обращается к кластеру и запрашивает создание нового пода на основе описанного шаблона (Pod Template).

Каждый создаваемый под сборщика содержит служебный контейнер jnlp (Jenkins Network Launch Protocol) для поддержания связи с управляющим узлом, а также один или несколько рабочих контейнеров с целевыми инструментами разработки. Для обеспечения безопасности и контроля доступа взаимодействие между Jenkins и кластером происходит от имени служебной учетной записи с строго ограниченными правами.

Шаг 1. Настройка пространства имен и прав доступа RBAC

Развертывание начинается с создания изолированного пространства имен в Kubernetes и настройки прав авторизации через механизмы Role-Based Access Control (RBAC). Для этого создается служебная учетная запись jenkins-admin в пространстве имен jenkins:

apiVersion: v1
kind: Namespace
metadata:
  name: jenkins
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-admin
  namespace: jenkins

Для управления динамическими подами данной учетной записи назначаются соответствующие привилегии через манифест ClusterRoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: jenkins-admin
  namespace: jenkins

Шаг 2. Развертывание управляющего узла и агента подключения

Управляющий узел Jenkins разворачивается через манифест Deployment с подключением постоянного тома (PersistentVolumeClaim) для долгосрочного хранения конфигураций, настроек плагинов и истории сборок. Для связи динамических подов с контроллером настраивается внутренний сервис с секретным токеном аутентификации:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-master
  namespace: jenkins
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins-master
  template:
    metadata:
      labels:
        app: jenkins-master
    spec:
      serviceAccountName: jenkins-admin
      containers:
      - name: jenkins
        image: jenkins/jenkins:lts
        ports:
        - containerPort: 8080
        - containerPort: 50000

Для надежного аутентифицированного соединения динамических подов секретный ключ токена сохраняется в объекте Kubernetes Secret и автоматически монтируется в каждый запускаемый под сборщика.

Шаг 3. Конфигурирование пайплайнов в Jenkinsfile

Описание рабочей среды переносится непосредственно в код пайплайна. Для стандартных задач используется декларативный шаблон с одним рабочим контейнером, например, для компиляции и тестирования Java-проектов:

pipeline {
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: maven
    image: maven:3.9-eclipse-temurin-17
    command: ["sleep", "infinity"]
    resources:
      requests:
        memory: "512Mi"
        cpu: "250m"
      limits:
        memory: "1Gi"
        cpu: "1000m"
'''
            defaultContainer 'maven'
        }
    }
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
    }
}

Если проект требует использования одновременно фронтенд- и бэкенд-инструментов, под может содержать несколько контейнеров (например, Maven и Node.js), работающих параллельно в общем сетевом пространстве пода и обращающихся к единой рабочей директории.

Шаг 4. Управление кешем и приватными корпоративными репозиториями

Эфемерность подов означает, что после успешного завершения или отмены задачи под полностью удаляется, а локальный кеш зависимостей теряется. Для работы с приватными корпоративными реестрами (такими как Nexus или Artifactory) конфигурационный файл settings.xml с авторизационными данными сохраняется в Kubernetes Secret и монтируется в контейнер сборщика:

volumeMounts:
- name: maven-settings
  mountPath: /root/.m2/settings.xml
  subPath: settings.xml
volumes:
- name: maven-settings
  secret:
    secretName: maven-settings

Если для команды критически важно сохранять артефакты сборки или промежуточные файлы для отладки в веб-интерфейсе Jenkins, применяются гибридные схемы: компиляция происходит в динамических подах, а артефакты архивируются на статический агент с томом PVC.

Шаг 5. Распределение затрат и финансовый учет по продуктовым командам

Главным стратегическим преимуществом переноса сборщиков в Kubernetes становится возможность точного финансового учета и аллокации инфраструктурных расходов. Запуск подов каждой продуктовой команды в отдельном пространстве имен (например, team-alpha-builds и team-beta-builds) позволяет использовать стандартные биллинговые метрики облачных провайдеров для автоматического распределения затрат.

Для предотвращения ситуации, когда одна команда захватывает все узлы кластера в момент релиза, на каждое пространство имен накладываются жесткие лимиты через объект ResourceQuota:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-alpha-quota
  namespace: team-alpha-builds
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    pods: "50"

Практические результаты и эксплуатационные ограничения

Переход на динамические поды полностью устраняет простаивание серверных мощностей, предотвращает конфликты версий и гарантирует чистую предсказуемую среду для каждого запуска. В качестве эксплуатационных ограничений следует учитывать небольшие задержки при первичном скачивании базовых Docker-образов на новые ноды кластера. Эта проблема успешно решается предзагрузкой частых образов (image pre-pulling) или использованием локальных реестров контейнеров. В результате перенос агентов в Kubernetes дает эластичную современную инфраструктуру с прозрачной экономикой без необходимости переписывать накопленные пайплайны.