Связка jenkins kubernetes решает это радикально. Идея простая до гениальности: под каждую сборку Kubernetes поднимает свежий эфемерный pod, агент в нем подключается к контроллеру, делает работу и сразу после удаляется. Никакого общего состояния, никакого простоя, никаких "грязных" нод. Это и есть cloud-native подход, которого в книге Ластера 2018 года еще не было как стандарта - тогда динамические агенты считались экзотикой, а сегодня это база масштабируемого Jenkins.
Как работает kubernetes-плагин и эфемерные pod-агенты
За всю магию отвечает kubernetes-plugin. Логика такая. Контроллер видит, что в очереди появилась задача с меткой (label), под которую настроен pod-шаблон. Плагин через Kubernetes API создает pod по этому шаблону. Внутри pod обязательно есть контейнер агента (исторически он называется jnlp - там запускается inbound-агент, который сам стучится на контроллер), плюс любые твои сборочные контейнеры: maven, node, docker-cli, kubectl, что угодно. Pod регистрируется как агент, забирает задачу, выполняет шаги. Как только сборка закончилась (или истек idle-таймаут), pod уничтожается.
Что это дает на практике:
- Эластичность. Прилетело 50 сборок одновременно - кластер поднимет 50 pod (в пределах квот). Тихо ночью - ноль агентов, ноль трат. С автоскейлером узлов кластер сам докупает железо под пик и отдает обратно.
- Идеальная изоляция. Каждая сборка в своем pod со своей файловой системой и сетевым неймспейсом. Сборки физически не могут испортить состояние друг другу.
- Воспроизводимость. Окружение описано в YAML и лежит рядом с кодом. Никакого ручного доустанавливания пакетов на агенте - что в шаблоне, то и в сборке.

Запуск Jenkins-контроллера в кластере через Helm
Прежде чем раздавать pod-агенты, сам контроллер обычно тоже живет в кластере. Канонический способ поставить jenkins в kubernetes - официальный Helm-чарт. Он сразу настраивает ServiceAccount с правами на создание pod, ставит kubernetes-plugin и подключает Configuration as Code (JCasC), так что облако агентов конфигурируется кодом, а не кликами в UI.
Код: Выделить всё
helm repo add jenkins https://charts.jenkins.io
helm repo update
helm upgrade --install jenkins jenkins/jenkins \
--namespace jenkins --create-namespace \
-f values.yaml
Код: Выделить всё
controller:
JCasC:
configScripts:
kube-cloud: |
jenkins:
clouds:
- kubernetes:
name: "k8s"
namespace: "jenkins"
jenkinsUrl: "http://jenkins.jenkins.svc.cluster.local:8080"
containerCapStr: "50"
templates:
- name: "default"
label: "k8s-agent"
containers:
- name: "jnlp"
image: "jenkins/inbound-agent:latest-jdk21"
Практика: pod-агенты в Jenkinsfile (jenkins pod agent на деле)
Самый чистый способ 2026 года - описать pod прямо в pipeline через declarative-блок agent с kubernetes и сырым YAML. Сборочные контейнеры объявляешь обычным Kubernetes-манифестом, а шаги загоняешь в нужный контейнер директивой container. Вот рабочий пример сборки и публикации образа (jenkins docker kubernetes - классический сценарий, только docker-демона тут нет, образ собираем kaniko, без привилегий):
Код: Выделить всё
pipeline {
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.9-eclipse-temurin-21
command: ["sleep"]
args: ["infinity"]
- name: kaniko
image: gcr.io/kaniko-project/executor:debug
command: ["sleep"]
args: ["infinity"]
'''
defaultContainer 'maven'
retries 2
}
}
stages {
stage('Build & Test') {
steps {
sh 'mvn -B clean verify'
}
}
stage('Image') {
steps {
container('kaniko') {
sh '''
/kaniko/executor \
--context `pwd` \
--dockerfile Dockerfile \
--destination registry.cyberlake.ru/app:$BUILD_NUMBER
'''
}
}
}
}
}
Если шаблон используется в нескольких пайплайнах, выноси его в общий podTemplate (scripted-стиль), где динамика уместна. Важная деталь: podTemplate создает эфемерный шаблон только на время своего блока и удаляет его сразу после - ровно та самая одноразовость:
Код: Выделить всё
podTemplate(yaml: '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: node
image: node:22-bookworm
command: ["sleep"]
args: ["infinity"]
''') {
node(POD_LABEL) {
container('node') {
checkout scm
sh 'npm ci && npm test'
}
}
}
Типичные грабли
- Забыли command/args в сборочном контейнере. Если контейнер с образом maven просто запустится и завершится, pod упадет в CrashLoopBackOff. Держи контейнеры живыми через sleep infinity - тогда Jenkins выполняет в них шаги.
- Нет прав у ServiceAccount. Контроллер должен иметь RBAC-права на create/delete/watch pod в нужном namespace. Helm-чарт это настраивает, но при ручной установке легко забыть Role и RoleBinding - агенты просто не поднимутся.
- Неверный jenkinsUrl. Если внутри кластера агент не может достучаться до контроллера (указали внешний адрес или закрыли порт inbound-агента), pod создается, висит и отваливается по таймауту. Используй внутренний svc-адрес.
- Слишком жирный pod без лимитов. Без resources requests/limits Kubernetes может выселить агент в середине сборки. Указывай ресурсы для каждого контейнера.
- Ставка на Blue Ocean для визуализации. Blue Ocean с 2023 в режиме поддержки - только security-фиксы, новых фич не будет. Это наследие; смотри сборки в штатном Pipeline UI, не строй процессы вокруг него.
Мини-лаба
- Подними тестовый кластер (kind или minikube) и поставь контроллер Helm-чартом в namespace jenkins.
- Проверь, что в Manage Jenkins появилось облако k8s (через JCasC), и запусти простейший pipeline с agent kubernetes и одним контейнером alpine, выполнив sh 'echo hello && hostname'.
- Запусти сборку и параллельно следи за pod: kubectl get pods -n jenkins -w. Убедись, что pod рождается на старте и исчезает после.
- Запусти 5 сборок разом и посмотри, как кластер поднимает несколько pod одновременно - это та самая эластичность вживую.
- Зачем в pod-шаблоне контейнеру задают command sleep infinity и что будет без этого?
- Чем declarative-блок agent kubernetes отличается от шага podTemplate и когда выбирать второй?
- Какие права в кластере нужны контроллеру, чтобы поднимать эфемерные агенты, и кто их настраивает при установке через Helm?
- Почему jenkinsUrl должен указывать на внутренний адрес сервиса, а не на внешний домен?
Динамические pod-агенты превращают Jenkins из парка вечно живых нод в эластичную фабрику одноразовых окружений: pod под сборку, чистая изоляция, оплата только за работу. Контроллер ставим Helm-чартом, облако описываем через JCasC, окружение - YAML рядом с кодом. Это и есть зрелый cloud-native Jenkins 2026 года, который масштабируется вместе с твоей нагрузкой, а не упирается в нее.