Введение

Непрерывная интеграция и непрерывное развертывание  —  сокращенно CI/CD  —  важны при разработке современного ПО: ими упрощаются автоматизированная интеграция кода и выпуск надежных приложений.

Jenkins  —  ведущий инструмент для создания конвейеров CI/CD, славится гибкостью и широкими возможностями плагинов.

Выполним с его помощью полную настройку конвейера CI/CD: от конфигурирования и интеграции Jenkins с системами контроля версий до оркестрации сборок, тестов и развертываний. Цель  —  усовершенствовать процесс разработки и выпуска ПО.

Применяемые инструменты и технологии:

  • GitHub для контроля версий;
  • Maven для управления проектами и для сборок;
  • SonarQube для анализа качества кода;
  • Docker для контейнеризации;
  • Jenkins для непрерывной интеграции;
  • ArgoCD и Helm для управления развертыванием Kubernetes;
  • Kubernetes для оркестрации контейнеров.

Настройка Git

Заложим основу для конвейера Jenkins с приложением Java, сконфигурируем Git:

  1. Создаем приватный гит-репозиторий:
  • В своей учетной записи на гит-хостинговой платформе  —  GitHub или GitLab  —  создаем репозиторий, для защиты кода устанавливаем видимость private.

2. Генерируем персональный токен доступа:

  • В настройках учетной записи  —  обычно внутри профиля или в выпадающем меню  — находим раздел Developer settings («Настройки разработчика») или Personal access tokens («Персональные токены доступа»).
  • Создаем токен, присваиваем разрешения, например repo для доступа к репозиториям.
  • Сохраняем токен, он понадобится для настройки доступа в конвейере Jenkins.

3. Клонируем репозиторий локально:

  • Находим исходный код, в Git Bash или терминале переходим в каталог, куда клонируется репозиторий.
  • Вводим команду ниже, заменив <URL> на url-адрес репозитория:
git clone <URL>

Создание экземпляра EC2

Этот этап автоматизируется с помощью Terraform, но ради простоты выполним его вручную.

  1. Под своими данными учетной записи заходим на консоль управления AWS. Нет учетной записи? Создаем.

2. Наверху, в меню Services («Службы»), переходим в раздел Compute, нажимаем EC2 и попадаем в дашборд EC2.

3. Запускаем экземпляр:

  • Нажимая кнопку Launch Instances («Запустить экземпляры»), запускаем процесс создания экземпляра EC2.

4. Добавляем теги:

  • Для совершенствования организации и управления добавляем экземпляру теги и названия.

5. Выбираем AMI, образ машины Amazon:

  • Из списка AMI, то есть преднастроенных шаблонов серверов с различными операционными системами и настройками, выбираем AMI под свои требования.
  • Простейший вариант для начинающих  —  Amazon Linux AMI или базовый сервер Ubuntu.

6. Выбираем тип экземпляра:

  • Тип экземпляра выбирается под свои требования.
  • Вариант по умолчанию  —  обычно это экземпляр t2.micro  —  хорош для тестирования и небольших рабочих нагрузок, он условно-бесплатного уровня.
  • Мы выбрали экземпляр t2.large с двумя виртуальными процессорами и 8 ГиБ памяти  —  для умеренных рабочих нагрузок.
  • Этот тип экземпляра платный, поэтому для эффективного управления своим бюджетом рекомендуем ознакомиться с текущими ценами в AWS.

7. Создаем пару ключей:

  • Создаем пару ключей для SSH-доступа к экземпляру или используем имеющуюся.
  • Загружаем .pem-файл с приватным ключом и сохраняем его. После создания он не загружается повторно.

8. Настраиваем данные экземпляра:

  • При необходимости настраиваются данные экземпляра: сетевые параметры, подсети, роль IAM и т. д. Пока оставляем настройки по умолчанию.

9. Настраиваем группу безопасности:

  • Группа безопасности  —  это как виртуальный брандмауэр, которым контролируется разрешенный входящий и исходящий трафик экземпляра.
  • Создается новая группа безопасности либо выбирается имеющаяся. Открываем входящие порты, например SSH-порт 22, пользовательские TCP 8080 и 9000.

10. Добавляем хранилище:

  • Указываем размер корневого тома  —  значение по умолчанию обычно применяют для тестирования.

