Gitea + Harbor + Jenkins как замена GitLab
С чего всё началось. С того, что уже установленный в моей локальной сети экземпляр сервиса GitLab CE вполне успешно работал, но был расположен на обычном HDD, т.е. не SSD и не NVMe. И вполне, какзалось бы, успешно работал, но при длительном аптайме он сжирал все ресурсы оперативной памяти, которой я ему выделил - 16 Гб (что видимо мало), начинал активно использовать swap, и когда планировщик начинал заниматься очисткой/оптимизацией структуры репозиториев, мог начинать тормозить с невероятной силой, из-за того, что исчерпывал ресурc IOPS диска. Конечно, перезагрузка хоста всё решала, но сама ситуация была несколько неприятной. К тому же, для каких-то небольших проектов и небольшой инфраструктуры такой комбайн как GitLab, мне кажется, не очень-то и нужен. Плюс ко всему, у меня еще были вопросы к формату описания сценариев CI/CD пайплайнов, которые, как мне кажется, в Jenkins можно делать значительно гибче чем в GitLab. Словом, GitLab безусловно крут и незаменим в наши дни, если вы работаете в больщой команде где много подгрупп и разых проектов, но для каких-то более простых задач можно обойтись инструментами установку и настройку которых я буду описывать ниже.
Для установки будем использовать ОС Ubuntu Linux 22.04 LTS на всех разворачиваемых хостах.
Установка Gitea (“Git с чашечкой чая!”)
Установка PostgreSQL и создание БД
На тему подготовки базы данных, я ориентировался на официальную инструкцию разработчиков Gitea
Сначала устанавливаем сам PostgreSQL:
|
|
После установки проверяем в файле /etc/postgresql/14/main/postgresql.conf
значения параметров:
listen_addresses
: по умолчанию этоlocalhost
, и если БД и Gitea на одном и том же хосте, то можно так и оставить, либо указать IP-адрес интерфейса на котором должен отвечать сервер БД. Если мы хотим чтобы БД работала на всех интерфейсах, то можно задать значение0.0.0.0
, либо несколько IP через запятую.password_encryption
: рекомендуется использоватьscram-sha-256
, по этому, чтобы “наверняка”, можно раскомментировать данную строчку в файле конфигурации
Далее, запускаем консольный клиент PostreSQL от имени пользователя postgres
и выполняем следующий наобор действий:
-
1
sudo -u postgres psql
-
1
CREATE ROLE gitea WITH LOGIN PASSWORD 'gitea';
Естественно, логин и пароль следует заменить на какой-то другой
-
1
CREATE DATABASE giteadb WITH OWNER gitea TEMPLATE template0 ENCODING UTF8 LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
-
В файл
nano /etc/postgresql/14/main/pg_hba.conf
добавляем строчку:-
для локального подключения:
1
local giteadb gitea scram-sha-256
-
для удаленного подключения:
1
host giteadb gitea 192.0.2.10/32 scram-sha-256
где имя БД, пользователя, IP должны соответствовать вашим условиям
Следует учитывать, что PostgreSQL применяет правила последовательно и лучше размещать данные правила авторизации до уже имеющихся в этом файле, чтобы глобальные правила их не перекрывали.
-
-
перезапускаем PostgreSQL для применения изменений:
1
sudo systemctl restart postgresql.service
После чего можно проверить подключение к БД:
- локально:
1
psql -U gitea -d giteadb
- удаленно:
1
psql "postgres://gitea@203.0.113.3/giteadb"
- локально:
Установка сервиса Gitea
Скачиваем бинарный файл и GPG-подпись:
|
|
Проверяем GPG-подпись (не обязательно):
|
|
Успехом проверки можно считать наличие в выводе строки: Good signature from "Teabot <teabot@gitea.io>"
, но остальные сообщения можно не обращать внимание
Если всё прошло успешно, то копируем файл в папку /usr/local/bin/
:
|
|
Создаем пользователя для сервиса gitea:
|
|
Создаем необходимую структуру папок:
|
|
Создаем файл определения сервиса systemd:
|
|
Wants=postgresql.service
и After=postgresql.service
Перезапускаем демона systemd и запускаем сервис:
|
|
Если всё успешно, то открываем в браузере http://[IP вашего сервера]:3000, где должна открыться страничка установки Gitea, на которой необходимо установить:
- тип БД: PostgreSQL
- указать IP-адрес или оставить localhost, если БД находится на том же хосте
- вписать логин и пароль от созданной ранее БД
- в самом низу страницы можно задать логин и пароль администратора сервиса. Если этого не делать, то можно после установки создать пользователя командой:
Естественно, имя пользователя и пароль могут быть другими
1
sudo -u git gitea --config /etc/gitea/app.ini admin user create --username gitea --password gitea123 --must-change-password --email root@gitea.local --admin
После успешной установки следует изменить парва доступа к фалу конфигурации:
|
|
По умолчанию создаваемый файл конфигурации содержит далеко не все из возможных параметров. Дополнительные параметры можно посмотреть в документации.
Нам, для успешного взаимодействия с Jenkins в дальнейшем, необходимо добавить в этот файл следующие строки:
|
|
После всех манипуляций перезапускаем сервис (а еще лучше хост) и убеждаемся, что всё работает. После чего можно переходить к следующему шагу.
|
|
Настройка прокси Nginx для Gitea
Шаг не обязательный, т.к. для локальной сети наличие TLS не обязательно и можно сделать чтобы сам сервис работал на 80 порту, но для лучшей надежности можно сделать.
Устанавливаем Nginx:
|
|
Создаем файл конфигурации:
|
|
И меняем дефолный конфиг на наш:
|
|
Перезапускаем Nginx и проверяем что всё работает на обычном порту http:
|
|
Настройка сервера Harbor (Docker registry)
Установка Docker
Harbor состоит из нескольких микросервисов, разворачиваемых в Docker, по этому сначала следует установить докер. Пользуясь офф.инструкцией выполняем следующий набор команд:
|
|
Добавляем репозиторий apt:
|
|
Устанавливаем сам Docker:
|
|
Установка Harbor
Выбираем какой нибудь релиз отсюда и скачиваем его и GPG-ключ с помощью wget:
|
|
Проверяем GPG-сигнатуру:
|
|
Интересующая нас строка - gpg: Good signature from "Harbor-sign (The key for signing Harbor build) <jiangd@vmware.com>" [unknown]
, на все последующие можно не обращать внимание.
Далее, распаковываем:
|
|
Копируем шаблон конфигурации:
|
|
Вносим в него необходимы правки, такие как: hostname, harbor_admin_password, пароль БД и т.д. Так же можно закомментировать всё что связано с https, так как в этом нет необходимости внутри локальной сети. Если понадобится вывести сервис в интернет, то, как мне кажется, проще будет сделать это через какой-то реверс-прокси.
Подробное описание параметров можно посмотреть тут: https://goharbor.io/docs/2.0.0/install-config/configure-yml-file/
После чего можно запускать скрипт install.sh
Если установка прошла успешно, то мониторим состояние развертывания через watch docker compose ps
до тех пор, пока стстус всех контейнеров не перейдет в состояние healthy
.
После этого можно открыть адрес хоста в браузере и попробовать создать какой-то тестовый проект.
Для того чтобы сам докер мог работать с этим реестром через http, нужно добавить в файл конфигурации /etc/docker/daemon.json
нечто подобное:
|
|
и перезапустить сам Docker:
|
|
После этого авторизуемся в нашем Docker registry под пользователем admin
:
|
|
И пробуем туда что-нибудь запушить:
|
|
Если всё прошло успешно, и образ появился в проекте library, то будем считать, что на данном этапе процесс настройки хранилища Docker-образов завершен.
Установка и настройка Jenkins
Начальная установка
Устанавливаем Java Runtime:
|
|
Подключаем репозиторий Apt и устанавливаем Jenkins:
|
|
Далее, открываем в браузере страницу http://[адрес хоста]:8080, где должна быть страница куда нужно ввести пароль администратора для разблокировки. Местоположение файла содержащего пароль так же должно быть указано на этой странице. Вставляем содержимое этого файла в соответствующее поле и жмем кнопку Continue
.
На следующей странице предлогается выбрать: “Установить предлогаемые плагины” (“Install suggested plugins”) или “Выбрать плагины самостоятельно” (“Select plugins to install”). Выбираем первый вариант, т.к. в нем уже есть большая часть того что нам могло бы понадобиться, что-то еще можно будет установить позже, по мере необходимости.
После красивой странички, где будет отображаться прогресс установки дополнениий, появится страница где будет предложено создать первого пользователя - администратора. Тут, думаю, все понятно: логин, пароль, email - это на ваше усмотрение.
Следующим шагом нужно указать Jenkins URL, на странице под заголовком “Instance Configuration”.
Если всё прошло успешно, то в конце мы увидим надпись “Jenkins is ready! Your Jenkins setup is complete.”
После нажатия на кнопку “Start using Jenkins” мы увидим основной дашборд, в котором сразу бросается в глаза красная еденичка, в правом-верхнем углу страницы, рядом с иконкой изображающей щит. Кликнув на которую, мы увидим уведомление, что выполнять сборки на той же ноде где и контроллер может быть не безопасно и предложено установить “агент”. Агент - это сервис, который выполняет команды контроллера на какой-то локальной или удаленной машине. Лучше, чтобы все агенты были на удаленных машинах, отдельно от “контроллера”, который мы только что установили. Чтобы работа “контроллера” стала безопасной, следующим шагом мы настроим “агент” на отдельной машине.
Настройка “постоянного агента” (“permanent agent”)
Перед подключением агента к Jenkins нужно его сначала немного подготовить:
- установить OpenSSH Server, через который Jenkins будет взаимодействовать с агентом
- установить Java Runtime
- установить Docker, так же как мы это делали на шаге установки Harbor, для того чтобы мы могли исповать его в наших пайплайнах
Устанавливаем Java Runtime и OpenSSH Server:
|
|
Существует два варианта подключения агента:
- через SSH, когда Jenkins-контроллер сам подключается к нужному хосту по SSH, копирует и запускает таи своего агента, передавая ему необходимые параметры для подключения к контроллеру
- когда мы самотоятельно копируем jar-файл приложения агента и организуем его запуск на удаленном хосте, указывая необходимые параметры для подключения к контроллеру
Первый вариант мне видится проще, по этому мы будем использовать именно его. Для этого нам сначала необходимо сгенерировать пару SSH-ключей - приватный и публичный. Приватный ключ, соответственно, будет использоваться контроллером для авторизации на исполнительной ноде (worker’е), а публичный будет добавляться в список авторизованных ключей на исполнителе.
|
|
В результате чего мы получим два файла: jenkins-agent-1
- это приватный ключ, и jenkins-agent-1.pub
- публичный ключ.
Далее, создаем пользователя, в домашней папке которого и от имени которого будет работать агент:
|
|
Добавиляем содержимое из полученного ранее файла ключа jenkins-agent-1.pub
в файл /var/jenkins/.ssh/authorized_keys
.
После этого, на хосте контроллера, необходимо добавить новый хост в список известных SSH-хостов:
|
|
Теперь можно добавить агента в разделе настроек веб-интерфейса Jenkins. Для этого переходим в раздел Manage Jenkins -> Nodes
и нажимаем кнопку New Node
. На появившейся странице задаем какое-то имя ноды, например jenkins-agent-1, выбираем тип “Permanent Agent” и жмем кнопку Create
.
На странице настроек агента необходимо заполнить следующие поля:
- Number of executers: параметр отвечающий за колличество одновременно выполняемых заданий на исполнении. По умолчанию равен еденице, но можно сделать больше, чтобы какие-то задачи могли выполняться параллельно
- Remote root directory: корневая папка для агента. Укажем домшнюю папку пользователя, которого мы создавали для агента -
/var/jenkins
- Launch method: выбираем
Launch agents via SSH
-
ниже, в поле
Host
, указываем адрес исполняющей ноды -
внизу поля
Credentials
нажимаем на кнопкуAdd
, и выбираем хранилище авторизационных данныхJenkins
В появившемся окне, необходимо заполнить поля:
- Domain:
Global credentials (unrestricted)
- Kind:
SSH Username with private key
- ID: можно оставить пустым, тогда сгенерируется случайный идентификатор, либо вписать что-то своё
- Username: указываем пользователя, которого мы создавали, т.е.
jenkins
- Private Key: выбираем
Enter directly
и в появившемся ниже поле нажимаем кнопкуAdd
. После чего в появившееся пространство вставляем содержимое файла приватного ключа SSH (jenkins-agent-1
), который мы генерировали ранее. - Passphrase: если приватный ключ был защищен паролем, то вписываем его в это поле, если нет, то оставляем его пустым
- Domain:
-
после добавления, выбираем из списка, находящегося между кнопкой
Add
и заголовком поля, только что созданную запись авторизационных данных
-
- Availability: оставляем
Keep this agent as much as possible
Всё остальное оставляем как есть и нажимаем кнопку Save
.
Теперь нужно сделать так, чтобы задания не могли попадать на ноду контроллера. Для этого, на той же странице натройки нод, кликаем на значек “шестеренки” справа, в строке ноды с именем “Built-In Node”, и в поле Number of executors
устанавливаем значение 0
, затем, сохраняем кнопкой Save
Чтобы проверить, что подчиненная нода работает нормально, нужно в писке нод кликнуть по её имени, и на открывшейся странице проверить список сообщений в разделе Log
, в конце которого дожно быть сообщение “Agent successfully connected and online”. А так же можно попробовать выполнить какие-то скриптовые комманды в разделе Script Console
.
Например, результатом выполнения комманды println System.getenv("PATH")
может быть нечто подобное:
|
|
или результат выполнения команды println "lsb_release -a".execute().text
, нечто вроде:
|
|
Если всё работает, то на данном этапе можно считать установку успешной. Дальшейшие действия будут зависить от ваших потребностей в выполнении конкретных задач.
Заключение
Теперь у нас есть весь необходимый инструментарий для организации автоматизированного управления инфраструктурой разработки. Всё остальное будет зависеть от ваших целей и фантазии. Все три установленных инструмента достаточно неприхотливы к ресурсам и производительности, что может иметь не маловажную роль для небольших проектов.
Следующими шагами будет:
- сопряжение Gitea с Jenkins и выполнение сценария из Jenkinsfile, находящегося в git-репоитории проекта
- создание Docker-образов из Pipeline’a и сохранение его в Harbor Docker Registry
- выполнение сценария внутри Docker-контейнера
- взаимодействие по SSH со сторонним из пайплайна
Но все эти шаги я опишу уже в следующей статье.