Из-за роста инстансов Jenkins команда может страдать от избыточного потребления ресурсов и медлительности конвейера доставки. Выход из этой ситуации — масштабирование. В статье пошагово разбираем, как масштабировать Jenkins с помощью Kubernetes.
![](https://habrastorage.org/getpro/habr/upload_files/ed0/c46/60d/ed0c4660d23d630e3cf3ddaa888a851a.jpg)
Зачем масштабировать Jenkins с помощью Kubernetes
Масштабируемость — способность системы или процесса обрабатывать увеличенный объём операций без ограничений или структурных узких мест. Масштабируя Jenkins, вы получаете возможность:
выполнять больше сборок параллельно;
автоматически заменять повреждённые инстансы;
распределять нагрузку между разными машинами;
уменьшать time to market приложения.
Хотя функция масштабируемости доступна в Jenkins из коробки, сам процесс масштабирования не так прост. Одним из лучших инструментов для управления масштабируемыми решениями считается Kubernetes.
![](https://habrastorage.org/getpro/habr/upload_files/1aa/884/9a1/1aa8849a1899933e44f08e0a285dbc8d.png)
До Jenkins: устанавливаем Kubernetes
Если ваша цель — настроить платформу Kubernetes с нуля поверх реального кластера, стоит начать с официальной документации, так как статья сосредоточена не на установке Kubernetes, а на реализации масштабируемого сервера непрерывной интеграции. Если же вам нужен Kubernetes для тестирования, можете использовать Minikube. Это инструмент, специально разработанный для запуска кластера Kubernetes с одним узлом на локальном компьютере. Он прост в установке, но у вас должен быть установлен VirtualBox.
Если у вас есть платформа UNIX, просто используйте эту команду для установки Minikube:
➜ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
Чтобы запустить Minikube после его установки:
➜ minikube start
Starting local Kubernetes v1.9.0 cluster...
Starting VM..
![](https://habrastorage.org/getpro/habr/upload_files/c54/f1a/4b2/c54f1a4b21d61d02747b020b34cb461b.png)
Чтобы проверить, что Minikube работает:
➜ minikube status
minikube: Running
cluster: Running
kubectl: Correctly Configured: pointing to minikube-vm at 192.168.99.100
Дополнительно нужно установить интерфейс командной строки Kubernetes для конфигурации кластера через консоль:
➜ curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/v1.9.0/bin/darwin/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/
Устанавливаем Jenkins Master
Один из способов установить Jenkins master — создать docker образ на основе базового образа Jenkins из официального репозитория (учитывайте, что Docker должен быть установлен на локальном компьютере). Для этого создайте dockerfile:
➜ vim Dockerfile
Dockerfile:
from jenkins/jenkins:2.60.1
# Distributed Builds plugins
RUN /usr/local/bin/install-plugins.sh ssh-slaves
# install Notifications and Publishing plugins
RUN /usr/local/bin/install-plugins.sh email-ext
RUN /usr/local/bin/install-plugins.sh mailer
RUN /usr/local/bin/install-plugins.sh slack
# Artifacts
RUN /usr/local/bin/install-plugins.sh htmlpublisher
# UI
RUN /usr/local/bin/install-plugins.sh greenballs
RUN /usr/local/bin/install-plugins.sh simple-theme-plugin
# Scaling
RUN /usr/local/bin/install-plugins.sh kubernetes
# install Maven
USER root
RUN apt-get update && apt-get install -y maven
USER jenkins
from [image_name]:[tag] — docker-файл будет основан на существующем образе. Очевидно, что для нашего docker-файла мы берем базовый образ Jenkins, который можно найти в официальном репозитории Docker.
RUN [command] — запускаем команду внутри образа в процессе сборки. Используем её для установки плагинов, которые могут потребоваться для вашего Jenkins master;
USER [user_name]: — команда сообщает, что все приведенные ниже команды будут выполняться под конкретным пользователем. В нашем случае используем стандартного административного пользователя, чтобы иметь возможность устанавливать дополнительные инструменты внутри образа во время сборки.
Ключевой плагин в контексте статьи — Jenkins «Kubernetes». Он позволяет развернуть Jenkins поверх кластера Kubernetes.
После dockerfile вам нужно создать образ, который можно использовать и запускать в кластере Kubernetes. Если вы используете Minikube, не забывайте, что он работает на локальной машине, но внутри виртуальной.
Minikube не видит docker образы, созданные на локальной машине. Чтобы сделать их видимыми, создайте docker образ прямо внутри виртуальной машины Minikube:
➜ eval $(minikube docker-env)
Затем создайте docker образ на основе dockerfile:
➜ docker build -t ybushnev/my-jenkins-image:1.0 .
Sending build context to Docker daemon 5.12kB
Step 1/16 : FROM jenkins/jenkins:2.105
………...
![](https://habrastorage.org/getpro/habr/upload_files/7af/9c1/503/7af9c1503741d68b83a874338e16def0.png)
После завершения процесса сборки проверьте, что созданный образ существует:
![](https://habrastorage.org/getpro/habr/upload_files/b85/be6/03c/b85be603ce93b2d831e108fbf53f33d0.png)
Jenkins master создан и может использоваться в кластере Kubernetes.
Разворачиваем Jenkins на Kubernetes
Чтобы развернуть приложение в Kubernetes, нужно создать конфигурацию развёртывания. Давайте посмотрим на базовую конфигурацию развёртывания для запуска Jenkins в Kubernetes:
➜ vim jenkins-deployment.yaml
jenkins-deployment.yaml:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: jenkins
spec:
replicas: 1
template:
metadata:
labels:
app: jenkins
spec:
containers:
- name: jenkins
image: ybushnev/my-jenkins-image:1.0
env:
- name: JAVA_OPTS
value: -Djenkins.install.runSetupWizard=false
ports:
- name: http-port
containerPort: 8080
- name: jnlp-port
containerPort: 50000
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
volumes:
- name: jenkins-home
emptyDir: {}
Рассмотрим основные параметры в этом файле:
apiVersion указывает, какая версия API Kubernetes будет использоваться;
kind определяет цель yaml файла;
name обозначает имя развёртывания, чтобы идентифицировать его позже в различных других развёртываниях, которые могут возникнуть;
spec отражает спецификацию основных параметров развёртывания и конфигурации;
containers содержит все контейнеры, которые должны быть запущены в указанном развёртывании;
containers.name обозначает имя контейнера развёртывания, чтобы идентифицировать его позже в других различных контейнерах;
image — docker образ, который используется для запуска контейнера;
env — переменные среды, которые передаются внутри контейнера;
ports — секции с портами, которые пересылаются за пределы контейнеров.
volumetMounts — создаётся, чтобы хранить данные вне контейнера.
Давайте установим только что созданное развёртывание в кластер Kubernetes с помощью команды:
➜ kubectl apply -f jenkins-deployment.yaml
deployment "jenkins" created
Внутри Kubernetes есть еще один очень важный термин, о котором вам знать, — Pod. Это основной строительный блок и самая маленькая единица в кластере Kubernetes. Он создаётся, как только вы выполняете развёртывание.
Поскольку каждое развёртывание должно создавать pod, давайте проверим, что у нас есть недавно созданный pod для развёртывания Jenkins:
➜ kubectl describe pod | grep jenkins
![](https://habrastorage.org/getpro/habr/upload_files/0e8/0bf/9c0/0e80bf9c0a7336aa12a57281cb05b014.png)
Чтобы поддерживать постоянное соединение с pod, пока его IP-адрес может меняться, в игру вступает сервис Kubernetes. Он определяет абстракцию между внешним миром и самими pods и предоставляет доступ — обрабатывает все коммуникации в развёртывании.
Чтобы создать сервис, нам нужно определить yaml файл:
➜ vim jenkins-service.yaml
jenkins-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: jenkins
spec:
type: NodePort
ports:
- port: 8080
targetPort: 32592
selector:
app: jenkins
Как только создадите файл, можете запустить его в контейнере Kubernetes с помощью команды:
➜ kubectl create -f jenkins-service.yaml
service "jenkins" created
![](https://habrastorage.org/getpro/habr/upload_files/b18/c20/8ae/b18c208aeb05efd3a88602e84cadc488.png)
Развёртывание и сервис созданы. Теперь откроем панель управления Kubernetes и проверим, что они там:
➜ ~ minikube dashboard
Когда перейдёте в раздел «Обзор», увидите, что развёртывание и модуль «Jenkins» находятся там:
![](https://habrastorage.org/getpro/habr/upload_files/4e0/549/a49/4e0549a49f424330a8d4bce30dce4953.png)
Если зайдёте в pod, можете найти основные журналы Jenkins, которые могут быть очень полезны в случае возникновения проблем во время использования Jenkins CI:
![](https://habrastorage.org/getpro/habr/upload_files/0f4/605/e36/0f4605e36cdb1bde9ba2222452ca0cfc.png)
В качестве окончательной проверки, что Jenkins master установлен, попробуем открыть пользовательский интерфейс Jenkins. Прежде всего, нам нужен порт, который служба Jenkins расширяет за пределами кластера Kubernetes. Узнаем его номер:
➜ kubectl get service
![](https://habrastorage.org/getpro/habr/upload_files/8bd/071/413/8bd07141350e1534dfb224f4c153d63e.png)
Также нужен IP-адрес кластера Kubernetes:
➜ minikube ip
192.168.99.100
В нашем случае результат Jenkins UI URL — 192.168.99.100: 3259.
![](https://habrastorage.org/getpro/habr/upload_files/a76/a35/6ca/a76a356ca93f94f26a75bf8df74c3068.png)
Конфигурация Jenkins Slaves
Теперь настроим Jenkins slave. Поскольку мы установили плагин Kubernetes с помощью dockerfile, нам не нужно ничего устанавливать отдельно.
Чтобы настроить Jenkins slave, нужно знать URL-адрес Kubernetes master и внутренний URL-адрес кластера Jenkins pod. Получить URL-адрес Kubernetes можно с помощью команды:
➜ kubectl cluster-info | grep master
Kubernetes master is running at https://192.168.99.100:8443
URL-адрес Jenkins pod стандартный — 8080. Чтобы получить IP-адрес, нужно:
Узнать идентификатор Jenkins pod:
➜ kubernetes-jenkins-infrastructure kubectl get pods | grep jenkins
jenkins-5fdbf5d7c5-dj2rq 1/1 Running 0 9m
Выполнить команду, которая описывает pods, передающие идентификатор модуля в качестве аргумента. Вы найдёте IP-адрес в выходных данных:
➜ kubernetes-jenkins-infrastructure kubectl describe pod jenkins-5fdbf5d7c5-dj2rq
…..
IP: 172.17.0.4
Теперь можно заполнять конфигурацию плагина Kubernetes. Для этого откройте интерфейс Jenkins, перейдите в раздел «Управление Jenkins -> Configure System -> Cloud -> Kubernetes» и заполните «URL-адрес Kubernetes» и «URL Jenkins», используя значения, полученные на предыдущем шаге:
![](https://habrastorage.org/getpro/habr/upload_files/be5/f34/4fa/be5f344fabe5cb36941249fa7e998e17.png)
В разделе «Kubernetes Pod Template» настройте образ, который будет использоваться для запуска slaves. Если у вас есть требования к slaves, можете создать ещё один dockerfile с соответствующими изменениями так же, как мы делали для Jenkins master. Если у вас нет специфических требований, можете использовать Jenkins slaves образ, доступный в официальном репозитории Docker hub. В разделе «Kubernetes Pod Template» нужно указать:
Kubernetes Pod Template Name: может быть любым и будет отображаться в качестве приставки для уникальных сгенерированных названий slaves, которые будут запускаться автоматически во время сборки.
Docker image: название docker образа, которое будет использоваться в качестве ссылки для запуска нового Jenkins slave.
![](https://habrastorage.org/getpro/habr/upload_files/e3d/f02/d8a/e3df02d8aa331ccbc95907824f155faa.png)
Вся конфигурация на месте, и мы готовы к тестам. Давайте создадим две сборки с одним шагом, который имитирует тайм-аут (скажем, 30 секунд) для выполнения длительной операции:
![](https://habrastorage.org/getpro/habr/upload_files/e1d/c33/3a6/e1dc333a60d2163b4435629864d14aaa.png)
![](https://habrastorage.org/getpro/habr/upload_files/b2a/263/db5/b2a263db509a41e53021fba28ef12fd0.png)
Теперь запустим выполнение для обеих сборок. Вы должны увидеть, что оба плана сборки появляются в окне Build Queue почти сразу:
![](https://habrastorage.org/getpro/habr/upload_files/f72/91f/453/f7291f4530c0f737b9ef56d295ece632.png)
Если вы применили правильную конфигурацию на предыдущих шагах, вы увидите, что у вас есть два дополнительных исполнителя, и оба имеют приставку «jenkins-slave». Это значит, что узлы были автоматически запущены внутри кластера Kubernetes с помощью плагина Jenkins Kubernetes. И самое главное — они были запущены параллельно:
![](https://habrastorage.org/getpro/habr/upload_files/fcd/fbb/c56/fcdfbbc56fa49ac10c9c1b45fecaff78.png)
Также вы можете подтвердить это с помощью панели управления Kubernetes, которая покажет вам пару новых pods:
![](https://habrastorage.org/getpro/habr/upload_files/1fc/dce/5ed/1fcdce5ed41f4efc7724c124df647e0a.png)
После завершения сборок вы увидите, что оба исполнителя сборки удалены и больше не доступны внутри кластера:
![](https://habrastorage.org/getpro/habr/upload_files/7c1/8aa/a1b/7c18aaa1bcab49ed7eb508a1c1e1170b.png)
Так выглядит процесс масштабирования Jenkins с помощью Kubernetes. Напоминаем, что Jenkins можно использовать для добавления всех ваших тестов, включая нагрузочные, в непрерывную интеграцию.
![](https://habrastorage.org/getpro/habr/upload_files/3d8/2b0/5d1/3d82b05d19c5bd65fa2a0445555b7ec8.png)
Материал подготовлен на основе статьи «Jenkins + Kubernetes: How to Set Up Jenkins on Top of a Kubernetes Cluster»
Для тех, кто хочет разобраться в Jenkins, Kubernetes и других DevOps-инструментах
«DevOps Tools для разработчиков» — практический курс, на котором разбираем основные эксплуатационные инструменты и рассказываем, как они связаны архитектурно и как выглядит инфраструктура в целом.
Вы получите базовое понимание DevOps-инструментов. Разберётесь, в чём разница между Gitlab CI и Jenkins, RabbitMQ и Apache Kafka и др., и научитесь подобирать лучшее решение под свою задачу.