11. Проверяем и запускаем:

  • Проверяем настройки экземпляра: данные AMI, тип экземпляра, группы безопасности, пары ключей.
  • Запускаем, нажимая Launch («Запустить»):

Получение доступа к экземпляру

После запуска экземпляр за несколько минут инициализируется.

Дальше подключаемся к экземпляру по SSH с помощью загруженного .pem-файла и Mobaxterm  —  для компьютеров с Windows:

  • Устанавливаем и открываем MobaXterm на рабочем столе или в меню «Пуск».
  • Нажимаем кнопку Session («Сеанс»), затем выбираем SSH.
  • Вводим IP-адрес или имя хоста сервера, указываем имя пользователя.
  • Нажимаем Advanced SSH settings («Расширенные настройки SSH»), ставим галочку в Use private key («Использовать приватный ключ») и выбираем пару приватных ключей, задействованных ранее в экземпляре.
  • Нажимая OK, подключаемся:

Настройка Jenkins

Устанавливаем Java:

Прежде чем запускать Jenkins, установим Java на сервере. Jenkins совместим и с Oracle Java, но оптимальное в целом взаимодействие у него с OpenJDK.

Устанавливаем Java на экземпляр, к которому подключились по SSH:

sudo apt update
sudo apt install openjdk-11-jdk
java -version

Устанавливаем Jenkins:

Имеется два варианта установки: с помощью скрипта или выполнением команд вручную.

Первый эффективен и воспроизводим, особенно если планируется развертывать Jenkins многократно или применять одну настройку в разных средах.

  • В vim или любом другом редакторе создаем файл скрипта:
vim install_jenkins.sh
  • Нажав i, переходим в режим вставки и пишем скрипт:
#!/bin/bash
# Загружаем GPG-ключ для Jenkins
sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \
https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key

# Добавляем репозиторий Jenkins в источники диспетчера пакетов
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
/etc/apt/sources.list.d/jenkins.list > /dev/null

# Обновляем репозитории диспетчера пакетов
sudo apt-get update

# Устанавливаем Jenkins
sudo apt-get install jenkins -y
  • Вводим:wq и нажимаем Enter. Этой командой записываем w в файл изменения и выходим q из редактора.
  • Делаем файл исполняемым:
chmod +x install_jenkins.sh
  • Теперь для установки Jenkins запускаем этот исполняемый скрипт:
./install_jenkins.sh

Настраиваем параметры брандмауэра:

Чтобы обеспечить доступ к Jenkins через браузер, важно корректно настроить параметры брандмауэра.

По умолчанию Jenkins запускается на порту 8080. Следует разрешить входящий трафик через этот порт в настройках группы безопасности.

Получаем доступ к пользовательскому интерфейсу Jenkins:

Доступ к ПИ Jenkins получаем, вводя в браузере IP-адрес экземпляра и :8080, например http://192.168.1.2:8080. То есть 192.168.1.2 заменяем фактическим IP-адресом сервера.

Разблокируем Jenkins исходным паролем администратора:

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

Устанавливаем предлагаемые плагины:

  • Разблокировав Jenkins, установим предлагаемые плагины или выберем конкретные плагины вручную.
  • Чтобы автоматически установить стандартный набор плагинов, рекомендуемый большинству пользователей, нажимаем Install suggested plugins («Установить предлагаемые плагины»):

Создаем пользователя-администратора:

  • После установки плагина предлагается создать пользователя с правами администратора для Jenkins.
  • Заполняем форму, указав имя пользователя, пароль, полное имя и электронную почту, нажимаем Save and Continue («Сохранить и продолжить»):

Jenkins готов:

  • Настроим URL-адрес экземпляра Jenkins.
  • Вводится URL-адрес по умолчанию  —  на основе IP-адреса и порта сервера.
  • Нажимая Start using Jenkins («Начать использовать Jenkins»), завершаем настройку и оказываемся в дашборде Jenkins:

Устанавливаем необходимые плагины:

  • В интерфейсе Jenkins дашборда переходим в Manage Jenkins («Управление Jenkins») > Plugins («Плагины»).
  • Находим и устанавливаем плагины docker pipeline и sonarqube scanner, при необходимости перезапускаем Jenkins:

Задача компиляции

  • В главном окне дашборда Jenkins нажимаем New Item («Новый элемент»).
  • Называем конвейер, выбираем тип проекта Pipeline («Конвейер»), нажимаем OK:

Настраиваем конвейер:

  • Нажимаем на созданную задачу и прокручиваем вниз до раздела Pipeline («Конвейер») на экране настройки.
  • Выбираем Pipeline script («Скрипт конвейера») или Pipeline script from SCM («Скрипт конвейера из SCM»).

В первом варианте пишется Groovy-скрипт непосредственно в интерфейсе Jenkins, во втором скрипт извлекается из SCM  —  системы управления исходным кодом.

  • Затем выбираем тип SCM, например Git.
  • Вводим URL-адрес репозитория, в котором содержится Jenkinsfile.
  • Если репозиторий приватный, добавляем учетные данные.
  • Указываем ветку для сборки: */main или */master.
  • Если Jenkinsfile находится в подкаталоге или назван по-другому, указываем путь, по умолчанию  —  Jenkinsfile:

Перезапускаем Jenkins:

  • Чтобы корректно применить изменения или обновления настроек, перезапускаем Jenkins: в Manage Jenkins на боковой панели дашборда выбираем Reload Configuration from Disk («Перезагрузить конфигурацию с диска») или Restart Safely («Перезагрузить безопасно»).

Настройка сервера Sonarqube

Процесс настройки упрощается установкой SonarQube как контейнера Docker. Это популярный вариант, с которым легче управление и масштабирование.

Потребуется: установить на сервере Docker.

Установка Docker:

  • В vim или любом другом редакторе создаем файл скрипта:
vim install_docker.sh
  • Нажав i, переходим в режим вставки и пишем скрипт:
#!/bin/bash

# Обновляем репозитории диспетчера пакетов
sudo apt-get update

# Устанавливаем необходимые зависимости
sudo apt-get install -y ca-certificates curl

# Создаем папку GPG-ключа для Docker
sudo install -m 0755 -d /etc/apt/keyrings

# Загружаем GPG-ключ для Docker
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc

# Обеспечиваем ключу корректные разрешения
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Добавляем репозиторий Docker в источники Apt
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Обновляем репозитории диспетчера пакетов
sudo apt-get update

sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  • Нажимая Esc, выходим в обычный режим, вводим :wq и нажимаем Enter.
  • Делаем файл исполняемым:
chmod +x install_docker.sh
  • Теперь для установки Docker запускаем этот исполняемый скрипт:
./install_docker.sh

Устанавливаем Sonarqube:

  • Извлекаем из Docker Hub официальный образ Docker для SonarQube:
docker pull sonarqube
  • Запускаем SonarQube в контейнере Docker:
docker run -d --name sonarqube -p 9000:9000 sonarqube

По умолчанию SonarQube запускается на порту 9000. Обеспечим доступ к дашборду SonarQube, разрешив в брандмауэре входящий трафик через этот порт.

Доступ к SonarQube получаем, вводя в браузере http://<your_instance_ip>:9000 и заменяя <your_instance_ip> IP-адресом сервера.

Вот учетные данные по умолчанию для входа в SonarQube:

  • Имя пользователя: admin
  • Пароль: admin

После первой настройки их рекомендуется сменить  —  по соображениям безопасности.

Интегрируем с Jenkins:

  • Устанавливаем сканер SonarQube для плагина Jenkins.
  • В дашборде SonarQube переходим в My Account («Моя учетная запись») > Security («Безопасность») и нажимаем Generate Token («Сгенерировать токен»).
  • Указываем название токена, нажимаем Generate («Сгенерировать»), сгенерированный токен копируем.

Добавляем токен SonarQube как учетные данные в Jenkins:

  • В Jenkins переходим в Manage Jenkins > Credentials («Учетные данные») > System («Система») > Global credentials («Глобальные учетные данные») или переходим к учетным данным проекта.
  • Нажимаем Add Credentials («Добавить учетные данные»).
  • В типе учетных данных выбираем Secret text («Секретный текст»).
  • В поле Secret вставляем токен аутентификации SonarQube.
  • Дополнительно указываем идентификатор и описание учетных данных.
  • Нажимая Create, сохраняем учетные данные.

Настраиваем в Jenkins сканер SonarQube:

  • В разделе для анализа SonarQube настроек задачи Jenkins указываем url-адрес сервера SonarQube, например http://<your_instance_ip>:9000, заменяя <your_instance_ip> IP-адресом сервера.
  • Токен аутентификации  —  добавленный ранее токен SonarQube.

Учетные данные

Корректно настраиваем все необходимые учетные данные для конвейера CI/CD: аутентификации SonarQube и тиг-репозитория, доступа к Docker Hub:

Jenkinsfile

Jenkinsfile  —  это текстовый файл, которым определяется конфигурация конвейера Jenkins. Этот файл написан на Groovy, скриптовом языке для платформы Java.

В Jenkinsfile указываются шаги, этапы и действия, выполняемые Jenkins при запуске задачи конвейера.

Внимание: некоторые части Jenkinsfile потребуется заменить своими данными, в том числе учетными.

Этапы конвейера:

Этап 1. Извлечение исходного кода из Git.

Этап 2. Сборка Java-приложения с помощью Maven.

Этап 3. Запуск модульных тестов с JUnit и Mockito.

Этап 4. Запуск анализа SonarQube для проверки качества кода.

Этап 5. Упаковывание приложения в jar-файл.

Этап 6. Развертывание приложения в тестовой среде с помощью Helm.

Этап 7. Запуск в развернутом приложении пользовательских тестов приемки.

Этап 8. Перевод приложения в производственную среду с помощью Helm.

pipeline {
agent {
docker {
image 'abhishekf5/maven-abhishek-docker-agent:v1'
args '--user root -v /var/run/docker.sock:/var/run/docker.sock' // подключается сокет Docker для доступа к демону Docker хоста
}
}
stages {
stage('Checkout') {
steps {
sh 'echo passed'
//гит-ветка: 'main', url-адрес: 'https://github.com/wangoimwangi/jenkins-CICD.git'
}
}
stage('Build and Test') {
steps {
sh 'ls -ltr'
// проект собирается, и создается jar-файл
sh 'cd spring-boot-app && mvn clean package'
}
}
stage('Static Code Analysis') {
environment {
SONAR_URL = "http://54.252.140.131:9000"
}
steps {
withCredentials([string(credentialsId: 'sonarqube', variable: 'SONAR_AUTH_TOKEN')]) {
sh 'cd spring-boot-app && mvn sonar:sonar -Dsonar.login=$SONAR_AUTH_TOKEN -Dsonar.host.url=${SONAR_URL}'
}
}
}
stage('Build and Push Docker Image') {
environment {
DOCKER_IMAGE = "ultimate-cicd:${BUILD_NUMBER}"
// DOCKERFILE_LOCATION = "spring-boot-app/Dockerfile"
REGISTRY_CREDENTIALS = credentials('docker-cred')
}
steps {
script {
sh 'cd spring-boot-app && docker build -t ${DOCKER_IMAGE} .'
def dockerImage = docker.image("${DOCKER_IMAGE}")
docker.withRegistry('https://index.docker.io/v1/', "docker-cred") {
dockerImage.push()
}
}
}
}
stage('Update Deployment File') {
environment {
GIT_REPO_NAME = "jenkins-CICD"
GIT_USER_NAME = "wangoimwangi"
}
steps {
withCredentials([string(credentialsId: 'github', variable: 'GITHUB_TOKEN')]) {
sh '''
git config user.email "[email protected]"
git config user.name "Maria"
BUILD_NUMBER=${BUILD_NUMBER}
sed -i "s/replaceImageTag/${BUILD_NUMBER}/g" spring-boot-app-manifests/deployment.yml
git add spring-boot-app-manifests/deployment.yml
git commit -m "Update deployment image to version ${BUILD_NUMBER}"
git push @github.com/${GIT_USER_NAME}/${GIT_REPO_NAME">https://${GITHUB_TOKEN}@github.com/${GIT_USER_NAME}/${GIT_REPO_NAME} HEAD:main
'''
}
}
}
}
}
  • Нажимая Build Now («Запустить сборку»), активируем сборку задачи конвейера: Jenkinsfile извлекается из репозитория и выполняется в Jenkins, как это определено.
  • Ход выполнения задачи конвейера отслеживаем в дашборде Jenkins.
  • Подробные логи и обновления статуса по мере выполнения каждого этапа конвейера просматриваем внутри задачи.
  • Если во время выполнения конвейера появляются проблемы, ищем ошибки в Jenkinsfile и настройках задачи.
  • В консольном выводе и логах содержится дополнительная информация о любых сбоях.

А в SonarQube  —  отчет о выполнении конвейера.

Настройка ArgoCD

Непрерывное развертывание конвейеров CI/CD с автоматизированием развертываний в Kubernetes контролируется в ArgoCD.

Выполняется локальное развертывание с Minikube или облачное с Amazon EKS.

Потребуется:

  • На компьютере с Windows устанавливаем VirtualBox или Hyper-V для виртуализации, это требование Minikube.

Устанавливаем Minikube:

  • Загружаем и устанавливаем Minikube согласно инструкциям по конкретной ОС из официальной документации Minikube.
  • Запускаем локальный кластер Kubernetes:
minikube start

Устанавливаем Kubectl:

  • Загружаем последнюю версию kubectl с официальной страницы выпуска Kubernetes.
  • Добавляем kubectl в PATH, чтобы запускать его в командной строке откуда угодно.

Установка оператора ArgoCD

Argo CD устанавливается в Kubernetes с помощью оператора Argo CD, которым автоматизируются развертывание экземпляров Argo CD и управление ими.

  • На официальной странице Operator Hub в строке поиска вводим Argo CD и нажимаем Install («Установить»).
  • Запускаем команды:
#Устанавливаем диспетчер жизненного цикла оператора — инструмент управления операторами, запускаемыми в кластере.

$ curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.27.0/install.sh | bash -s v0.27.0
#Устанавливаем оператор AgroCD
kubectl create -f https://operatorhub.io/install/argocd-operator.yaml
  • Этот оператор установится в пространстве имен operators и будет доступен из всех пространств имен кластера.
# наблюдаем, как появляется оператор 
$ kubectl get csv -n operators

Настройка контроллера ArgoCD

  • В операторе Argo CD на странице Operator Hub прокручиваем вниз до Operator Documentation («Документация оператора»).
  • Нажимаем Usage («Использование»), затем Basics («Основы»).
  • Копируем имеющуюся yaml-конфигурацию для развертывания Argo CD в кластере Kubernetes.
  • Чтобы определить экземпляр Argo CD, создаем файл vim argocd-basic.yml с таким содержимым:
apiVersion: argoproj.io/v1alpha1
kind: ArgoCD
metadata:
name: example-argocd
labels:
example: basic
spec: {}
  • Применяем конфигурацию:
kubectl apply -f argocd-basic.yml

Настройка пользовательского интерфейса ArgoCD

  • Чтобы получить доступ к ПИ сервера Argo CD через браузер, меняем тип службы с ClusterIP на NodePort:
kubectl get svc
  • В Minikube генерируется url-адрес для прямого доступа к серверу Argo CD через браузер:
minikube service argocd-server --url
  • url-адрес предыдущей команды копируем в браузер и оказываемся в ПИ Argo CD:
  • Имя пользователя по умолчанию  —  admin. Пароль администратора извлекаем из секретов Kubernetes:
kubectl get secret
  • Отредактировав секрет example-argocd-cluster, копируем пароль администратора:
kubectl edit secret example-argocd-cluster
  • Секреты K8s шифруются в base 64, поэтому декодируем так:
echo <encoded password here>= | base64 -d
  • Входим в ПИ Argo CD под именем пользователя admin и паролем, полученным на предыдущем этапе:

Развертывание с Argo CD

  • В ПИ Argo CD нажимаем Create Application («Создать приложение»).
  • Вводим обязательную информацию о приложении:

Application Name: вводим информативное название приложения.

Project Name: указываем название проекта, к которому относится приложение.

Sync: для автоматической синхронизации выбираем Automatic.

Repository URL: вводим url-адрес гит-репозитория, где содержится код приложения.

Path: указываем путь к файлам развертывания в репозитории.

Destination: вводим url-адрес кластера Kubernetes, например https://kubernetes.default.svc.

Namespace: указываем пространство имен Kubernetes, в котором развернем приложение.

  • Теперь нажимаем Create, и с помощью Argo CD в кластере Kubernetes на основе этой конфигурации автоматически создастся приложение:

Заключение

Интегрировав GitHub, Maven, SonarQube, Docker, Jenkins, Argo CD, Helm и Kubernetes в конвейер CI/CD, мы повысили эффективность и надежность программной разработки: благодаря оптимизированию процессов ускорили разработку и выпуск, увеличили качество ПО.

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

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Mary Wangoi: End-to-End CI/CD Pipeline Implementation

Предыдущая статьяИнтеллектуальная синергия: динамические отношения между искусственным и человеческим интеллектом