6. [Тестирование и запуск](#тестирование-и-запуск)
7. [Мониторинг и отладка](#мониторинг-и-отладка)
8. [Заключение](#заключение)
9. [Инфраструктура](#инфраструктура)
10. [Установка Gitea в кластере K3s](#установка-gitea-в-кластере-k3s)
11. [Настройка Gitea Runner в LXC контейнере](#настройка-gitea-runner-в-lxc-контейнере)
A. [Инфраструктура](#инфраструктура)
B. [Установка Gitea в кластере K3s](#установка-gitea-в-кластере-k3s)
C. [Настройка Gitea Runner в LXC контейнере](#настройка-gitea-runner-в-lxc-контейнере)
## Введение
Gitea Actions — это встроенная система непрерывной интеграции и развертывания (CI/CD) в Gitea, которая позволяет автоматизировать процессы сборки, тестирования и развертывания ваших проектов. Большой плюс этой системы в том, что она достаточна не требовательна к ресурсам и может быть развернута в собственном изолированном окружении.
Gitea Actions — это встроенная система непрерывной интеграции и развертывания (CI/CD) в Gitea, которая позволяет автоматизировать процессы сборки, тестирования и развертывания ваших проектов. Большой плюс этой системы в том, что она достаточна не требовательна к ресурсам и может быть развернута в собственном изолированном окружении.
В этой статье мы рассмотрим пример работы с данной системой, на примере того как настроить Gitea Actions для Go проекта с автоматической сборкой мультиплатформенных бинарников, созданием Docker образов и публикацией релизов.
@@ -43,7 +43,7 @@ Gitea Actions — это встроенная система непрерывн
Собственно функциональная часть проекта Go не блещет оригинальностью и имеет следующую простую структуру:
```
``` text
hello_gitea/
├── main.go # Основной код приложения
├── go.mod # Зависимости Go
@@ -93,7 +93,7 @@ func main() {
})
// Endpoints
r.GET("/health",func(c*gin.Context){
r.GET("/healthz", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"version": version,
@@ -148,8 +148,8 @@ func main() {
### Dockerfile
Помимо того, что мы будем собирать бинарники для разных платформ, мы также настроим сборку docker image в котором будем
запускать наш сервер api - это может быть полезным для развертывания нашего приложения, если мы настроим такое - например
Помимо того, что мы будем собирать бинарники для разных платформ, мы также настроим сборку docker image в котором будем
запускать наш сервер api - это может быть полезным для развертывания нашего приложения, если мы настроим такое - например
через ArgoCD или flux (впрочем это тема отдельнйо статьи).
Итак для контейнеризации используем многоэтапную сборку, что как вещают мудрецы является якобы полезным и правильным.
@@ -191,23 +191,22 @@ EXPOSE 8080
CMD ["./hello-api"]
```
**Ремарка:**
**Ремарка:**
Тут хочется немного поразмышлять - по хорошему надо или разобраться в вариантах кэширования gitea или в качестве
базововго образа для каждого из этапов использовать предварительно собранный образ со всем необходимым.
базововго образа для каждого из этапов использовать предварительно собранный образ со всем необходимым.
При каждом запуске workflow будет запускаться новый контейнер docker in docker и там запускаться построение образа естественно кэшей не будет или надо как то придумывать как их хранить на ранере и пробрасывать в dind. Ну или руками сделать нужные образы и использоват их в Dockerfile. Правда пулиться они опять же будут походу каждый раз. Короче говоря тут есть чем поразбираться и пооптимизировать ...
## Настройка Gitea Actions
### Включение Actions в Gitea
1. **Проверьте версию Gitea**
Gitea Actions доступны начиная с версии 1.17.0. Убедитесь, что ваш сервер Gitea поддерживает Actions.
- Собирает образы для Linux AMD64 и ARM64 (docker buildx build \ ...)
- Публикует образы с тегом версии и `latest` (--push)
1 **create-release:**
чтобы авторизация сработала на докерхабе надо внести секреты DOCKERHUB_TOKEN, DOCKERHUB_USERNAME или вцелом для всей gitea в настройках или в настройках конкретного репозитория
я использовал докерхаб, но можно заморочиться и настроить работу с приватным репозиторием ...
- Запускается первым
- Использует контейнер собранный на базе golang:1.24 для сборки бинарников (image: ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:latest)
- Собирает бинарники для всех платформ (Linux, Windows, macOS)
- Создает архивы с бинарниками
- Создает релиз с именем текущей версии через Gitea API
- Загружает бинарники как assets релиза
2.**create-release:**
- Запускается после успешной сборки Docker образов
- Использует Go контейнер для сборки бинарников (image: golang:1.21)
- Собирает бинарники для всех платформ (Linux, Windows, macOS)
- Создает архивы с бинарниками
- Создает релиз через Gitea API
- Загружает бинарники как assets релиза
при каждом запуске, как я понимаю, данного job будет скачиваться и устанавливаться в контейнере, созданном на базе golang:1.21
для работы данного job используется кастомный образ - если бы мы использовали просто golang:1.24, то при каждом запуске данного job необходимо было бы скачивать jq и устанавливаться в контейнере (возможно со временем что то еще потребовалось бы)
```yaml
- name:Setup Go
- name: Setup Go container
run: |
# Install jq for JSON parsing
apt-get update && apt-get install -y jq
@@ -397,28 +437,129 @@ jobs:
jq --version
```
решение как говорится в лоб: чтобы убрать эту работу при каждом выполнении workflow надо сделать свой образ
**решение в лоб:** применено, чтобы убрать эту повторяющуюся работу при каждом выполнении workflow - сделан свой образ - "${DOCKERHUB_USERNAME}"/my-build-golang-runner:latest
``` Dockerfile
# базовый образ
FROM golang:1.24
# Install some packages
RUN apt-get update && apt-get install -y git ca-certificates jq
# Устанавливаем пакеты (одинаково работают на amd64/arm64)
RUN apt-get update && \
apt-get install -y --no-install-recommends \
git \
ca-certificates \
jq && \
rm -rf /var/lib/apt/lists/*
# (Опционально) Можно добавить команду по умолчанию
CMD ["bash"]
```
собратьего и запушить (желательно с мультиплатформенностью). конечно если вам не надо билдить образы для разных платформ тогда все попроще
Сначала собралего и запушил (желательно с мультиплатформенностью) на каком-то локальном АРМ (не раннере)
решение рабочее но надо всегда иметь под рукой АРм с buildx или лучше автоматизировать все и сделать задачу для сборки на раннере `.gitea/workflows/build-builder.yaml`
- Собираем образы для Linux AMD64 и ARM64 (команда docker buildx build \ ...)
- Публикуем образы с тегом версии и `latest` (опция --push команды docker buildx build ...)
чтобы авторизация сработала на докерхабе надо внести секреты DOCKERHUB_TOKEN, DOCKERHUB_USERNAME или вцелом для всего инстанса gitea в настройках инстанса или в настройках конкретного репозитория
я использовал докерхаб, но можно заморочиться и настроить работу с приватным репозиторием ...
Уже после ряда тестовых релизо выяснил, что запуски workflow `build.yaml` да собственно как и `build-builder.yaml` порождают на хосте раннера зависшие докер контейнеры buildx
```text
СONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2a9ad63c5a31 moby/buildkit:buildx-stable-1 "buildkitd --allow-i…" 11 seconds ago Up 10 seconds buildx_buildkit_test-buldx0
843eee192570 moby/buildkit:buildx-stable-1 "buildkitd --allow-i…" 22 minutes ago Up 22 minutes buildx_buildkit_modest_haibt0
```
Это происходит потому, что раннер запускает докер в докере контейнер также
docker run --privileged -it --rm -v /var/run/docker.sock:/var/run/docker.sock docker:28.3.2-dind sh
то есть пробрасывает хостовый сокет докер демона в контейнер и когда там выполняется `docker buildx create --use` контейнер запускается на хосте а не внутри docker:28.3.2-dind
Со временем это может превратиться в утечку ресурсов
Решения как минимум два - добавить параметр --name - `docker buildx create --name go-buildx --use` - тогда подхватится существующий контейнер или создастся новый. Второй способ удалять buildx `docker buildx rm --name go-buildx`
## Настройка секретов
@@ -441,12 +582,14 @@ docker buildx build \
### Создание токенов
**Gitea Token:**
1. Перейдите в настройки профиля → "Applications"
2. Создайте новый токен с правами на репозиторий
3. Скопируйте токен
4. В разделе Actions репозитория создайте секрет уровня репозитория - я создал с именем GITEATOKEN (такой не даст сделать: GITEA_TOKEN)
**Docker Hub Token:**
1. Войдите в Docker Hub
2. Перейдите в Account Settings → Security
3. Создайте новый Access Token
@@ -457,9 +600,9 @@ docker buildx build \
### Локальное тестирование
1. **Проверим синтаксис workflow:**
1 **Проверим синтаксис workflow:**
ну если мы в ide то наверное все автоматом отформатировано
ну если мы в ide, то наверное все хорошо и уже автоматом отформатировано ...
но тем не менее ...
```bash
@@ -467,7 +610,10 @@ docker buildx build \
yamllint .gitea/workflows/build.yaml
```
2. **Протестируем сборку локально:**
2 **Протестируем сборку локально:**
пока ручное тестирование
```bash
# Сборка для текущей платформы
go build -o hello-api main.go
@@ -477,7 +623,8 @@ docker buildx build \
GOOS=linux GOARCH=arm64 go build -o hello-api-linux-arm64 main.go
```
3. **Тестирование Docker образа:**
3 **Тестирование Docker образа:**
```bash
# Сборка образа
docker build -t hello-api:test .
@@ -486,19 +633,23 @@ docker buildx build \
docker run -p 8080:8080 hello-api:test
# Тестирование API
curl http://localhost:8080/health
curl http://localhost:8080/healthz
```
тут надо погонять curl по эндпойнтам, убедиться что приложение работает (пока тоже вручную)
### Запуск Actions
1. **Создаем тег:**
1 **Создаем тег вручную или скриптом (`scripts/release-interactive.sh`):**
```bash
git tag v1.1.20
git push origin v1.1.20
# или скрипт
# текст скрипта - запуск можно сделать через make
#release-interactive:
# @./scripts/release-interactive.sh
#!/bin/bash
@@ -519,7 +670,7 @@ docker buildx build \
echo ""
# Запрашиваем новую версию
read -p "Введите новую версию (формат X.Y.Z): " VERSION
read -r -p "Введите новую версию (формат X.Y.Z): " VERSION
# Проверяем, что версия не пустая
if [ -z "$VERSION" ]; then
@@ -539,7 +690,7 @@ docker buildx build \
echo " Текущая версия: $CURRENT_VERSION"
echo " Новая версия: $VERSION"
echo ""
read -p "Продолжить? (y/N): " CONFIRM
read -r -p "Продолжить? (y/N): " CONFIRM
if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
echo "❌ Релиз отменен"
@@ -594,6 +745,24 @@ docker buildx build \
echo "✅ Версия обновлена в main.go"
# Обновляем версию в makefile
echo "📝 Обновляем версию в makefile..."
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
sed -i '' "s/^VERSION=.*/VERSION=$VERSION/" makefile
else
# Linux
sed -i "s/^VERSION=.*/VERSION=$VERSION/" makefile
fi
# Проверяем, что изменение применилось
if ! grep -q "^VERSION=$VERSION" makefile; then
echo "Ошибка: Не удалось обновить версию в makefile"
exit 1
fi
echo "✅ Версия обновлена в makefile"
# Выполняем git команды
echo "📦 Добавляем изменения в git..."
git add .
@@ -611,60 +780,70 @@ docker buildx build \
echo "🎉 Релиз v$VERSION успешно завершен!"
echo "📋 Выполненные действия:"
echo " - Обновлена версия в main.go"
echo " - Обновлена версия в makefile"
echo " - Создан коммит с сообщением 'Release v$VERSION'"
echo " - Создан тег v$VERSION"
echo " - Изменения отправлены в удаленный репозиторий"
```
2. **Мониторинг выполнения:**
- Переходим в репозиторий → "Actions"
- Находим запущенный workflow
- Отслеживаем выполнение каждого job
2 **Мониторинг выполнения:**
- Переходим в репозиторий → "Actions"
- Находим запущенный workflow
- Отслеживаем выполнение каждого job
### Ожидаемый результат
После успешного выполнения:
1. **Docker образы** будут опубликованы в Docker Hub:
- `username/hello-api:v1.1.20`
- `username/hello-api:latest`
1 **Релиз** будет создан в Gitea с бинарниками:
2. **Релиз** будет создан в Gitea с бинарниками:
- `hello-api-linux-amd64.tar.gz`
- `hello-api-linux-arm64.tar.gz`
- `hello-api-windows-amd64.tar.gz`
- `hello-api-darwin-amd64.tar.gz`
- `hello-api-darwin-arm64.tar.gz`
- `hello-api-linux-amd64.tar.gz`
- `hello-api-linux-arm64.tar.gz`
- `hello-api-windows-amd64.tar.gz`
- `hello-api-darwin-amd64.tar.gz`
- `hello-api-darwin-arm64.tar.gz`
2 **Docker образы** будут опубликованы в Docker Hub:
- `username/hello-api:v1.1.20`
- `username/hello-api:latest`
3 **В ветке relese** появится новый коммит - на него можно, например, настроить деплой ArgoCD/flux в кластере k3s
## Мониторинг и отладка
### Просмотр логов
1. **В Gitea:**
- Переходим в репозиторий → "Actions"
- Выберем workflow
- Нажмем на job для просмотра логов
1 **В Gitea:**
2. **Отладка ошибок:**
- Проверим правильность секретов
- Убедимся в корректности путей к репозиторию
- Проверим права доступа токенов
- Переходим в репозиторий → "Actions"
- Выберем workflow
- Нажмем на job для просмотра логов
2 **Отладка ошибок:**
- Проверим правильность секретов
- Убедимся в корректности путей к репозиторию
- Проверим права доступа токенов
### Частые проблемы
1. **Ошибка авторизации в Docker Hub:**
- Проверим правильность `DOCKERHUB_TOKEN`
- Убедимся, что токен не истек
1 **Ошибка авторизации в Docker Hub:**
2. **Ошибка создания релиза:**
- Проверим права токена `GITEATOKEN`
- Убедимся, что тег не существует
- Проверим правильность `DOCKERHUB_TOKEN`
- Убедимся, что токен не истек
3. **Ошибка сборки:**
- Проверим зависимости в `go.mod`
- Убедимся в корректности Dockerfile
2 **Ошибка создания релиза:**
- Проверим права токена `GITEATOKEN`
- Убедимся, что тег не существует
3 **Ошибка сборки:**
- Проверим зависимости в `go.mod`
- Убедимся в корректности Dockerfile
## Заключение
@@ -699,12 +878,13 @@ Gitea Actions предоставляет мощные возможности д
### Архитектура системы
Этот и последующие разделы описывают инфраструктуру на которой я проверял все описанное выше.
Если у вас используются другие подходы, то можете пропустить их или ознакомиться для общего развития.
Этот и последующие разделы описывают инфраструктуру, на которой я проверял все описанное выше.
Если у вас используются другие подходы, то можете пропустить чтение этих разделов
или ознакомиться для общего развития.
Итак инфраструктура состоит из следующих компонентов:
```
``` text
Proxmox VE (ARM64)
├── K3s Cluster
├── Master Node
@@ -720,31 +900,34 @@ Proxmox VE (ARM64)
### Требования к системе
**Proxmox VE:**
- ARM64 архитектура
- Минимум 8GB RAM
- 100GB свободного места
- Поддержка LXC контейнеров
- ARM64 архитектура (orangepi 5 Plus)
- Минимум 8GB RAM (16Gb)
- 100GB свободного места (1 Gb)
- Поддержка LXC контейнеров (+)
**K3s Cluster:**
- Kubernetes 1.24+
- Helm 3.8+
- Ingress Controller (Traefik)
- Persistent Storage (Longhorn)
- Persistent Storage (NFS)
**LXC Container:**
- Ubuntu 22.04 LTS
- 4GB RAM
- 20GB дискового пространства
- Docker Engine
- Go 1.21+
## Установка Gitea в кластере K3s
### Анализ существующего кластера
Ваш кластер уже настроен и работает. Вот текущая конфигурация:
Текущая конфигурация:
**Узлы кластера:**
```bash
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
Как видите я организовал доступ через внешний IP к URL `https://direct-dev.ru/gitea`, то есть через префикс роута, опыт работы с actions показал, что лучше бы организовать было через поддомен третьего уровня: что то типа `https://gitea.direct-dev.ru` - в этом случае всякие разные предопределенные jobs типа checkout@v3 должны клонирование отрабатывать нормально.
``` bash
# Проверка секретов
kubectl get secrets -n gitea
```
### Настройка Actions в существующем Gitea
### Настройка Actions в существующем инстансе Gitea
echo"Ошибка: Неверный формат версии. Используйте формат X.Y.Z (например, 1.0.25)"
exit1
fi
echo"🚀 Начинаем релиз версии v$VERSION..."
# Проверяем, что мы в git репозитории
if ! git rev-parse --git-dir > /dev/null 2>&1;then
echo"Ошибка: Не найден git репозиторий"
exit1
fi
# Проверяем, что нет незакоммиченных изменений
if ! git diff-index --quiet HEAD --;then
echo"Ошибка: Есть незакоммиченные изменения. Сначала закоммитьте их."
exit1
fi
# Обновляем версию в main.go
echo"📝 Обновляем версию в main.go..."
if[["$OSTYPE"=="darwin"* ]];then
# macOS
sed -i ''"s/const version = \"[^\"]*\"/const version = \"$VERSION\"/" main.go
else
# Linux
sed -i "s/const version = \"[^\"]*\"/const version = \"$VERSION\"/" main.go
fi
# Проверяем, что изменение применилось
if ! grep -q "const version = \"$VERSION\"" main.go;then
echo"Ошибка: Не удалось обновить версию в main.go"
exit1
fi
echo"✅ Версия обновлена в main.go"
# Выполняем git команды
echo"📦 Добавляем изменения в git..."
git add .
echo"💾 Создаем коммит..."
git commit -m "Release v$VERSION"
echo"🏷️ Создаем тег..."
git tag -a "v$VERSION" -m "Release v$VERSION"
echo"🚀 Отправляем изменения и теги..."
git push
git push --tags
echo"🎉 Релиз v$VERSION успешно завершен!"
echo"📋 Выполненные действия:"
echo" - Обновлена версия в main.go"
echo" - Создан коммит с сообщением 'Release v$VERSION'"
echo" - Создан тег v$VERSION"
echo" - Изменения отправлены в удаленный репозиторий"
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.