В современном DevOps для эффективного, надежного и последовательного развертывания программного обеспечения важна автоматизация. Весь процесс разработки и выпуска ПО оптимизируется при помощи мощного инструмента GitLab CI/CD. Развернем с ним приложение Java в мультикластере Kubernetes, управляемом на AWS и настраиваемом в eksctl. Рассмотрим процесс от создания кластера Kubernetes до развертывания контейнеризованного приложения Java, попутно интегрируя инструменты DevOps Trivy и SonarQube.
Рабочий процесс пошагово

Обзор проекта
- Регистрация экземпляра AWS в качестве GitLab Runner
- Создание конвейера GitLab CI/CD
- Модульное тестирование с Maven
- Сканирование зависимостей с Trivy
- Анализ качества кода с SonarQube
- Сборка и контейнеризация приложения
- Сканирование образа контейнера с Trivy
- Отправка образа контейнера в реестр контейнеров GitLab
- Развертывание приложения в Kubernetes
- Настройка кластера AWS EKS с помощью
eksctl
- Подключение кластера EKS к GitLab
- Запуск конвейера
Шаг 1. Создание проекта в Gitlab

Шаг 2. Настройка экземпляра AWS как агента Gitlab
- Заходим на консоль управления AWS.
- Запускаем экземпляр EC2 с такими характеристиками:
- AMI — образ машины Amazon: выбираем Ubuntu или Amazon Linux.
- Тип экземпляра: выбираем его под требования задания, например t2.micro для тестирования.
- Группа безопасности: разрешаем экземпляру SSH-доступ.




Установка GitLab Runner на экземпляр EC2
- Подключаемся по SSH к экземпляру EC2.
2. Устанавливаем GitLab Runner:
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
sudo chmod +x /usr/local/bin/gitlab-runner
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner start

Регистрация GitLab Runner в проекте
- Чтобы зарегистрировать этот экземпляр в качестве GitLab Runner проекта, нужен токен аутентификации.
- Переходим в Project > settings > CI/CD > Runners.

- Указываем соответствующее название тега:


- Регистрируем экземпляр такой командой:


sudo gitlab-runner run


Следуем инструкциям:
- Вводим URL-адрес экземпляра GitLab:
https://gitlab.com/
. - Указываем исполнителя: ради простоты выбираем
shell
, хотя можно воспользоваться Docker или другими исполнителями. - Проверяем в файле
/home/ubuntu/.gitlab-runner/config.toml
.
Шаг 3. Создание конвейера GitLab CI/CD
Подготовив инфраструктуру, приступим к определению конвейера GitLab CI/CD в файле .gitlab-ci.yml
. Этапы конвейера: тестирование, сканирование, сборка, развертывание приложения Java и другие.
- Клонируем репозиторий в локальной среде:


2. Добавляем код и отправляем в репозиторий Github:




Шаг 4. Настройка конвейера: .gitlab-ci.yml
1. Этапы
- Сначала задаем в файле этапы:

2. Необходимые инструменты
- Прежде чем переходить к проекту, устанавливаем инструменты:
- sudo apt install -y openjdk-17-jre-headless
- sudo apt install -y maven
- sudo apt-get install -y wget apt-transport-https gnupg lsb-release
- wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
- echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
- sudo apt -y install docker.io && chmod 666 /var/run/docker.sock
- sudo apt-get update && sudo apt-get install -y trivy
- sudo snap install kubectl --classic

- Для этого предоставим пользователю
gitlab-runner
права суперпользователя, иначе эти команды не выполнятся. - Переходим в папку
/etc/sudoers.d
и редактируем файл ниже:

3. Модульное тестирование с Maven
Это первый этап, которым обеспечивается надежность приложения. Для запуска модульных тестов привлекается Maven:
mvn test
- Этой командой компилируется код, запускаются определенные в проекте тесты. В выводе выявляются сбои или проблемы, которые необходимо устранить.

