Всем привет! На связи Виктор Ашакин, DevOps-инженер компании «Флант». Периодически к нам приходят клиенты с вопросом поиска альтернативы GitLab, GitHub c блэкджеком удобным CI\CD и on-premise размещением. Наш взгляд пал на Open Source-инструмент Gitea.
Gitea — достаточно популярное решение, у него 44,6K звёзд на GitHub. Приложение написано на Go, легковесно и не требовательно к системным ресурсам. В сравнении с GitLab, который под капотом имеет сложный комбайн из технологий, сервис Gitea прост и потребляет в два раза меньше ресурсов. Конечно, его можно прокачать по вкусу с помощью кэширующего кластера Redis или отказоустойчивого кластера PostgreSQL. Это добавит определённую гибкость, но для большинства потребителей будет избыточно.
Gitea имеет схожий с GitHub интерфейс и функционал. CI/CD Gitea Actions — практически полный аналог GitHub Actions и в большинстве с ним совместим. За период работы с Gitea Actions из отличий я нашёл только отсутствие функционала repository_dispatch, но и он планируется к внедрению в версии 1.23. Также Gitea можно использовать, как OAuth 2.0 authentication identity provider, что даёт нам функционал Authentication, Аuthorization and Аccounting (AAA), то есть аутентификацию, авторизацию и управление пользователями, и может являться единой точкой входа для доступа к сторонним веб-ресурсам (SSO).
Описанными выше фишками возможности Gitea не ограничиваются, но их будет достаточно, чтобы построить экосистему управления кодом и развёртывания его в Kubernetes.
В первой части статьи будет описано, как установить и настроить сервер Gitea, а также как с помощью него организовать авторизацию через Dex в кластере Deckhouse Kubernetes Platform (DKP). Во второй и третьей части настроим Gitea act_runner и подготовим Gitea Actions-пайплайн, в котором развернём в кластере приложение с помощью werf.
Установка и серверы Gitea
В работе нам понадобятся серверы для Gitea и Gitea act_runner, а также кластер Deckhouse Kubernetes Platform. Разумеется, последний пригодится только в случае, если вам нужен Kubernetes. А если нет, то Gitea отлично работает без него, и вы можете воспользоваться этой инструкцией для установки сервиса, хотя часть функционала при этом использоваться не будет.
Как развернуть кластер DKP, подробно описано в статье моего коллеги, так что сосредоточусь на двух первых пунктах. Здесь я расскажу о настройке сервера Gitea, а к act_runner вернёмся во второй части.
Подготовка
Для Gitea нам понадобится сервер, соответствующий следующим минимальным требованиям:
не менее 2 ядер CPU;
не менее 4 ГБ RAM;
не менее 20 ГБ дискового пространства;
сконфигурированный доступ по SSH.
В качестве ОС я остановился на Ubuntu 22.04, но можно выбрать то, что вам больше по душе: Linux, Windows, macOS, FreeBSD и так далее.
Установка и настройка БД
Обратите внимание, что для удобства все действия в консоли выполняются от пользователя root, я отмечу места, где будут нужны действия от другого пользователя.
Gitea поддерживает следующие СУБД: PostgreSQL (⩾12), MySQL (⩾ 8.0), MariaDB (⩾ 10.4), SQLite (builtin) и MSSQL (⩾ 2012 SP4). Я буду использовать MySQL 8.1.
Первым делом заходим на сервер Gitea и выполняем команды по установке пакетов MySQL:
apt update
apt install mysql-common=5.8+1.0.8 mysql-server-8.0=8.0.28-0ubuntu4 mysql-client-8.0=8.0.28-0ubuntu4 mysql-server-core-8.0=8.0.28-0ubuntu4 mysql-client-core-8.0=8.0.28-0ubuntu4
# Фиксируем версию mysql (это опционально)
apt-mark hold mysql-common=5.8+1.0.8 mysql-server-8.0=8.0.28-0ubuntu4 mysql-client-8.0=8.0.28-0ubuntu4 mysql-server-core-8.0=8.0.28-0ubuntu4 mysql-client-core-8.0=8.0.28-0ubuntu4
Создаём базу данных и её пользователя, под которым сервис Gitea будет заходить в MySQL. Для этого и нам нужно зайти в MySQL:
$ mysql
# Смена пароля для пользователя root
ALTER USER 'root'@'localhost' IDENTIFIED BY '<your_secret_root_password>';
FLUSH PRIVILEGES;
# Создание пользователя БД gitea
CREATE USER 'gitea'@'%' IDENTIFIED BY '<your_secret_gitea_password>';
# Создание инстанса БД
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_bin';
# Добавление прав на БД
GRANT ALL PRIVILEGES ON giteadb.* TO 'gitea'@'%';
FLUSH PRIVILEGES;
На этом для нашей задачи настройки базы данных можно закончить. Остальные выходят за рамки статьи, но почитать о них можно на nixCraft.
Установка Gitea
Для установки Gitea нужно скопировать бинарный файл, создать сервисного пользователя, под которым сервис Gitea будет запущен в ОС, и подготовить структуру каталогов.
Поехали! Устанавливаем пакет Git:
apt install git
Скачиваем бинарник Gitea и готовим его к запуску:
wget -O gitea https://dl.gitea.com/gitea/1.22.2/gitea-1.22.2-linux-amd64
chmod +x gitea
mv gitea /usr/local/bin/gitea
Создаём сервисного пользователя:
adduser \
--system \
--shell /bin/bash \
--gecos 'Git Version Control' \
--group \
--disabled-password \
--home /home/git git
Готовим структуру каталогов:
mkdir -p /var/lib/gitea/{custom,data,log,public,indexers}
chown -R git:git /var/lib/gitea/
chmod -R 750 /var/lib/gitea/
mkdir /etc/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea
Отлично, теперь сервер Gitea практически готов к запуску. Остаётся последний штрих — создать сервис systemd
:
vim /etc/systemd/system/gitea.service
Копируем текст юнита systemd
:
[Unit]
Description=Gitea
After=syslog.target
After=network.target
After=mysql.service
[Service]
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
[Install]
WantedBy=multi-user.target
Инициализируем, запускаем и проверяем наш сервис Gitea:
systemctl daemon-reload
systemctl start gitea
systemctl status gitea
systemctl enable gitea
Настройка nginx
Для доступа по HTTP нам нужно настроить обратный прокси-сервер. Устанавливаем nginx и готовим его конфиг для работы с Gitea и Gitea container registry:
apt install nginx
vim /etc/nginx/sites-available/gitea.conf
ln -s /etc/nginx/sites-available/gitea.conf /etc/nginx/sites-enabled/gitea.conf
В файле /etc/nginx/sites-available/gitea.conf
нам нужно указать следующие настройки, где вместо <your_gitea_domain_name>
— DNS-имя вашего Gitea-сервера:
server {
listen 80;
server_name <your_gitea_domain_name>;
root /var/lib/gitea/public;
access_log off;
error_log off;
location /v2/ { # https://github.com/go-gitea/gitea/issues/21092#issuecomment-1749965397
client_max_body_size 512m;
proxy_pass http://127.0.0.1:3000/v2/;
}
location / {
client_max_body_size 512m;
proxy_pass http://127.0.0.1:3000;
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Для безопасности рекомендую не выставлять сервер Gitea голым задом в открытую сеть, пока не выполните шаги из следующего раздела статьи — «Конфигурация Gitea». Вместо этого стоит «повесить» nginx на IP-адрес в локальной сети или на localhost.
Для этого в конфигурационном файле gitea.conf можно поправить:
server {
listen 127.0.0.1 8080
...
На локальной машине добавить запись в /etc/hosts
:
...
127.0.0.1 your_gitea_domain
Пробросить порт 8080 до сервера Gitea:
ssh -L 8080:127.0.0.1:8080 gitea-host
После этого на веб-интерфейс Gitea можно заходить по адресу http://your_gitea_domain:8080
. Эти действия не обязательны — просто рекомендация.
Заказ сертификата и настройки nginx для работы по HTTPS я опущу. В моём случае перед nginx Gitea находится другой обратный прокси-сервер, который занимается заказом сертификатов и обслуживанием HTTPS-трафика. Gitea умеет сам заказывать сертификаты у ACME-провайдера, по умолчанию это Let's Encrypt. Настройки ACME описаны в официальной документации.
Отмечу, что в моём конфиге nginx указана секция для настройки location /v2/
, о которой ничего не сказано в официальной документации. У нас была проблема с тем, что Kubernetes-кластер не мог забрать образ из registry (crictl pull
), решение нашлось в issue.
Конфигурация Gitea
Следующим шагом в веб-интерфейсе Gitea нам нужно задать основные настройки работы сервера. Открываем в браузере домен, который указывали в конфигурационном файле nginx, и заполняем поля для подключения к БД:
Основные параметры Gitea:
Дополнительные параметры опционально, по вашему вкусу:
Задаём логин и пароль для администратора. Если вдруг вы забыли пароль, его можно сменить через CLI с помощью команды gitea admin user change-password --username user --password password --config /etc/gitea/app.ini
:
Нажимаем кнопку Install Gitea
. После этого сервер какое-то время будет выполнять инициализацию и заполнит конфигурационный файл /etc/gitea/app.ini
.
Наш сервис Gitea готов угощать нас своим ароматом :).
Проверка работы Gitea
Теперь стоит проверить, работает ли наш сервер. В браузере логинимся в Gitea с кредами, которы задали на предыдущем шаге. Если пропустили, то пользователя можно создать через консоль.
Организационная структура доступа в Gitea выглядит следующим образом: Organization → Teams. Здесь Organization — это группа верхнего уровня, а Teams — подгруппы нижнего уровня.
Давайте создадим тестовую организацию для проверки работы Gitea. В правом верхнем углу выбираем плюсик → New Organization → название организации (у меня это team-romeo), галочка Visibility limited
.
После создания организации в ней автоматически появится команда Owners
, членом которой и будет пользователь, создавший организацию.
Для удобной работы с репозиториями добавим в свой профиль открытую часть SSH-ключа: после этого можно без ввода пароля пулить и пушить код. Если ключа ещё нет, то RSA-ключ можно сформировать командой ssh-keygen -t ed25519
.
Копируем открытую часть своего RSA-ключа:
cat ~/.ssh/id_ed25519.pub
# У себя скопировать всю строку полностью
ssh-ed25519
your_public_rsa_key user@pc.local
Добавляем ключ к себе в профиль: нажимаем на аватар → Settings → SSH / GPG Keys → Add key. Задаём произвольное название в поле Key Name и вставляем открытую часть нашего ed25519-ключа.
Перейдём в свою организацию и создадим тестовый репозиторий под названием Hello-world
. Можем клонировать к себе новосозданный репозиторий без регистрации и смс ввода пароля:
git clone git@your_gitea.com:team-romeo/hello-world.git
cd hello-worl
touch README.md
git add README.md
git commit -m "first commit"
git push
На этом мы закончили с настройкой Gitea. Время перейти к аутентификации и авторизации в кластер DKP.
Настройка аутентификации и авторизации в кластере Deckhouse Kubernetes Platform через Gitea с помощью Dex
Как я уже говорил в начале статьи, Gitea может выступать как провайдер OAuth2, то есть обеспечить аутентификацию и авторизацию пользователей во внешних источниках, поддерживающих стандарт OpenID. Вишенкой на торте будет функционал Dex, который позволяет закрывать аутентификацией любой ingress в кластере. Он добавит безопасности приложениям и позволит скрыть чувствительные ресурсы от внешних глаз.
Итак, для авторизации пользователей в DKP через Gitea OAuth2 воспользуемся Dex. Это Open Source-решение, которое служит связующим звеном между различными сервисами идентификации (Identity Provider) и веб-ресурсами. Один из основных мейнтейнеров Dex — мой коллега Максим Набоких. Dex входит в модуль user-authn
Deckhouse Kubernetes Platform.
Настройка аутентификации
Чтобы задействовать сервис Dex, необходимо лишь включить модуль DKP user-authn, что значительно упрощает настройку. Давайте зайдём в кластер DKP и проверим, включён ли модуль:
kubectl get mc user-authn
NAME ENABLED VERSION AGE MESSAGE
Error from server (NotFound): moduleconfigs.deckhouse.io "user-authn" not found
Видим, что модуль не включён, создадим YAML-манифест для его включения:
kubectl create -f - <<EOF
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: user-authn
spec:
enabled: true
EOF
После включения модуля user-authn
проверяем доменное имя сервиса dex
. На этот домен Identity Provider (Gitea OAuth2) будет возвращаться callback-запрос с информацией об авторизации пользователей и их атрибутами.
$ kubectl -n d8-user-authn get ing | grep dex
dex nginx dex.<your_d8_domain_name> 10.0.1.199 80, 443 1m
Теперь нам нужно «подружить» наш Dex и Gitea OAuth2. Для этого сначала создадим в Gitea сущность Application, а затем в DKP — YAML-манифест DexProvider
.
Всё достаточно просто. Заходим в веб-интерфейс Gitea, затем в Site Administration → Integrations → Applications. Далее:
В поле
Application Name
указываем произвольное название, к примеру Dex DKP.В поле
Redirect URIs
указываем наш callback-домен сервиса Dex:https://dex.<your_d8_domain_name>/callback
.Нажимаем Create Application. Важно скопировать значения полей
Client ID
иClient Secret
— это условные логин и пароль для нашего сервиса Dex. В дальнейшем эти данные не будут доступны для просмотра, в случае их утери можно только пересоздать Application.Нажимаем кнопку Save для завершения процедуры создания Application.
В кластере Deckhouse создаём ресурс DexProvider, с помощью которого настроим Dex для авторизации через Gitea. Другие примеры с описанием настроек DexProvider OIDC вы найдёте в документации.
В DexProvider нужно указать адрес сервера Gitea, а также значение для clientID и clientSecret, которые мы записали при создании Application в Gitea:
kubectl create -f - <<EOF
apiVersion: deckhouse.io/v1
kind: DexProvider
metadata:
name: gitea
spec:
type: OIDC
displayName: gitea
oidc:
issuer: https://<your_gitea_domain_name>/ # адрес целевого gitea сервера
clientID: gitea_app_client_id # gitea Application client ID
clientSecret: gitea_app_client_secret # gitea Application client Secret
insecureSkipEmailVerified: true
getUserInfo: true
EOF
Проверим работу аутентификации. Для этого зайдём на какой-нибудь веб-ресурс DKP, например в Grafana.
Получаем адрес:
$ kubectl -n d8-monitoring get ing -l app.kubernetes.io/managed-by=Helm,app=grafana,heritage=deckhouse,module=prometheus
NAME CLASS HOSTS ADDRESS PORTS AGE
grafana nginx grafana.<your_d8_domain_name> 10.0.1.199 80, 443 150d
Вводим в браузере адрес сервиса Grafana и получаем окно Dex с выбором провайдера авторизации:
Затем — окно Gitea с разрешением передавать в сервис Dex данные аккаунта:
Если всё прошло успешно и аутентификация настроена, откроется нужная нам страница с Grafana. Если же по какой-то причине аутентификация не работает, можно посмотреть логи Dex:
kubectl -n d8-user-authn logs -l app=dex -f
{"time":"2024-11-06T10:01:58.85570082Z","level":"INFO","msg":"login successful","connector_id":"gitea","username":"","preferred_username":"tester","email":"tester@tester.com","groups":null,"client_remote_addr":"176.14.136.71","request_id":"878414e4-c8ef-4705-9c55-92844fa4a8ac"}
Настройка авторизации
За разграничение прав доступа пользователей к ресурсам DKP отвечает модуль user-authz.
С его помощью мы можем ограничить пользователям доступ к определённым пространствам имён, разрешить просмотр или запретить изменение ресурсов в них. Настройка прав доступа выполняется стандартным для RBAC Kubernetes способом: с помощью создания ресурсов RoleBinding
или ClusterRoleBinding
. Пользователи могут выписывать себе kubeconfig для доступа к кластеру через утилиту kubectl, использовать веб-интерфейс Kubernetes Dashboard или аналогичные решения.
Для настройки авторизации в кластере нужно включить модуль user-authz
и создать ресурс RoleBinding
, в котором описано, кому, куда и какие права мы даём. Ресурс ClusterRoleBinding
используется, если мы настраиваем manage-роль (networking, Kubernetes, observability и так далее), а RoleBinding
— для настроек доступа к пользовательским окружениям.
Для начала создадим в кластере Deckhouse тестовое пространство имён с названием gitea-authz-test
и тестовое приложение tester-app
в нём:
kubectl create namespace gitea-authz-test
kubectl -n gitea-authz-test create deployment tester-app --image=nginx:1.27
Включаем модуль user-authz
:
kubectl create -f - <<EOF
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: user-authz
spec:
enabled: true
EOF
Предоставим пользователю viktor.ashakin права админа пространства имён тестового приложения, для этого создадим ресурс RoleBinding
:
kubectl create -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-admin
namespace: gitea-authz-test
subjects:
- kind: Group
name: team-romeo
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: d8:use:role:admin
apiGroup: rbac.authorization.k8s.io
EOF
Проверяем работу авторизации. Для этого зайдём в Kubernetes Dashboard. За работу Dashboard отвечает модуль d8-dashboard, который включён по умолчанию.
Определяем доменное имя сервиса Dashboard:
# Получаем адрес Dashboard
kubectl -n d8-dashboard get ing -l app.kubernetes.io/managed-by=Helm,app=dashboard
NAME CLASS HOSTS
dashboard nginx dashboard.<your_d8_domain_name>
В браузере открываем страницу сервиса Dashboard https://dashboard.<your_d8_domain_name>
, вводим название пространства имён (namespace) нашего приложения: gitea-authz-test
.
Откроется страница со всеми ресурсами в пространстве имён. Права админа позволяют нам редактировать или удалять ресурсы, изменять количество реплик тестового приложения. Удалим deployment нашего приложения:
Полный доступ мы посмотрели, теперь проверим, как работают ограниченные права доступа. Создадим тестового пользователя tester в Gitea: в веб-интерфейсе нажимаем на иконку пользователя → Site Administration → Identity & Access → User Accounts → Create User Account.
Создаём в кластере ресурс RoleBinding
для пользователя tester с ролью viewer:
kubectl create -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-viewer
namespace: gitea-authz-test
subjects:
- kind: User
name: tester@tester.com # Для пользователя указывается его email
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: d8:use:role:viewer
apiGroup: rbac.authorization.k8s.io
EOF
Возвращаем тестовое приложение к жизни:
kubectl -n gitea-authz-test create deployment tester-app --image=nginx:1.27
Открываем в браузере вкладку-инкогнито и логинимся в Gitea под новым пользователем tester. В соседней инкогнито-вкладке открываем страницу Dashboard и указываем gitea-authz-test
в качестве названия пространства имён. При попытке удалить deployment приложения получим ошибку:
Теперь предоставим доступ с правами админа ко всем ресурсам в пространстве имён кластера Deckhouse группе team-romeo:owners. Данная группа была создана ранее на этапе проверки Gitea.
Описанный ниже функционал работает только в режиме enableMultiTenancy, который доступен в DKP версии Enterprise Edition. С помощью
enableMultiTenancy
мы можем предоставлять доступ к пространству имён на основе лейблов.
Включаем MultiTenancy в модуле user-authz
, для этого редактируем ресурс:
kubectl edit mc user-authz
и добавляем опцию spec.settings.enableMultiTenancy: true
:
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: user-authz
spec:
enabled: true
settings:
enableMultiTenancy: true
Теперь в кластере Deckhouse создаём ресурс ClusterAuthorizationRule
. Подробные примеры можно посмотреть в документации к модулю user-authz.
kubectl create -f - <<EOF
apiVersion: deckhouse.io/v1
kind: ClusterAuthorizationRule
metadata:
name: admins
spec:
accessLevel: SuperAdmin
allowAccessToSystemNamespaces: true
allowScale: true
portForwarding: true
subjects:
- kind: Group
name: team-romeo:owners
EOF
В браузере открываем страницу с сервисом Dashboard, где можем просматривать любые пространства имён, изменять количество реплик приложений и просматривать секреты.
Для примера выберем d8-monitoring:
После этого у нас откроется страница со всеми ресурсами, находящимися в пространстве имён d8-monitoring. Ресурс ClusterAuthorizationRule
позволяет нам гибко управлять доступом для групп и отдельных пользователей. Достаточно повесить нужный лейбл на пространство имён и задать matchExpressions
в ClusterAuthorizationRule
.
Промежуточный итог
Теперь у нас есть готовый сервер Gitea, а также настроены аутентификация и авторизация в Deckhouse Kubernetes Platform.
В двух следующих частях статьи поговорим о Gitea Actions. Настроим инфраструктуру, напишем Actions CI/CD-пайплайны и развернём приложение в кластере DKP с помощью werf.
P. S.
Читайте также в нашем блоге: