Из-за роста инстансов Jenkins команда может страдать от избыточного потребления ресурсов и медлительности конвейера доставки. Выход из этой ситуации — масштабирование. В статье пошагово разбираем, как масштабировать Jenkins с помощью Kubernetes.

Зачем масштабировать Jenkins с помощью Kubernetes

Масштабируемость — способность системы или процесса обрабатывать увеличенный объём операций без ограничений или структурных узких мест. Масштабируя Jenkins, вы получаете возможность:

  • выполнять больше сборок параллельно;

  • автоматически заменять повреждённые инстансы;

  • распределять нагрузку между разными машинами;

  • уменьшать time to market приложения. 

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

«CI/CD с Jenkins»

До 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..

Чтобы проверить, что 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
………...

После завершения процесса сборки проверьте, что созданный образ существует:

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

Чтобы поддерживать постоянное соединение с 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: 8080
  selector:
    app: jenkins

Как только создадите файл, можете запустить его в контейнере Kubernetes с помощью команды:

➜  kubectl create -f jenkins-service.yaml
service "jenkins" created

Развёртывание и сервис созданы. Теперь откроем панель управления Kubernetes и проверим, что они там:

➜  ~ minikube dashboard

Когда перейдёте в раздел «Обзор», увидите, что развёртывание и модуль «Jenkins» находятся там:

Если зайдёте в pod, можете найти основные журналы Jenkins, которые могут быть очень полезны в случае возникновения  проблем во время использования Jenkins CI:

В качестве окончательной проверки, что Jenkins master установлен, попробуем открыть пользовательский интерфейс Jenkins. Прежде всего, нам нужен порт, который служба Jenkins расширяет за пределами кластера Kubernetes. Узнаем его номер:

➜   kubectl get service

Также нужен IP-адрес кластера Kubernetes:

➜ minikube ip

192.168.99.100

В нашем случае результат Jenkins UI URL — 192.168.99.100: 3259.

Конфигурация 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-адрес, нужно:

  1. Узнать идентификатор Jenkins pod:

➜  kubernetes-jenkins-infrastructure kubectl get pods | grep jenkins 
jenkins-5fdbf5d7c5-dj2rq   1/1       Running   0          9m
  1. Выполнить команду, которая описывает 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», используя значения, полученные на предыдущем шаге:

В разделе «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.

Вся конфигурация на месте, и мы готовы к тестам. Давайте создадим две сборки с одним шагом, который имитирует тайм-аут (скажем, 30 секунд) для выполнения длительной операции:

Теперь запустим выполнение для обеих сборок. Вы должны увидеть, что оба плана сборки появляются в окне Build Queue почти сразу:

Если вы применили правильную конфигурацию на предыдущих шагах, вы увидите, что у вас есть два дополнительных исполнителя, и оба имеют приставку «jenkins-slave». Это значит, что узлы были автоматически запущены внутри кластера Kubernetes с помощью плагина Jenkins Kubernetes. И самое главное — они были запущены параллельно:

Также вы можете подтвердить это с помощью панели управления Kubernetes, которая покажет вам пару новых pods:

После завершения сборок вы увидите, что оба исполнителя сборки удалены и больше не доступны внутри кластера:

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

«CI/CD с Jenkins»

Материал подготовлен на основе статьи «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 и др., и научитесь подобирать лучшее решение под свою задачу. 

Ознакомиться с программой и записаться

Комментарии (0)