4. Сканирование зависимостей с Trivy
- Trivy — это сканер уязвимостей для образов контейнеров, файловых систем, гит-репозиториев. Просканируем им зависимости приложения Java:
trivy fs --format table -o fs.html .
- Этой командой в текущем каталоге сканируются уязвимости применяемых в приложении зависимостей, вывод сохраняется в файле
fs.html
. - Это важный этап для обеспечения безопасности проекта. Чтобы получить вывод, после мы «артефактируем» файл
fs.html
.

- Запуская его, получаем примерно такой вывод:



5. Анализ качества кода с SonarQube
- SonarQube — инструмент анализа исходного кода на предмет выявления багов, уязвимостей и кода с запашком.
- Интегрируя SonarQube в конвейер сборки, вы поддерживаете высокое качество кода.
- SonarQube состоит из двух частей: сканерной и серверной. Сначала настроим сервер вручную с помощью Docker:


- Доступ к порталу SonarQube получаем в
https://public-ip:9000
:

- Имя пользователя и пароль по умолчанию —
admin
.


- Чтобы получить персональный токен, переходим в Project > Settings > Access Tokens и нажимаем
Add Token
:

- Копируем код и вставляем в SonarQube:


- Сохраняем настройку.

- Вводим персональный токен и сохраняем.

- Нажимаем
Set up
.

- Выбираем
other
и копируем код:

- Переходим в репозиторий Gitlab, создаем файл
sonar-project.properties
и вставляем в него этот код:

- Сохраняем файл и нажимаем
continue
на портале SonarQube:

- Затем переходим к следующему этапу
Add environment variables
:

- Согласно второму этапу, создадим две переменные:

- По завершении нажимаем
continue
на 2-м этапе SonarQube. - И получаем целиком задание, которое нужно скопировать и вставить в файл
.gitlab-ci.yml
:

- Добавляем конвейер и сохраняем:

- Запускаем конвейер и благодаря SonarQube видим на сервере примерно такой результат:

6. Сборка, контейнеризация и сканирование приложения
- Завершив тестирование и сканирование, переходим к следующему этапу — сборке пакета приложения и созданию образа Docker.
- Прежде чем отправлять образ, с помощью Trivy сканируем его на уязвимости.
- Этот важнейший этап для безопасности: им выявляются любые проблемы в собранном образе Docker.

- Запуская конвейер, получаем примерно такой вывод:



7. Отправка образа контейнера в реестр контейнеров GitLab
Созданный образ Docker отправляем на хранение в реестр контейнеров GitLab, где он будет доступен для развертывания:

- Запуская это задание, находим добавленный в реестр контейнеров образ в Deploy > Container Registry:

8. Развертывание приложения в Kubernetes
Наконец, развертываем контейнеризованное приложение в кластере Kubernetes.
- В этом задании декодируем детали конфигурации, закодированные ранее в целях безопасности:

- Здесь создается переменная KUBE_CONTEXT
project-path:k8s-agent
и используется образbitnami
для kubectl. - В манифесте включено несколько переменных Gitlab, поэтому ключевым словом
envsubst
заменяем их на исходные значения.
deployment-service.yaml.template
:
apiVersion: apps/v1
kind: Deployment # Создаваемый Kubernetes вид ресурса
metadata:
name: java-app
spec:
selector:
matchLabels:
app: java-app
replicas: 2 # Количество реплик, создаемых для этого развертывания
template:
metadata:
labels:
app: java-app
spec:
imagePullSecrets:
- name: registry-credentials # Для аутентификации в реестре контейнеров
containers:
- name: java-app-container
image: $CI_REGISTRY/harsh005/java-app/java-app:$CI_PIPELINE_ID # Образ, используемый для контейнеров в кластере
imagePullPolicy: Always
ports:
- containerPort: 8080 # Порт, на котором запускается контейнер в кластере
---
apiVersion: v1 # Версия API Kubernetes
kind: Service # Создаваемый Kubernetes вид ресурса
metadata: # Метаданные создаваемого вида ресурса
name: java-app-svc
spec:
selector:
app: java-app
ports:
- protocol: "TCP"
port: 80
targetPort: 8080
type: LoadBalancer # тип службы.
Этап 5. Настройка кластера AWS EKS с помощью eksctl
eksctl
— простой инструмент CLI для создания кластеров и управления ими в EKS, его предпочитают за простоту и удобство. Вот как с помощью eksctl
создается кластер EKS.
1. Установка eksctl
- Нажимаем ссылку.
- Устанавливаем версию для Windows.

- Извлекаем папку на локальном компьютере:

2. Настройка интерфейса командной строки AWS
- Загружаем инструмент интерфейса командной строки AWS на локальный компьютер:

- Загружаем отсюда интерфейс командной строки AWS и настраиваем его для учетной записи.
- Для этого в учетке создаем пользователя IAM.
- В Security credentials нажимаем
Create access key
и создаем ключ доступа и секретный ключ, оба копируем:


- Теперь в локальной командной строке вводим
aws configure
и вставляем туда эти учетные данные:

- Вставляем ключ доступа в Access Key ID, а секретный ключ — в Secret Access Key ID. Указываем также регион по умолчанию.
Настроив интерфейс командной строки AWS, установим и инструмент клиента для Kubernetes, то есть Kubectl, с помощью которого приложения будут развертываться в кластере.
3. Создание кластера EKS
- Создаем yaml-файл настройки кластера EKS:
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-test-cluster
region: us-east-1
nodeGroups:
- name: small-nodegroup
instanceType: t2.micro
desiredCapacity: 2
- name: medium-nodegroup
instanceType: t2.small
desiredCapacity: 2
- Теперь весь кластер запустится в EKS одной командой:
eksctl create cluster -f cluster-setup.yml


Этап 6. Подключение кластера EKS к GitLab
Создав кластер EKS, переходим к следующему этапу — подключению кластера к GitLab для управления развертываниями напрямую из конвейера сборки.
- Создаем в репозитории конфигурационный файл агента
.gitlab/agents/eks-k8s/config.yaml
:
user_access:
access_as:
agent: {}
projects:
- id: <your-project-id>
- Переходим в Operate («Управление») > Kubernetes Cluster («Кластер Kubernetes») > Connect a cluster («Подключить кластер»).

- Выбираем агента из выпадающего списка и зарегистрируем:

- После этого этапа копируем команды настройки токена и агента.
- Чтобы развернуть GitLab-агент, запускаем эти команды в кластере:


helm repo add gitlab https://charts.gitlab.io
helm repo update
helm upgrade --install eks-k8s gitlab/gitlab-agent \
--namespace gitlab-agent-eks-k8s \
--create-namespace \
--set image.tag=v17.3.0-rc7 \
--set config.token= <your-token> \
--set config.kasAddress= <your-kasAddress>
- После того как агент развернут, статус подключения в Gitlab становится
Connected
:

- Теперь, чтобы извлечь образ при создании развертывания, добавим учетные данные реестра в манифесте Kubernetes.
- Для этого создаем секрет
registry-credentials
. - Так что для этого этапа понадобится токен аутентификации в реестре.
- Переходим в Settings («Настройки») > Repository («Репозиторий») > Display tokens («Показать токены») > Add Token («Добавить токен»):


- Создаем токен развертывания и копируем учетные данные как имя пользователя и пароль для реестра контейнеров:

- Переходим в кластер и создаем секрет реестра Docker
registry-credentials
:
kubectl create secret docker-registry registry-credentials --docker-server=registry.gitlab.com --docker-username=<1st-token> --docker-password=<2nd-token> --dry-run=client -o yaml > registry-credentials.yml

Этап 7. Запуск конвейера
Все настроено, пора запустить конвейер.
1. Коммитим и добавляем код
- Коммитим в репозиторий GitLab файл
.gitlab-ci.yml
, исходный код Java и манифесты развертывания Kubernetes, Dockerfile:
.gitlab-ci.yml
:
stages:
- pre-requisite
- unit_test
- trivy_scan
- sonar_test
- build_and_scan
- image_push
- deploy_to_eks
install_tools:
stage: pre-requisite
script:
- sudo apt install -y openjdk-17-jre-headless
- sudo apt install -y maven
- sudo apt-get install -y wget apt-transport-https gnupg lsb-release
- wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
- echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
- sudo apt-get update && sudo apt-get install -y trivy
- sudo apt -y install docker.io && sudo chmod 666 /var/run/docker.sock
- sudo snap install kubectl --classic
tags:
- dedicated-runner
only:
- main
unit_testing:
stage: unit_test
script:
- mvn test
tags:
- dedicated-runner
only:
- main
trivy_fs_scan:
stage: trivy_scan
script:
- trivy fs --format table -o fs.html .
tags:
- dedicated-runner
artifacts:
paths:
- fs.html
only:
- main
sonarqube-check:
stage: sonar_test
image:
name: sonarsource/sonar-scanner-cli:latest
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Определяется местоположение кеша задачи анализа.
GIT_DEPTH: "0" # В git дается указание извлечь все ветки проекта, требуемые задаче анализа
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- sonar-scanner
allow_failure: true
only:
- main
image_build_&_scan:
stage: build_and_scan
variables:
Image_tag: $CI_REGISTRY/harsh005/java-app/java-app:$CI_PIPELINE_ID
script:
- mvn clean package
- docker build -t $Image_tag .
- trivy image $Image_tag --format table -o image.html
tags:
- dedicated-runner
artifacts:
paths:
- image.html
only:
- main
image_push:
stage: image_push
variables:
Image_tag: $CI_REGISTRY/harsh005/java-app/java-app:$CI_PIPELINE_ID
before_script:
- docker login $CI_REGISTRY -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
script:
- docker push $Image_tag
tags:
- dedicated-runner
only:
- main
k8s-deploy:
stage: deploy_to_eks
variables:
KUBE_CONTEXT: harsh005/java-app:eks-k8s
image:
name: bitnami/kubectl:latest
entrypoint: ['']
before_script:
- kubectl config use-context "$KUBE_CONTEXT"
script:
- envsubst < deployment-service.yaml.template > deployment-service.yaml
- kubectl apply -f deployment-service.yaml
only:
- main
when: manual
- Чтобы все задания выполнялись в ветке
main
, здесь также поместили элементы управления заданиями. И если все задания до этапаdeploy_to_eks
выполнены успешно, вручную запускается заданиеk8s-deploy
, которым код развернется в самоуправляемом Kubernetes.
2. Активируем конвейер
- После того как код добавлен, в GitLab файл
.gitlab-ci.yml
автоматически обнаруживается, и конвейер активируется:

3. Отслеживаем конвейер
- Переходим в CI/CD («Непрерывная интеграция и непрерывное развертывание») > Pipelines («Конвейеры») проекта GitLab и отслеживаем ход выполнения.
- В ветке
test
видим последовательное выполнение каждого этапа — установки, тестирования, сканирования, сборки и развертывания:


- С результатами сканирования Trivy или тестирования SonarQube можно ознакомиться.
- Завершив все тестирование и сборку, вручную активируем задание
k8s-deploy
для финального развертывания:


4. Просматриваем результаты конвейера
- Логи выходных данных просматриваются для каждого задания. Если все настроено корректно, конвейер успешно завершается, и приложение Java развертывается в кластере Kubernetes:

5. Вывод
- Копируем внешний ip-адрес — URL-адрес балансировщика нагрузки — и вставляем в браузер:


Заключение
С помощью GitLab CI/CD мы настроили и развернули приложение Java в самоуправляемом Kubernetes-мультикластере проекта. Провели при этом модульное тестирование, сканирование безопасности, анализ качества кода, сборку и контейнеризацию.
Этим конвейером автоматизируется процесс разработки и выпуска программного обеспечения, безопасно и эффективно осуществляется последовательное развертывание высококачественного кода. Запустив конвейер, мы увидели, как с GitLab CI/CD упрощаются сложные развертывания, а инструменты и процессы интегрируются в единый автоматизированный рабочий поток.
Читайте также:
- JAVA: разница между параметрами JVM -D, -X, -XX
- Реализация конвейера CI/CD «от и до»
- Руководство по AWS: настройка экземпляра EC2 для развертывания приложений Java
Читайте нас в Telegram, VK и Дзен
Перевод статьи @Harsh: Deploying Secure Java Applications on AWS EKS Using GitLab CI/CD, Maven, Trivy and SonarQube