13 Commits

Author SHA1 Message Date
9e431a00ce Release v1.0.36
Some checks failed
Release Build / create-release (push) Failing after 6m14s
Release Build / create-docker-image (push) Has been skipped
Release Build / update-to-release-branch (push) Has been skipped
2025-07-28 17:44:23 +06:00
75822f7fb8 Release v1.0.35
Some checks failed
Release Build / create-release (push) Failing after 6m17s
Release Build / create-docker-image (push) Has been skipped
Release Build / update-to-release-branch (push) Has been skipped
2025-07-28 17:33:06 +06:00
707cd82717 Release v1.0.34
Some checks failed
Release Build / create-release (push) Failing after 6m29s
Release Build / create-docker-image (push) Has been skipped
Release Build / update-to-release-branch (push) Has been skipped
2025-07-28 17:11:14 +06:00
6f10caa69d Release v1.0.33
Some checks failed
Release Build / create-release (push) Successful in 6m37s
Release Build / create-docker-image (push) Failing after 37s
Release Build / update-to-release-branch (push) Has been skipped
2025-07-28 17:00:47 +06:00
da3538051e Release v1.0.33
Some checks failed
Release Build / create-release (push) Failing after 3s
Release Build / create-docker-image (push) Has been skipped
Release Build / update-to-release-branch (push) Has been skipped
2025-07-28 16:59:35 +06:00
032bdaa619 Release v1.0.33
Some checks failed
Release Build / create-release (push) Failing after 2s
Release Build / create-docker-image (push) Has been skipped
Release Build / update-to-release-branch (push) Has been skipped
2025-07-28 16:56:50 +06:00
b786ed1bf8 Release v1.0.33
Some checks failed
Release Build / create-release (push) Failing after 3s
Release Build / create-docker-image (push) Has been skipped
Release Build / update-to-release-branch (push) Has been skipped
2025-07-28 16:55:34 +06:00
231867a310 Release v1.0.33
Some checks failed
Release Build / create-release (push) Failing after 2s
Release Build / create-docker-image (push) Has been skipped
Release Build / update-to-release-branch (push) Has been skipped
2025-07-28 16:50:29 +06:00
9d82d42680 Release v1.0.32
Some checks failed
Release Build / create-release (push) Failing after 6s
Release Build / create-docker-image (push) Has been skipped
Release Build / update-to-release-branch (push) Has been skipped
2025-07-28 16:26:11 +06:00
9da418648c changed builder image
All checks were successful
Build Builder Docker Image / create-builder-docker-image (push) Successful in 5m42s
2025-07-28 16:02:16 +06:00
7a33e815af Release v1.0.31
All checks were successful
Release Build / create-release (push) Successful in 6m27s
Release Build / create-docker-image (push) Successful in 3m32s
Release Build / update-to-release-branch (push) Successful in 8s
2025-07-28 15:47:12 +06:00
bf643393ad Release v1.0.30
All checks were successful
Release Build / create-release (push) Successful in 6m30s
Release Build / create-docker-image (push) Successful in 3m41s
Release Build / update-to-release-branch (push) Successful in 8s
2025-07-28 14:05:01 +06:00
c4a3ea4d98 Release v1.0.28
All checks were successful
Release Build / create-release (push) Successful in 6m40s
Release Build / create-docker-image (push) Successful in 3m28s
Release Build / update-to-release-branch (push) Successful in 7s
2025-07-28 12:42:44 +06:00
12 changed files with 1071 additions and 450 deletions

View File

@@ -1,4 +1,4 @@
name: Release Build name: Build Builder Docker Image
on: on:
push: push:
tags: tags:
@@ -21,26 +21,31 @@ jobs:
echo "github.sha = ${{ github.sha }}" echo "github.sha = ${{ github.sha }}"
echo "github.repository = ${{ github.repository }}" echo "github.repository = ${{ github.repository }}"
echo "========================" echo "========================"
echo "Cloning..."
git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
cd hello_gitea cd hello_gitea
echo "Checkout to ${{ github.ref }} ..."
git checkout ${{ github.ref }} git checkout ${{ github.ref }}
- name: Setup Docker Buildx - name: Setup Docker Buildx
run: | run: |
# Docker is already installed in docker:dind image # Docker is already installed in docker:dind image
echo "look at docker version"
docker --version docker --version
# Setup Docker Buildx for multi-platform builds # Setup Docker Buildx for multi-platform builds
docker buildx create --use echo "setup buildx"
docker buildx create --name builder-builx --use
docker buildx inspect --bootstrap docker buildx inspect --bootstrap
- name: Login to Docker Hub - name: Login to Docker Hub
run: | run: |
echo "login to docker hub ..."
echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
- name: Build multi-platform Docker images - name: Build multi-platform Docker images
run: | run: |
cd hello_gitea cd hello_gitea
# Build multi-platform images using buildx echo "Build multi-platform images using buildx ..."
docker buildx build \ docker buildx build \
--platform linux/amd64,linux/arm64 \ --platform linux/amd64,linux/arm64 \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:${{ github.ref_name }} \ --tag ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:${{ github.ref_name }} \
@@ -49,3 +54,6 @@ jobs:
-f Dockerfile.builder \ -f Dockerfile.builder \
. .
- name: Remove buildx
run: |
docker buildx rm builder-builx

View File

@@ -5,139 +5,181 @@ on:
- v* - v*
jobs: jobs:
# create-release: create-release:
# runs-on: ubuntu-latest runs-on: ubuntu-latest
# container: container:
# # image: golang:1.21 # image: golang:1.21
# image: ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:latest # image: ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:builder-1.0.32
# needs: create-release-branch image: ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:latest
# steps: steps:
# - name: Checkout repository - name: Checkout repository
# run: | run: |
# git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
# cd hello_gitea cd hello_gitea
# git checkout ${{ github.ref }} git checkout ${{ github.ref }}
# - name: Setup Go - name: Setup Go
# run: | run: |
# # Install jq for JSON parsing # Install jq for JSON parsing
# apt-get update && apt-get install -y jq # apt-get update && apt-get install -y jq
# git --version git --version
# go version go version
# jq --version jq --version
# - name: Build all binaries - name: Build all binaries
# run: | run: |
# cd hello_gitea cd hello_gitea
# mkdir -p bin mkdir -p bin
echo "Building for all platforms..."
# # Build for all platforms # Build for all platforms
# GOOS=linux GOARCH=amd64 go build -o bin/hello-api-linux-amd64 main.go echo "Building for linux amd64..."
# GOOS=linux GOARCH=arm64 go build -o bin/hello-api-linux-arm64 main.go quick-build linux amd64
# GOOS=windows GOARCH=amd64 go build -o bin/hello-api-windows-amd64.exe main.go
# GOOS=darwin GOARCH=amd64 go build -o bin/hello-api-darwin-amd64 main.go
# GOOS=darwin GOARCH=arm64 go build -o bin/hello-api-darwin-arm64 main.go
# # Create archives echo "Building for linux arm64..."
# cd bin quick-build linux arm64
# tar -czf hello-api-linux-amd64.tar.gz hello-api-linux-amd64
# tar -czf hello-api-linux-arm64.tar.gz hello-api-linux-arm64
# tar -czf hello-api-windows-amd64.tar.gz hello-api-windows-amd64.exe
# tar -czf hello-api-darwin-amd64.tar.gz hello-api-darwin-amd64
# tar -czf hello-api-darwin-arm64.tar.gz hello-api-darwin-arm64
# ls -la echo "Building for windows amd64..."
quick-build windows amd64
# - name: Create Release echo "Building for darwin amd64..."
# run: | quick-build darwin amd64
# cd hello_gitea
# # Create release using Gitea API
# curl -X POST \
# -H "Authorization: token ${{ secrets.GITEATOKEN }}" \
# -H "Content-Type: application/json" \
# -d '{
# "tag_name": "${{ github.ref_name }}",
# "name": "Release ${{ github.ref_name }}",
# "body": "Automated release with multi-platform binaries and Docker image",
# "draft": false,
# "prerelease": false
# }' \
# "https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases"
# # Upload assets echo "Building for darwin arm64..."
# RELEASE_ID=$(curl -s -H "Authorization: token ${{ secrets.GITEATOKEN }}" \ quick-build darwin arm64
# "https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases/tags/${{ github.ref_name }}" | \
# jq -r '.id')
# # Upload all binaries echo "Listing bin directory..."
# for file in bin/*.tar.gz; do ls -la bin
# echo "Uploading $file..."
# curl -X POST \
# -H "Authorization: token ${{ secrets.GITEATOKEN }}" \
# -H "Content-Type: application/octet-stream" \
# --data-binary @$file \
# "https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases/$RELEASE_ID/assets?name=$(basename $file)"
# done
# create-docker-image: # Create archives
# runs-on: ubuntu-latest echo "Creating archives..."
# container: cd bin
# image: docker:28.3.2-dind
# needs: create-release
# steps:
# - name: Checkout repository
# run: |
# # Install git
# apk add --no-cache git
# echo "=== GitHub Variables ===" # Create archives with correct file names
# echo "github.ref = ${{ github.ref }}" echo "Creating archives for linux amd64..."
# echo "github.ref_name = ${{ github.ref_name }}" tar -czf hello-api-linux-amd64.tar.gz hello-api-linux-amd64
# echo "github.sha = ${{ github.sha }}"
# echo "github.repository = ${{ github.repository }}"
# echo "========================"
# git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
# cd hello_gitea
# git checkout ${{ github.ref }}
# - name: Setup Docker Buildx echo "Creating archives for linux arm64..."
# run: | tar -czf hello-api-linux-arm64.tar.gz hello-api-linux-arm64
# # Docker is already installed in docker:dind image
# docker --version
# # Setup Docker Buildx for multi-platform builds echo "Creating archives for windows amd64..."
# docker buildx create --use mv hello-api-windows-amd64 hello-api-windows-amd64.exe
# docker buildx inspect --bootstrap tar -czf hello-api-windows-amd64.tar.gz hello-api-windows-amd64.exe
# - name: Login to Docker Hub echo "Creating archives for darwin amd64..."
# run: | tar -czf hello-api-darwin-amd64.tar.gz hello-api-darwin-amd64
# echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
# - name: Build multi-platform Docker images echo "Creating archives for darwin arm64..."
# run: | tar -czf hello-api-darwin-arm64.tar.gz hello-api-darwin-arm64
# cd hello_gitea
# # Build multi-platform images using buildx
# docker buildx build \
# --platform linux/amd64,linux/arm64 \
# --tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:${{ github.ref_name }} \
# --tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:latest \
# --push \
# .
create-release-branch: echo "Listing bin directory again ..."
ls -la
- name: Create Release
run: |
cd hello_gitea
# Create release using Gitea API
echo "Creating release..."
curl -X POST \
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
-H "Content-Type: application/json" \
-d '{
"tag_name": "${{ github.ref_name }}",
"name": "Release ${{ github.ref_name }}",
"body": "Automated release with multi-platform binaries and Docker image",
"draft": false,
"prerelease": false
}' \
"https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases"
echo "Getting release id..."
RELEASE_ID=$(curl -s -H "Authorization: token ${{ secrets.GITEATOKEN }}" \
"https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases/tags/${{ github.ref_name }}" | \
jq -r '.id')
# Upload all binaries
echo "Uploading assets..."
for file in bin/*.tar.gz; do
echo "Uploading $file..."
curl -X POST \
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
-H "Content-Type: application/octet-stream" \
--data-binary @$file \
"https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases/$RELEASE_ID/assets?name=$(basename $file)"
done
echo "Release created successfully"
create-docker-image:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: docker:28.3.2-dind image: docker:28.3.2-dind
# needs: create-docker-image needs: create-release
steps: steps:
- name: Create Release Branch - name: Checkout repository
run: | run: |
# Install git
apk add --no-cache git
echo "=== GitHub Variables ===" echo "=== GitHub Variables ==="
echo "github.ref = ${{ github.ref }}" echo "github.ref = ${{ github.ref }}"
echo "github.ref_name = ${{ github.ref_name }}" echo "github.ref_name = ${{ github.ref_name }}"
echo "github.sha = ${{ github.sha }}" echo "github.sha = ${{ github.sha }}"
echo "github.repository = ${{ github.repository }}" echo "github.repository = ${{ github.repository }}"
echo "========================" echo "========================"
git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
cd hello_gitea
git checkout ${{ github.ref }}
- name: Setup Docker Buildx
run: |
# Docker is already installed in docker:dind image
docker --version
echo "Setting up Docker Buildx for multi-platform builds..."
# Setup Docker Buildx for multi-platform builds
docker buildx create --name go-buildx --use
docker buildx inspect --bootstrap
- name: Login to Docker Hub
run: |
echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
- name: Build multi-platform Docker images
run: |
cd hello_gitea
echo "Building multi-platform images using buildx..."
# Build multi-platform images using buildx
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:${{ github.ref_name }} \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:latest \
--push \
.
echo "Multi-platform images built successfully"
- name: Remove buildx
run: |
echo "Removing buildx..."
docker buildx rm go-buildx
update-to-release-branch:
runs-on: ubuntu-latest
container:
image: docker:28.3.2-dind
needs: create-docker-image
steps:
- name: Create Release Branch
run: |
echo "Creating release branch..."
echo "=== GitHub Variables ==="
echo "github.ref = ${{ github.ref }}"
echo "github.ref_name = ${{ github.ref_name }}"
echo "github.sha = ${{ github.sha }}"
echo "github.repository = ${{ github.repository }}"
echo "DOCKERHUB_USERNAME = ${{ secrets.DOCKERHUB_USERNAME }}"
echo "DOCKERHUB_TOKEN = ${{ secrets.DOCKERHUB_TOKEN }}"
echo "GITEATOKEN = ${{ secrets.GITEATOKEN }}"
echo "========================"
# Clone repository # Clone repository
echo "Cloning repository..." echo "Cloning repository..."
git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
@@ -167,3 +209,4 @@ jobs:
# Push changes to release branch # Push changes to release branch
echo "Pushing changes to release branch..." echo "Pushing changes to release branch..."
git push origin release --force git push origin release --force
echo "Changes pushed to release branch successfully"

View File

@@ -1,5 +1,5 @@
# Build stage # Build stage
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder
# Install git and ca-certificates # Install git and ca-certificates
RUN apk --no-cache add git ca-certificates RUN apk --no-cache add git ca-certificates

View File

@@ -9,5 +9,24 @@ RUN apt-get update && \
jq && \ jq && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
# Создаем рабочую директорию
WORKDIR /app
# Копируем файлы зависимостей
COPY go.mod go.sum ./
# Предварительно загружаем все зависимости
RUN go mod download && go mod verify
# Создаем скрипт для быстрой сборки
COPY scripts/quick-build.sh /usr/local/bin/quick-build
# делаем скрипт исполняемым
RUN chmod +x /usr/local/bin/quick-build
# Устанавливаем переменные окружения
ENV GOPATH=/go
ENV PATH=$PATH:/go/bin:/usr/local/bin
# (Опционально) Можно добавить команду по умолчанию # (Опционально) Можно добавить команду по умолчанию
CMD ["bash"] CMD ["bash"]

238
README.md
View File

@@ -1,12 +1,15 @@
# Hello Gitea API # Hello Gitea API
Простой REST API сервер, построенный на Go с использованием Gin framework. Современный REST API сервер, построенный на Go с использованием Gin framework и структурированного логирования.
## 🚀 Возможности ## 🚀 Возможности
- ✅ REST API с JSON ответами - ✅ REST API с JSON ответами
- ✅ Health check endpoint - ✅ Health check endpoint
- ✅ CORS поддержка - ✅ CORS поддержка
-**Современное структурированное логирование** (Go 1.24+)
-**Настраиваемые уровни и форматы логирования**
-**Системная информация и мониторинг**
- ✅ Мультиплатформенная сборка - ✅ Мультиплатформенная сборка
- ✅ Docker образы для Linux AMD64/ARM64 - ✅ Docker образы для Linux AMD64/ARM64
- ✅ Автоматические релизы через Gitea Actions - ✅ Автоматические релизы через Gitea Actions
@@ -37,6 +40,8 @@ go run main.go
## 🔧 Конфигурация ## 🔧 Конфигурация
### Основные настройки
Сервер запускается на порту 8080 по умолчанию. Можно изменить через переменную окружения: Сервер запускается на порту 8080 по умолчанию. Можно изменить через переменную окружения:
```bash ```bash
@@ -44,46 +49,98 @@ export PORT=3000
./hello-api ./hello-api
``` ```
### Настройка логирования
Приложение поддерживает гибкую настройку логирования через переменные окружения:
#### Уровни логирования (`LOG_LEVEL`)
```bash
# Доступные уровни (по возрастанию важности):
export LOG_LEVEL=DEBUG # Все сообщения
export LOG_LEVEL=INFO # Информационные и выше
export LOG_LEVEL=WARN # Предупреждения и выше
export LOG_LEVEL=ERROR # Только ошибки
```
#### Форматы логирования (`LOG_FORMAT`)
```bash
# JSON формат (по умолчанию) - для production
export LOG_FORMAT=json
# Текстовый формат - для разработки
export LOG_FORMAT=text
```
#### Примеры конфигурации
**Для разработки:**
```bash
export LOG_LEVEL=DEBUG
export LOG_FORMAT=text
export PORT=8080
go run main.go
```
**Для production:**
```bash
export LOG_LEVEL=INFO
export LOG_FORMAT=json
export PORT=8080
./hello-api
```
## 📡 API Endpoints ## 📡 API Endpoints
### GET / ### GET /
Основной endpoint Основной endpoint
**Ответ:** **Ответ:**
```json ```json
{ {
"message": "Hello, World!", "message": "Hello, World!",
"version": "1.0.0" "version": "1.0.33"
} }
``` ```
### GET /health ### GET /healthz
Health check endpoint Health check endpoint
**Ответ:** **Ответ:**
```json ```json
{ {
"status": "ok", "status": "ok",
"version": "1.0.0" "version": "1.0.33"
} }
``` ```
### GET /api/v1/info ### GET /api/v1/info
Информация о сервисе Информация о сервисе
**Ответ:** **Ответ:**
```json ```json
{ {
"service": "hello-api", "service": "hello-api",
"status": "running", "status": "running",
"version": "1.0.0" "version": "1.0.33"
} }
``` ```
### POST /api/v1/echo ### POST /api/v1/echo
Echo endpoint - возвращает отправленное сообщение Echo endpoint - возвращает отправленное сообщение
**Запрос:** **Запрос:**
```json ```json
{ {
"message": "Hello from client!" "message": "Hello from client!"
@@ -91,18 +148,149 @@ Echo endpoint - возвращает отправленное сообщение
``` ```
**Ответ:** **Ответ:**
```json ```json
{ {
"echo": "Hello from client!", "echo": "Hello from client!",
"version": "1.0.0" "version": "1.0.33"
} }
``` ```
## 🛠 Разработка ### GET /api/v1/config
**Новый endpoint** - системная информация и конфигурация
**Ответ:**
```json
{
"version": "1.0.33",
"system_info": {
"go_version": "go1.24.0",
"os": "linux",
"architecture": "amd64",
"num_cpu": 8,
"start_time": "2024-01-15T10:30:45Z"
},
"environment": {
"PATH": "/usr/local/bin:/usr/bin:/bin",
"PORT": "8080",
"LOG_LEVEL": "INFO"
},
"uptime": "2h30m15s"
}
```
### POST /api/v1/log-test
**Новый endpoint** - тестирование уровней логирования
**Запрос:**
```json
{
"level": "debug",
"message": "Test log message"
}
```
**Ответ:**
```json
{
"status": "logged",
"level": "debug",
"message": "Test log message"
}
```
## 📊 Логирование
### Структурированное логирование
Приложение использует современную систему логирования Go 1.24+ (`log/slog`) с поддержкой:
- **Структурированных логов** в JSON и текстовом формате
- **Уровней логирования** (DEBUG, INFO, WARN, ERROR)
- **Контекстной информации** (IP клиента, User-Agent, время запроса)
- **Автоматического форматирования** времени
- **Фильтрации чувствительных данных**
### Примеры логов
#### JSON формат (production)
```json
{
"time": "2024-01-15T10:30:45.123Z",
"level": "INFO",
"msg": "HTTP Request",
"method": "GET",
"path": "/api/v1/config",
"status": 200,
"latency": "1.234ms",
"client_ip": "192.168.1.100",
"user_agent": "curl/7.68.0",
"timestamp": "2024-01-15T10:30:45.123Z"
}
```
#### Текстовый формат (development)
``` text
2024-01-15T10:30:45.123Z INFO HTTP Request method=GET path=/api/v1/config status=200 latency=1.234ms client_ip=192.168.1.100 user_agent="curl/7.68.0"
```
## Основные изменения в README
### 🆕 **Новые разделы:**
1. **Конфигурация логирования** - подробное описание переменных окружения
2. **Форматы логирования** - примеры JSON и текстового формата
3. **Новые API endpoints** - `/api/v1/config` и `/api/v1/log-test`
4. **Безопасность логирования** - фильтрация чувствительных данных
### 📊 **Детальное описание логирования:**
- **Уровни логирования** (DEBUG, INFO, WARN, ERROR)
- **Форматы** (JSON для production, text для разработки)
- **Примеры логов** с реальными данными
- **Контекстная информация** в логах
### 🔧 **Практические примеры:**
- Настройка для разработки и production
- Команды для тестирования
- Отладочные приемы
### 📦 **Улучшенная структура:**
- Четкое разделение возможностей
- Пошаговые инструкции
- Примеры конфигурации
- Команды для тестирования
Теперь README полностью отражает современные возможности приложения с детальным описанием системы логирования! 🎉
### Логируемые события
- **HTTP запросы** с детальной информацией
- **Ошибки приложения** с контекстом
- **Системные события** (запуск, остановка)
- **API вызовы** с параметрами
- **Конфигурационные изменения**
### Безопасность
- **Автоматическая фильтрация** чувствительных переменных окружения
- **Безопасное логирование** без утечки секретов
- **Контролируемые уровни** для разных сред
## Разработка
### Зависимости ### Зависимости
- Go 1.21+ - Go 1.24+
- Gin framework - Gin framework
### Сборка ### Сборка
@@ -128,16 +316,42 @@ GOOS=darwin GOARCH=arm64 go build -o hello-api-darwin-arm64 main.go
### Тестирование ### Тестирование
```bash ```bash
# Запуск сервера # Запуск сервера с отладочным логированием
export LOG_LEVEL=DEBUG
export LOG_FORMAT=text
go run main.go go run main.go
# Тестирование API # Тестирование API
curl http://localhost:8080/ curl http://localhost:8080/
curl http://localhost:8080/health curl http://localhost:8080/healthz
curl http://localhost:8080/api/v1/info curl http://localhost:8080/api/v1/info
curl http://localhost:8080/api/v1/config
# Тестирование echo
curl -X POST http://localhost:8080/api/v1/echo \ curl -X POST http://localhost:8080/api/v1/echo \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"message":"Hello!"}' -d '{"message":"Hello!"}'
# Тестирование логирования
curl -X POST http://localhost:8080/api/v1/log-test \
-H "Content-Type: application/json" \
-d '{"level": "debug", "message": "Test log message"}'
```
### Отладка
Для детального анализа работы приложения:
```bash
# Включить отладочное логирование
export LOG_LEVEL=DEBUG
export LOG_FORMAT=text
# Запустить приложение
go run main.go
# В другом терминале - мониторинг логов
tail -f /var/log/application.log # если логи в файл
``` ```
## 🚀 CI/CD ## 🚀 CI/CD
@@ -161,8 +375,6 @@ curl -X POST http://localhost:8080/api/v1/echo \
Таким образом, данный файл обеспечивает автоматическую сборку и публикацию артефактов проекта при выпуске новых версий, что упрощает процесс релиза и гарантирует наличие актуальных образов и бинарников для пользователей. Таким образом, данный файл обеспечивает автоматическую сборку и публикацию артефактов проекта при выпуске новых версий, что упрощает процесс релиза и гарантирует наличие актуальных образов и бинарников для пользователей.
## 📄 Лицензия ## 📄 Лицензия
MIT License MIT Licens

View File

@@ -1,124 +0,0 @@
name: Release Build
on:
push:
tags:
- v*
jobs:
create-docker-image:
runs-on: ubuntu-latest
container:
image: docker:28.3.2-dind
steps:
- name: Checkout repository
run: |
# Install git
apk add --no-cache git
echo "=== GitHub Variables ==="
echo "github.ref = ${{ github.ref }}"
echo "github.ref_name = ${{ github.ref_name }}"
echo "github.sha = ${{ github.sha }}"
echo "github.repository = ${{ github.repository }}"
echo "========================"
git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
cd hello_gitea
git checkout ${{ github.ref }}
- name: Setup Docker Buildx
run: |
# Docker is already installed in docker:dind image
docker --version
# Setup Docker Buildx for multi-platform builds
docker buildx create --use
docker buildx inspect --bootstrap
- name: Login to Docker Hub
run: |
echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
- name: Build multi-platform Docker images
run: |
cd hello_gitea
# Build multi-platform images using buildx
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:${{ github.ref_name }} \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:latest \
--push \
.
create-release:
runs-on: ubuntu-latest
container:
# image: golang:1.21
image: ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:latest
needs: create-docker-image
steps:
- name: Checkout repository
run: |
git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
cd hello_gitea
git checkout ${{ github.ref }}
- name: Setup Go
run: |
# Install jq for JSON parsing
apt-get update && apt-get install -y jq
git --version
go version
jq --version
- name: Build all binaries
run: |
cd hello_gitea
mkdir -p bin
# Build for all platforms
GOOS=linux GOARCH=amd64 go build -o bin/hello-api-linux-amd64 main.go
GOOS=linux GOARCH=arm64 go build -o bin/hello-api-linux-arm64 main.go
GOOS=windows GOARCH=amd64 go build -o bin/hello-api-windows-amd64.exe main.go
GOOS=darwin GOARCH=amd64 go build -o bin/hello-api-darwin-amd64 main.go
GOOS=darwin GOARCH=arm64 go build -o bin/hello-api-darwin-arm64 main.go
# Create archives
cd bin
tar -czf hello-api-linux-amd64.tar.gz hello-api-linux-amd64
tar -czf hello-api-linux-arm64.tar.gz hello-api-linux-arm64
tar -czf hello-api-windows-amd64.tar.gz hello-api-windows-amd64.exe
tar -czf hello-api-darwin-amd64.tar.gz hello-api-darwin-amd64
tar -czf hello-api-darwin-arm64.tar.gz hello-api-darwin-arm64
ls -la
- name: Create Release
run: |
cd hello_gitea
# Create release using Gitea API
curl -X POST \
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
-H "Content-Type: application/json" \
-d '{
"tag_name": "${{ github.ref_name }}",
"name": "Release ${{ github.ref_name }}",
"body": "Automated release with multi-platform binaries and Docker image",
"draft": false,
"prerelease": false
}' \
"https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases"
# Upload assets
RELEASE_ID=$(curl -s -H "Authorization: token ${{ secrets.GITEATOKEN }}" \
"https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases/tags/${{ github.ref_name }}" | \
jq -r '.id')
# Upload all binaries
for file in bin/*.tar.gz; do
echo "Uploading $file..."
curl -X POST \
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
-H "Content-Type: application/octet-stream" \
--data-binary @$file \
"https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases/$RELEASE_ID/assets?name=$(basename $file)"
done

View File

@@ -1,13 +1,13 @@
# Настройка Gitea Actions для Go проекта: Полное руководство # Настройка Gitea Actions для Go проекта: Полное руководство
--- ```metadata
**readTime:** 15-20 минут readTime: 15-20 минут
**date:** 2025-07-27 18:00 date: 2025-07-27 18:00
**author:** Direct-Dev(aka Антон Кузнецов) author: Direct-Dev(aka Антон Кузнецов)
**level:** Средний level: Средний
**tags:** #gitea #gitea-actions #ci-cd #go #docker #devops #automation #k3s tags: #gitea #gitea-actions #ci-cd #go #docker #devops #automation #k3s
**version:** 1.0.0 version: 1.0.0
--- ```
## Содержание ## Содержание
@@ -19,9 +19,9 @@
6. [Тестирование и запуск](#тестирование-и-запуск) 6. [Тестирование и запуск](#тестирование-и-запуск)
7. [Мониторинг и отладка](#мониторинг-и-отладка) 7. [Мониторинг и отладка](#мониторинг-и-отладка)
8. [Заключение](#заключение) 8. [Заключение](#заключение)
9. [Инфраструктура](#инфраструктура) A. [Инфраструктура](#инфраструктура)
10. [Установка Gitea в кластере K3s](#установка-gitea-в-кластере-k3s) B. [Установка Gitea в кластере K3s](#установка-gitea-в-кластере-k3s)
11. [Настройка Gitea Runner в LXC контейнере](#настройка-gitea-runner-в-lxc-контейнере) C. [Настройка Gitea Runner в LXC контейнере](#настройка-gitea-runner-в-lxc-контейнере)
## Введение ## Введение
@@ -43,7 +43,7 @@ Gitea Actions — это встроенная система непрерывн
Собственно функциональная часть проекта Go не блещет оригинальностью и имеет следующую простую структуру: Собственно функциональная часть проекта Go не блещет оригинальностью и имеет следующую простую структуру:
``` ``` text
hello_gitea/ hello_gitea/
├── main.go # Основной код приложения ├── main.go # Основной код приложения
├── go.mod # Зависимости Go ├── go.mod # Зависимости Go
@@ -93,7 +93,7 @@ func main() {
}) })
// Endpoints // Endpoints
r.GET("/health", func(c *gin.Context) { r.GET("/healthz", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"status": "ok", "status": "ok",
"version": version, "version": version,
@@ -197,7 +197,6 @@ CMD ["./hello-api"]
базововго образа для каждого из этапов использовать предварительно собранный образ со всем необходимым. базововго образа для каждого из этапов использовать предварительно собранный образ со всем необходимым.
При каждом запуске workflow будет запускаться новый контейнер docker in docker и там запускаться построение образа естественно кэшей не будет или надо как то придумывать как их хранить на ранере и пробрасывать в dind. Ну или руками сделать нужные образы и использоват их в Dockerfile. Правда пулиться они опять же будут походу каждый раз. Короче говоря тут есть чем поразбираться и пооптимизировать ... При каждом запуске workflow будет запускаться новый контейнер docker in docker и там запускаться построение образа естественно кэшей не будет или надо как то придумывать как их хранить на ранере и пробрасывать в dind. Ну или руками сделать нужные образы и использоват их в Dockerfile. Правда пулиться они опять же будут походу каждый раз. Короче говоря тут есть чем поразбираться и пооптимизировать ...
## Настройка Gitea Actions ## Настройка Gitea Actions
### Включение Actions в Gitea ### Включение Actions в Gitea
@@ -242,55 +241,11 @@ on:
- v* - v*
jobs: jobs:
create-docker-image:
runs-on: ubuntu-latest
container:
image: docker:28.3.2-dind
steps:
- name: Checkout repository
run: |
# Install git
apk add --no-cache git
echo "=== GitHub Variables ==="
echo "github.ref = ${{ github.ref }}"
echo "github.ref_name = ${{ github.ref_name }}"
echo "github.sha = ${{ github.sha }}"
echo "github.repository = ${{ github.repository }}"
echo "========================"
git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
cd hello_gitea
git checkout ${{ github.ref }}
- name: Setup Docker Buildx
run: |
# Docker is already installed in docker:dind image
docker --version
# Setup Docker Buildx for multi-platform builds
docker buildx create --use
docker buildx inspect --bootstrap
- name: Login to Docker Hub
run: |
echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
- name: Build multi-platform Docker images
run: |
cd hello_gitea
# Build multi-platform images using buildx
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:${{ github.ref_name }} \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:latest \
--push \
.
create-release: create-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: golang:1.21 # image: golang:1.21
needs: create-docker-image image: ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:latest
steps: steps:
- name: Checkout repository - name: Checkout repository
run: | run: |
@@ -301,7 +256,7 @@ jobs:
- name: Setup Go - name: Setup Go
run: | run: |
# Install jq for JSON parsing # Install jq for JSON parsing
apt-get update && apt-get install -y jq # apt-get update && apt-get install -y jq
git --version git --version
go version go version
jq --version jq --version
@@ -358,37 +313,121 @@ jobs:
--data-binary @$file \ --data-binary @$file \
"https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases/$RELEASE_ID/assets?name=$(basename $file)" "https://direct-dev.ru/gitea/api/v1/repos/GiteaAdmin/hello_gitea/releases/$RELEASE_ID/assets?name=$(basename $file)"
done done
create-docker-image:
runs-on: ubuntu-latest
container:
image: docker:28.3.2-dind
needs: create-release
steps:
- name: Checkout repository
run: |
# Install git
apk add --no-cache git
echo "=== GitHub Variables ==="
echo "github.ref = ${{ github.ref }}"
echo "github.ref_name = ${{ github.ref_name }}"
echo "github.sha = ${{ github.sha }}"
echo "github.repository = ${{ github.repository }}"
echo "========================"
git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
cd hello_gitea
git checkout ${{ github.ref }}
- name: Setup Docker Buildx
run: |
# Docker is already installed in docker:dind image
docker --version
# Setup Docker Buildx for multi-platform builds
docker buildx create --use
docker buildx inspect --bootstrap
- name: Login to Docker Hub
run: |
echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
- name: Build multi-platform Docker images
run: |
cd hello_gitea
# Build multi-platform images using buildx
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:${{ github.ref_name }} \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/hello-api:latest \
--push \
.
update-to-release-branch:
runs-on: ubuntu-latest
container:
image: docker:28.3.2-dind
needs: create-docker-image
steps:
- name: Create Release Branch
run: |
echo "=== GitHub Variables ==="
echo "github.ref = ${{ github.ref }}"
echo "github.ref_name = ${{ github.ref_name }}"
echo "github.sha = ${{ github.sha }}"
echo "github.repository = ${{ github.repository }}"
echo "DOCKERHUB_USERNAME = ${{ secrets.DOCKERHUB_USERNAME }}"
echo "DOCKERHUB_TOKEN = ${{ secrets.DOCKERHUB_TOKEN }}"
echo "GITEATOKEN = ${{ secrets.GITEATOKEN }}"
echo "========================"
# Clone repository
echo "Cloning repository..."
git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
cd hello_gitea
# Configure git
echo "Configuring git..."
git config user.email "info@direct-dev.ru"
git config user.name "Direct-Dev-Robot"
# Check if release branch exists
echo "Checking if release branch exists..."
if git ls-remote --heads origin release | grep -q release; then
echo "Release branch exists, checking out..."
git checkout release
echo "release branch exists - pulling release branch..."
git pull origin release
else
echo "release branch does not exist - creating new release branch..."
git checkout -b release
fi
# Reset to the tag commit
echo "Resetting to the tag commit ${{ github.ref_name }} ..."
git reset --hard ${{ github.ref_name }}
# Push changes to release branch
echo "Pushing changes to release branch..."
git push origin release --force
``` ```
### Разберемся как работает workflow ### Разберемся как работает workflow
**Триггеры:** **Триггеры:**
- Workflow запускается при создании тега, начинающегося с `v*` (например, `v1.0.0`)
- Workflow запускается при пуше в Gitea тега, начинающегося с `v*` (например, `v1.1.29`)
**Jobs:** **Jobs:**
1. **create-docker-image:** - создание образов docker с нашим проектом 1 **create-release:**
- Используем Docker-in-Docker контейнер (image: docker:28.3.2-dind)
- Настраиваем Docker Buildx для мультиплатформенной сборки (docker buildx create --use docker buildx inspect --bootstrap)
- Авторизуемч в Docker Hub (echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin)
- Собирает образы для Linux AMD64 и ARM64 (docker buildx build \ ...)
- Публикует образы с тегом версии и `latest` (--push)
чтобы авторизация сработала на докерхабе надо внести секреты DOCKERHUB_TOKEN, DOCKERHUB_USERNAME или вцелом для всей gitea в настройках или в настройках конкретного репозитория - Эта таска запускается первой и не требует никаких зависимых тасков выполненными
я использовал докерхаб, но можно заморочиться и настроить работу с приватным репозиторием ... - Использует контейнер собранный на базе golang:1.24 для сборки бинарников (image: ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:latest)
2. **create-release:**
- Запускается после успешной сборки Docker образов
- Использует Go контейнер для сборки бинарников (image: golang:1.21)
- Собирает бинарники для всех платформ (Linux, Windows, macOS) - Собирает бинарники для всех платформ (Linux, Windows, macOS)
- Создает архивы с бинарниками - Создает архивы с бинарниками
- Создает релиз через Gitea API - Создает релиз с именем текущей версии через Gitea API
- Загружает бинарники как assets релиза - Загружает бинарники как assets релиза
при каждом запуске, как я понимаю, данного job будет скачиваться и устанавливаться в контейнере, созданном на базе golang:1.21 для работы данного job используется кастомный образ - если бы мы использовали просто golang:1.24, то при каждом запуске данного job необходимо было бы скачивать jq и устанавливаться в контейнере (возможно со временем, что-то еще потребовалось бы ...)
```yaml ```yaml
- name: Setup Go - name: Setup Go container
run: | run: |
# Install jq for JSON parsing # Install jq for JSON parsing
apt-get update && apt-get install -y jq apt-get update && apt-get install -y jq
@@ -397,28 +436,133 @@ jobs:
jq --version jq --version
``` ```
решение как говорится в лоб: чтобы убрать эту работу при каждом выполнении workflow надо сделать свой образ **решение в лоб:** применено, чтобы убрать эту повторяющуюся работу при каждом выполнении workflow - сделан свой образ - "${DOCKERHUB_USERNAME}"/my-build-golang-runner:latest
``` Dockerfile ``` Dockerfile
# базовый образ
FROM golang:1.24 FROM golang:1.24
# Install some packages # Устанавливаем пакеты (одинаково работают на amd64/arm64)
RUN apt-get update && apt-get install -y git ca-certificates jq RUN apt-get update && \
apt-get install -y --no-install-recommends \
git \
ca-certificates \
jq && \
rm -rf /var/lib/apt/lists/*
# (Опционально) Можно добавить команду по умолчанию
CMD ["bash"]
``` ```
собрать его и запушить (желательно с мультиплатформенностью). конечно если вам не надо билдить образы для разных платформ тогда все попроще Сначала собрал его и запушил (желательно с мультиплатформенностью) на каком-то локальном АРМ (не раннере)
```bash ```bash
#!/bin/bash #!/bin/bash
docker buildx build \ docker buildx build \
--platform linux/amd64,linux/arm64 \ --platform linux/amd64,linux/arm64 \
--tag ${DOCKERHUB_USERNAME}/my-build-golang-runner:latest \ --tag ${DOCKERHUB_USERNAME:-defaultdockeruser}/my-build-golang-runner:latest \
--push \ --push \
-f Dockerfile_for_runner_image \ -f Dockerfile_for_runner_image \
. .
``` ```
решение рабочее но надо всегда иметь под рукой АРм с buildx или лучше автоматизировать все и сделать задачу для сборки на раннере `.gitea/workflows/build-builder.yaml`
```yaml
name: Build Builder Docker Image
on:
push:
tags:
- builder-*
jobs:
create-builder-docker-image:
runs-on: ubuntu-latest
container:
image: docker:28.3.2-dind
steps:
- name: Checkout repository
run: |
# Install git
apk add --no-cache git
echo "=== GitHub Variables ==="
echo "github.ref = ${{ github.ref }}"
echo "github.ref_name = ${{ github.ref_name }}"
echo "github.sha = ${{ github.sha }}"
echo "github.repository = ${{ github.repository }}"
echo "========================"
echo "Cloning..."
git clone https://oauth2:${{ secrets.GITEATOKEN }}@direct-dev.ru/gitea/GiteaAdmin/hello_gitea.git hello_gitea
cd hello_gitea
echo "Checkout to ${{ github.ref }} ..."
git checkout ${{ github.ref }}
- name: Setup Docker Buildx
run: |
# Docker is already installed in docker:dind image
echo "look at docker version"
docker --version
# Setup Docker Buildx for multi-platform builds
echo "setup buildx"
docker buildx create --name builder-builx --use
docker buildx inspect --bootstrap
- name: Login to Docker Hub
run: |
echo "login to docker hub ..."
echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
- name: Build multi-platform Docker images
run: |
cd hello_gitea
echo "Build multi-platform images using buildx ..."
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:${{ github.ref_name }} \
--tag ${{ secrets.DOCKERHUB_USERNAME }}/my-build-golang-runner:latest \
--push \
-f Dockerfile.builder \
.
- name: Remove buildx
run: |
docker buildx rm builder-builx
```
эта задача будет запущена на ранере при пуше тега с префиксом `builder-`
2 **create-docker-image:** - создание образов docker с нашим проектом
- Запускается только после успешного завершения `create-release`
- Используем Docker-in-Docker контейнер (image: docker:28.3.2-dind)
- Настраиваем Docker Buildx для мультиплатформенной сборки (docker buildx create --use docker buildx inspect --bootstrap)
- Авторизуемся в Docker Hub (echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin)
- Собираем образы для 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 +585,14 @@ docker buildx build \
### Создание токенов ### Создание токенов
**Gitea Token:** **Gitea Token:**
1. Перейдите в настройки профиля → "Applications" 1. Перейдите в настройки профиля → "Applications"
2. Создайте новый токен с правами на репозиторий 2. Создайте новый токен с правами на репозиторий
3. Скопируйте токен 3. Скопируйте токен
4. В разделе Actions репозитория создайте секрет уровня репозитория - я создал с именем GITEATOKEN (такой не даст сделать: GITEA_TOKEN) 4. В разделе Actions репозитория создайте секрет уровня репозитория - я создал с именем GITEATOKEN (такой не даст сделать: GITEA_TOKEN)
**Docker Hub Token:** **Docker Hub Token:**
1. Войдите в Docker Hub 1. Войдите в Docker Hub
2. Перейдите в Account Settings → Security 2. Перейдите в Account Settings → Security
3. Создайте новый Access Token 3. Создайте новый Access Token
@@ -457,9 +603,9 @@ docker buildx build \
### Локальное тестирование ### Локальное тестирование
1. **Проверим синтаксис workflow:** 1 **Проверим синтаксис workflow:**
ну если мы в ide то наверное все автоматом отформатировано ну если мы в ide, то наверное все хорошо и уже автоматом отформатировано ...
но тем не менее ... но тем не менее ...
```bash ```bash
@@ -467,7 +613,10 @@ docker buildx build \
yamllint .gitea/workflows/build.yaml yamllint .gitea/workflows/build.yaml
``` ```
2. **Протестируем сборку локально:** 2 **Протестируем сборку локально:**
пока ручное тестирование
```bash ```bash
# Сборка для текущей платформы # Сборка для текущей платформы
go build -o hello-api main.go go build -o hello-api main.go
@@ -477,7 +626,8 @@ docker buildx build \
GOOS=linux GOARCH=arm64 go build -o hello-api-linux-arm64 main.go GOOS=linux GOARCH=arm64 go build -o hello-api-linux-arm64 main.go
``` ```
3. **Тестирование Docker образа:** 3 **Тестирование Docker образа:**
```bash ```bash
# Сборка образа # Сборка образа
docker build -t hello-api:test . docker build -t hello-api:test .
@@ -486,19 +636,23 @@ docker buildx build \
docker run -p 8080:8080 hello-api:test docker run -p 8080:8080 hello-api:test
# Тестирование API # Тестирование API
curl http://localhost:8080/health curl http://localhost:8080/healthz
``` ```
тут надо погонять curl по эндпойнтам, убедиться что приложение работает (пока тоже вручную)
### Запуск Actions ### Запуск Actions
1. **Создаем тег:** 1 **Создаем тег вручную или скриптом (`scripts/release-interactive.sh`):**
```bash ```bash
git tag v1.1.20 git tag v1.1.20
git push origin v1.1.20 git push origin v1.1.20
# или скрипт # текст скрипта - запуск можно сделать через make
#release-interactive:
# @./scripts/release-interactive.sh
#!/bin/bash #!/bin/bash
@@ -519,7 +673,7 @@ docker buildx build \
echo "" echo ""
# Запрашиваем новую версию # Запрашиваем новую версию
read -p "Введите новую версию (формат X.Y.Z): " VERSION read -r -p "Введите новую версию (формат X.Y.Z): " VERSION
# Проверяем, что версия не пустая # Проверяем, что версия не пустая
if [ -z "$VERSION" ]; then if [ -z "$VERSION" ]; then
@@ -539,7 +693,7 @@ docker buildx build \
echo " Текущая версия: $CURRENT_VERSION" echo " Текущая версия: $CURRENT_VERSION"
echo " Новая версия: $VERSION" echo " Новая версия: $VERSION"
echo "" echo ""
read -p "Продолжить? (y/N): " CONFIRM read -r -p "Продолжить? (y/N): " CONFIRM
if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
echo "❌ Релиз отменен" echo "❌ Релиз отменен"
@@ -594,6 +748,24 @@ docker buildx build \
echo "✅ Версия обновлена в main.go" 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 команды # Выполняем git команды
echo "📦 Добавляем изменения в git..." echo "📦 Добавляем изменения в git..."
git add . git add .
@@ -611,13 +783,15 @@ docker buildx build \
echo "🎉 Релиз v$VERSION успешно завершен!" echo "🎉 Релиз v$VERSION успешно завершен!"
echo "📋 Выполненные действия:" echo "📋 Выполненные действия:"
echo " - Обновлена версия в main.go" echo " - Обновлена версия в main.go"
echo " - Обновлена версия в makefile"
echo " - Создан коммит с сообщением 'Release v$VERSION'" echo " - Создан коммит с сообщением 'Release v$VERSION'"
echo " - Создан тег v$VERSION" echo " - Создан тег v$VERSION"
echo " - Изменения отправлены в удаленный репозиторий" echo " - Изменения отправлены в удаленный репозиторий"
``` ```
2. **Мониторинг выполнения:** 2 **Мониторинг выполнения:**
- Переходим в репозиторий → "Actions" - Переходим в репозиторий → "Actions"
- Находим запущенный workflow - Находим запущенный workflow
- Отслеживаем выполнение каждого job - Отслеживаем выполнение каждого job
@@ -626,46 +800,54 @@ docker buildx build \
После успешного выполнения: После успешного выполнения:
1. **Docker образы** будут опубликованы в Docker Hub: 1 **Релиз** будет создан в Gitea с бинарниками:
- `username/hello-api:v1.1.20`
- `username/hello-api:latest`
2. **Релиз** будет создан в Gitea с бинарниками:
- `hello-api-linux-amd64.tar.gz` - `hello-api-linux-amd64.tar.gz`
- `hello-api-linux-arm64.tar.gz` - `hello-api-linux-arm64.tar.gz`
- `hello-api-windows-amd64.tar.gz` - `hello-api-windows-amd64.tar.gz`
- `hello-api-darwin-amd64.tar.gz` - `hello-api-darwin-amd64.tar.gz`
- `hello-api-darwin-arm64.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:** 1 **В Gitea:**
- Переходим в репозиторий → "Actions" - Переходим в репозиторий → "Actions"
- Выберем workflow - Выберем workflow
- Нажмем на job для просмотра логов - Нажмем на job для просмотра логов
2. **Отладка ошибок:** 2 **Отладка ошибок:**
- Проверим правильность секретов - Проверим правильность секретов
- Убедимся в корректности путей к репозиторию - Убедимся в корректности путей к репозиторию
- Проверим права доступа токенов - Проверим права доступа токенов
### Частые проблемы ### Частые проблемы
1. **Ошибка авторизации в Docker Hub:** 1 **Ошибка авторизации в Docker Hub:**
- Проверим правильность `DOCKERHUB_TOKEN` - Проверим правильность `DOCKERHUB_TOKEN`
- Убедимся, что токен не истек - Убедимся, что токен не истек
2. **Ошибка создания релиза:** 2 **Ошибка создания релиза:**
- Проверим права токена `GITEATOKEN` - Проверим права токена `GITEATOKEN`
- Убедимся, что тег не существует - Убедимся, что тег не существует
3. **Ошибка сборки:** 3 **Ошибка сборки:**
- Проверим зависимости в `go.mod` - Проверим зависимости в `go.mod`
- Убедимся в корректности Dockerfile - Убедимся в корректности Dockerfile
## Заключение ## Заключение
В этой статье мы рассмотрели полный процесс настройки Gitea Actions для Go проекта. Мы создали автоматизированный pipeline, который: В этой статье мы рассмотрели полный процесс настройки Gitea Actions для Go проекта. Мы создали автоматизированный pipeline, который:
@@ -699,12 +881,13 @@ Gitea Actions предоставляет мощные возможности д
### Архитектура системы ### Архитектура системы
Этот и последующие разделы описывают инфраструктуру на которой я проверял все описанное выше. Этот и последующие разделы описывают инфраструктуру, на которой я проверял все описанное выше.
Если у вас используются другие подходы, то можете пропустить их или ознакомиться для общего развития. Если у вас используются другие подходы, то можете пропустить чтение этих разделов
или ознакомиться для общего развития.
Итак инфраструктура состоит из следующих компонентов: Итак инфраструктура состоит из следующих компонентов:
``` ``` text
Proxmox VE (ARM64) Proxmox VE (ARM64)
├── K3s Cluster ├── K3s Cluster
├── Master Node ├── Master Node
@@ -720,31 +903,34 @@ Proxmox VE (ARM64)
### Требования к системе ### Требования к системе
**Proxmox VE:** **Proxmox VE:**
- ARM64 архитектура
- Минимум 8GB RAM - ARM64 архитектура (orangepi 5 Plus)
- 100GB свободного места - Минимум 8GB RAM (16Gb)
- Поддержка LXC контейнеров - 100GB свободного места (1 Gb)
- Поддержка LXC контейнеров (+)
**K3s Cluster:** **K3s Cluster:**
- Kubernetes 1.24+ - Kubernetes 1.24+
- Helm 3.8+ - Helm 3.8+
- Ingress Controller (Traefik) - Ingress Controller (Traefik)
- Persistent Storage (Longhorn) - Persistent Storage (NFS)
**LXC Container:** **LXC Container:**
- Ubuntu 22.04 LTS - Ubuntu 22.04 LTS
- 4GB RAM - 4GB RAM
- 20GB дискового пространства - 20GB дискового пространства
- Docker Engine - Docker Engine
- Go 1.21+
## Установка Gitea в кластере K3s ## Установка Gitea в кластере K3s
### Анализ существующего кластера ### Анализ существующего кластера
Ваш кластер уже настроен и работает. Вот текущая конфигурация: Текущая конфигурация:
**Узлы кластера:** **Узлы кластера:**
```bash ```bash
kubectl get nodes -o wide kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
@@ -754,6 +940,7 @@ k3s-control-03 Ready control-plane,etcd,master 544d v1.33.2+k3s1 10.x
``` ```
**Существующие компоненты:** **Существующие компоненты:**
- Kubernetes v1.33.2+k3s1 - Kubernetes v1.33.2+k3s1
- 3 узла control-plane с etcd - 3 узла control-plane с etcd
- Traefik Ingress Controller - Traefik Ingress Controller
@@ -804,7 +991,7 @@ valkey-data-gitea-valkey-cluster-2 Bound pvc-368f0ab9-7851-423f-afb9-443287
Доступ к gitea лучше сделать через ingress или на худой конец через port-forward: Доступ к gitea лучше сделать через ingress или на худой конец через port-forward:
1. **Временный доступ через port-forward:** 1 **Временный доступ через port-forward:**
```bash ```bash
# Доступ к Gitea через port-forward # Доступ к Gitea через port-forward
@@ -814,7 +1001,7 @@ kubectl port-forward -n gitea svc/gitea-http 3000:3000
curl http://localhost:3000 curl http://localhost:3000
``` ```
2. **Создание IngressRoute для постоянного доступа:** 2 **Создание IngressRoute для постоянного доступа:**
```yaml ```yaml
# gitea-ingressroute.yaml # gitea-ingressroute.yaml
@@ -850,12 +1037,12 @@ spec:
KUBECONFIG=~/.kube/config_hlab kubectl apply -f gitea-ingress.yaml KUBECONFIG=~/.kube/config_hlab kubectl apply -f gitea-ingress.yaml
``` ```
Таким образом мой инстанс gitea доступен с внешнего адреса https://direct-dev.ru/gitea Таким образом мой инстанс gitea доступен с внешнего адреса <https://direct-dev.ru/gitea>
в /data/gitea/conf/app.ini в /data/gitea/conf/app.ini
[server] [server]
ROOT_URL = https://direct-dev.ru/gitea ROOT_URL = <https://direct-dev.ru/gitea>
DOMAIN = direct-dev.ru DOMAIN = direct-dev.ru
### Конфигурация Gitea ### Конфигурация Gitea
@@ -864,6 +1051,7 @@ Gitea установлен через Helm.
**Версия:** Gitea 1.24.3 (rootless) **Версия:** Gitea 1.24.3 (rootless)
**Архитектура:** **Архитектура:**
- PostgreSQL для базы данных (развернут отдельно ) - PostgreSQL для базы данных (развернут отдельно )
- Valkey cluster (Redis) для кэширования - Valkey cluster (Redis) для кэширования
- NFS Storage Class для persistent storage - NFS Storage Class для persistent storage
@@ -892,7 +1080,6 @@ helm repo update
helm upgrade gitea gitea-charts/gitea -n gitea -f gitea-values.yaml helm upgrade gitea gitea-charts/gitea -n gitea -f gitea-values.yaml
``` ```
**Проверка конфигурации:** **Проверка конфигурации:**
```bash ```bash
@@ -949,27 +1136,31 @@ redis-cluster:
enabled: false enabled: false
``` ```
Как видите я организовал доступ через внешний IP к URL `https://direct-dev.ru/gitea`, то есть через префикс роута, опыт работы с actions показал, что лучше бы организовать было через поддомен третьего уровня: что то типа `https://gitea.direct-dev.ru` - в этом случае всякие разные предопределенные jobs типа checkout@v3 должны клонирование отрабатывать нормально.
``` bash ``` bash
# Проверка секретов # Проверка секретов
kubectl get secrets -n gitea kubectl get secrets -n gitea
``` ```
### Настройка Actions в существующем Gitea ### Настройка Actions в существующем инстансе Gitea
1. **Проверка включения Actions:** 1 **Проверка включения Actions:**
```bash ```bash
# Проверка конфигурации Actions # Проверка конфигурации Actions
kubectl exec -n gitea deployment/gitea -c gitea -- cat /data/gitea/conf/app.ini" kubectl exec -n gitea deployment/gitea -c gitea -- cat /data/gitea/conf/app.ini"
``` ```
2. **Включение Actions через веб-интерфейс:** 2 **Включение Actions через веб-интерфейс:**
- Откройте Gitea через port-forward или ingress - Откройте Gitea через port-forward или ingress
- Перейдите в Site Administration → Actions - Перейдите в Site Administration → Actions
- Включите "Enable Actions" - Включите "Enable Actions"
- Настройте "Default Actions URL" (например, https://gitea.com) - Настройте "Default Actions URL" (например, <https://gitea.com>)
3. **Проверка работы Actions:** 3 **Проверка работы Actions:**
```bash ```bash
# Проверка логов Gitea на предмет ошибок Actions # Проверка логов Gitea на предмет ошибок Actions
@@ -978,7 +1169,8 @@ kubectl logs -n gitea deployment/gitea | grep -i action
### Настройка DNS и SSL ### Настройка DNS и SSL
Cert-Manager установлен. Инструкций вагон и маленькая тележка - не смысла повторяться. Проверим конфигурацию: Инструкция по установке Cert-Manager не приводится - инструкций вагон и маленькая тележка -
нет смысла повторяться:
```bash ```bash
# Проверка Cert-Manager # Проверка Cert-Manager
@@ -990,12 +1182,13 @@ kubectl get clusterissuer
1. **Настройка DNS записи:** 1. **Настройка DNS записи:**
```bash ```text
# Добавить A-запись в DNS (у меня сloudflare) Добавить A-запись в DNS (у меня сloudflare)
gitea.your-domain.com -> внешний (белый) Ip - за ним пробросы портов если нужно ... чтобы в итоге запрос поступил на traefik gitea.your-domain.com -> внешний (белый) Ip - за ним пробросы портов если нужно ...
чтобы в итоге запрос поступил на traefik
``` ```
2. **Создание ClusterIssuer (если не существует):** 2 **Создание ClusterIssuer (если не существует):**
```bash ```bash
# Создание ClusterIssuer для Let's Encrypt - лучше через dns resolver # Создание ClusterIssuer для Let's Encrypt - лучше через dns resolver
@@ -1027,7 +1220,7 @@ EOF
### Доступ к Gitea ### Доступ к Gitea
1. **Временный доступ через port-forward:** 1 **Временный доступ через port-forward:**
```bash ```bash
# Доступ к Gitea через port-forward # Доступ к Gitea через port-forward
@@ -1036,14 +1229,14 @@ kubectl port-forward -n gitea svc/gitea-http 3000:3000
# В браузере http://localhost:3000/gitea # В браузере http://localhost:3000/gitea
``` ```
2. **Постоянный доступ через ingressroute:** 2 **Постоянный доступ через ingressroute:**
``` bash ``` bash
# Проверка сертификата # Проверка сертификата
kubectl get certificate -n gitea kubectl get certificate -n gitea
``` ```
3. **Проверка доступа:** 3 **Проверка доступа:**
```bash ```bash
# Проверка через curl # Проверка через curl
@@ -1094,7 +1287,7 @@ spec:
# - Network: DHCP # - Network: DHCP
``` ```
2. **Настройка сети:** 2 **Настройка сети:**
```bash ```bash
# В контейнере # В контейнере
@@ -1114,7 +1307,7 @@ apt update && apt upgrade -y
apt install -y curl wget git vim htop apt install -y curl wget git vim htop
``` ```
2. **Установка Docker:** 2 **Установка Docker:**
```bash ```bash
# Удаление старых версий # Удаление старых версий
@@ -1151,7 +1344,7 @@ systemctl start docker
docker --version docker --version
``` ```
3. **Установка Go:** 3 **Установка Go:**
```bash ```bash
# Скачивание Go для ARM64 # Скачивание Go для ARM64
@@ -1174,7 +1367,7 @@ go version
mkdir -p $HOME/go/{bin,src,pkg} mkdir -p $HOME/go/{bin,src,pkg}
``` ```
4. **Установка дополнительных инструментов:** 4 **Установка дополнительных инструментов:**
```bash ```bash
# Установка build tools # Установка build tools
@@ -1216,7 +1409,7 @@ chmod +x /usr/local/bin/act_runner
act_runner --version act_runner --version
``` ```
2. **Создание пользователя для runner:** 2 **Создание пользователя для runner:**
```bash ```bash
# Создание пользователя # Создание пользователя
@@ -1228,7 +1421,7 @@ mkdir -p /opt/gitea-runner
chown gitea-runner:gitea-runner /opt/gitea-runner chown gitea-runner:gitea-runner /opt/gitea-runner
``` ```
3. **Настройка конфигурации runner:** 3 **Настройка конфигурации runner:**
```bash ```bash
# Переключение на пользователя runner # Переключение на пользователя runner
@@ -1353,7 +1546,7 @@ EOF
- Нажмите "New Runner" - Нажмите "New Runner"
- Скопируйте токен регистрации - Скопируйте токен регистрации
2. **Регистрация runner:** 2 **Регистрация runner:**
```bash ```bash
# В контейнере LXC под пользователем gitea-runner # В контейнере LXC под пользователем gitea-runner
@@ -1366,7 +1559,7 @@ act_runner register \
``` ```
3. **Создание systemd сервиса:** 3 **Создание systemd сервиса:**
```bash ```bash
# Создание файла сервиса # Создание файла сервиса
@@ -1432,7 +1625,7 @@ EOF
chmod +x /opt/gitea-runner/monitor.sh chmod +x /opt/gitea-runner/monitor.sh
``` ```
2. **Настройка cron для мониторинга:** 2 **Настройка cron для мониторинга:**
```bash ```bash
# Добавление в crontab # Добавление в crontab
@@ -1449,7 +1642,7 @@ curl -H "Authorization: token YOUR_GITEA_TOKEN" \
https://gitea.your-domain.com/api/v1/actions/runners https://gitea.your-domain.com/api/v1/actions/runners
``` ```
2. **Создание тестового workflow:** 2 **Создание тестового workflow:**
```yaml ```yaml
# .gitea/workflows/test-runner.yaml # .gitea/workflows/test-runner.yaml
@@ -1517,7 +1710,7 @@ EOF
systemctl restart docker systemctl restart docker
``` ```
2. **Настройка ограничений ресурсов:** 2 **Настройка ограничений ресурсов:**
```bash ```bash
# Обновление systemd сервиса с ограничениями # Обновление systemd сервиса с ограничениями
@@ -1580,7 +1773,6 @@ chmod +x /opt/gitea-runner/backup.sh
echo "0 2 * * * /opt/gitea-runner/backup.sh" | crontab - echo "0 2 * * * /opt/gitea-runner/backup.sh" | crontab -
``` ```
## Работа с кластером ## Работа с кластером
### Основные команды для работы с кластером ### Основные команды для работы с кластером

2
go.mod
View File

@@ -1,6 +1,6 @@
module direct-dev-ru/hello_gitea module direct-dev-ru/hello_gitea
go 1.21 go 1.24
require github.com/gin-gonic/gin v1.10.1 require github.com/gin-gonic/gin v1.10.1

243
main.go
View File

@@ -1,20 +1,127 @@
package main package main
import ( import (
"context"
"log/slog"
"net/http" "net/http"
"os" "os"
"runtime"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
const version = "1.0.27" const version = "1.0.36"
// SystemInfo holds system information
type SystemInfo struct {
GoVersion string `json:"go_version"`
OS string `json:"os"`
Architecture string `json:"architecture"`
NumCPU int `json:"num_cpu"`
StartTime string `json:"start_time"`
}
var (
startTime = time.Now()
logger *slog.Logger
)
// setupLogger configures structured logging with different levels for dev/prod
func setupLogger() {
var logLevel slog.Level
var logFormat string
// Determine log level from environment
switch os.Getenv("LOG_LEVEL") {
case "DEBUG":
logLevel = slog.LevelDebug
case "INFO":
logLevel = slog.LevelInfo
case "WARN":
logLevel = slog.LevelWarn
case "ERROR":
logLevel = slog.LevelError
default:
logLevel = slog.LevelInfo
}
// Determine log format from environment
logFormat = os.Getenv("LOG_FORMAT")
if logFormat == "" {
logFormat = "json" // Default to JSON for production
}
// Configure logger based on format
var handler slog.Handler
opts := &slog.HandlerOptions{
Level: logLevel,
AddSource: true,
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
// Customize timestamp format
if a.Key == slog.TimeKey {
return slog.Attr{
Key: slog.TimeKey,
Value: slog.StringValue(a.Value.Time().Format("2006-01-02T15:04:05.000Z07:00")),
}
}
return a
},
}
if logFormat == "text" {
handler = slog.NewTextHandler(os.Stdout, opts)
} else {
handler = slog.NewJSONHandler(os.Stdout, opts)
}
logger = slog.New(handler)
slog.SetDefault(logger)
}
// logMiddleware creates a structured logging middleware for Gin
func logMiddleware() gin.HandlerFunc {
return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
// Create structured log entry
logger.Info("HTTP Request",
"method", param.Method,
"path", param.Path,
"status", param.StatusCode,
"latency", param.Latency,
"client_ip", param.ClientIP,
"user_agent", param.Request.UserAgent(),
"timestamp", param.TimeStamp.Format("2006-01-02T15:04:05.000Z07:00"),
)
return "" // Return empty string as we handle logging ourselves
})
}
// errorLogger logs errors with structured context
func ErrorLogger(err error, context ...any) {
logger.Error("Application Error",
append([]any{"error", err.Error()}, context...)...,
)
}
func main() { func main() {
// Setup structured logging
setupLogger()
logger.Info("Starting application",
"version", version,
"go_version", runtime.Version(),
"os", runtime.GOOS,
"architecture", runtime.GOARCH,
"num_cpu", runtime.NumCPU(),
)
// Set Gin mode // Set Gin mode
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
// Create router // Create router with custom logger
r := gin.Default() r := gin.New()
r.Use(logMiddleware())
r.Use(gin.Recovery())
// Add middleware for CORS // Add middleware for CORS
r.Use(func(c *gin.Context) { r.Use(func(c *gin.Context) {
@@ -31,7 +138,8 @@ func main() {
}) })
// Health check endpoint // Health check endpoint
r.GET("/health", func(c *gin.Context) { r.GET("/healthz", func(c *gin.Context) {
logger.Debug("Health check requested", "client_ip", c.ClientIP())
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"status": "ok", "status": "ok",
"version": version, "version": version,
@@ -40,6 +148,10 @@ func main() {
// Main endpoint // Main endpoint
r.GET("/", func(c *gin.Context) { r.GET("/", func(c *gin.Context) {
logger.Info("Root endpoint accessed",
"client_ip", c.ClientIP(),
"user_agent", c.Request.UserAgent(),
)
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"message": "Hello, World!", "message": "Hello, World!",
"version": version, "version": version,
@@ -50,6 +162,7 @@ func main() {
api := r.Group("/api/v1") api := r.Group("/api/v1")
{ {
api.GET("/info", func(c *gin.Context) { api.GET("/info", func(c *gin.Context) {
logger.Debug("API info requested", "client_ip", c.ClientIP())
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"service": "hello-api", "service": "hello-api",
"version": version, "version": version,
@@ -63,17 +176,104 @@ func main() {
} }
if err := c.ShouldBindJSON(&request); err != nil { if err := c.ShouldBindJSON(&request); err != nil {
logger.Warn("Invalid JSON in echo request",
"client_ip", c.ClientIP(),
"error", err.Error(),
)
c.JSON(http.StatusBadRequest, gin.H{ c.JSON(http.StatusBadRequest, gin.H{
"error": "Invalid JSON", "error": "Invalid JSON",
}) })
return return
} }
logger.Info("Echo request processed",
"client_ip", c.ClientIP(),
"message_length", len(request.Message),
)
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"echo": request.Message, "echo": request.Message,
"version": version, "version": version,
}) })
}) })
// Configuration endpoint with detailed logging
api.GET("/config", func(c *gin.Context) {
logger.Debug("Configuration requested", "client_ip", c.ClientIP())
systemInfo := SystemInfo{
GoVersion: runtime.Version(),
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
NumCPU: runtime.NumCPU(),
StartTime: startTime.Format(time.RFC3339),
}
// Get environment variables (excluding sensitive ones)
envVars := make(map[string]string)
sensitiveCount := 0
for _, env := range os.Environ() {
// Skip sensitive environment variables
if !isSensitiveEnvVar(env) {
envVars[env] = os.Getenv(env)
} else {
sensitiveCount++
}
}
logger.Info("Configuration accessed",
"client_ip", c.ClientIP(),
"env_vars_count", len(envVars),
"sensitive_vars_filtered", sensitiveCount,
"uptime", time.Since(startTime).String(),
)
c.JSON(http.StatusOK, gin.H{
"version": version,
"system_info": systemInfo,
"environment": envVars,
"uptime": time.Since(startTime).String(),
})
})
// New logging endpoint to test log levels
api.POST("/log-test", func(c *gin.Context) {
var request struct {
Level string `json:"level"`
Message string `json:"message"`
}
if err := c.ShouldBindJSON(&request); err != nil {
logger.Warn("Invalid JSON in log-test request",
"client_ip", c.ClientIP(),
"error", err.Error(),
)
c.JSON(http.StatusBadRequest, gin.H{
"error": "Invalid JSON",
})
return
}
// Log based on requested level
switch request.Level {
case "debug":
logger.Debug(request.Message, "client_ip", c.ClientIP())
case "info":
logger.Info(request.Message, "client_ip", c.ClientIP())
case "warn":
logger.Warn(request.Message, "client_ip", c.ClientIP())
case "error":
logger.Error(request.Message, "client_ip", c.ClientIP())
default:
logger.Info(request.Message, "client_ip", c.ClientIP(), "level", request.Level)
}
c.JSON(http.StatusOK, gin.H{
"status": "logged",
"level": request.Level,
"message": request.Message,
})
})
} }
// Get port from environment or use default // Get port from environment or use default
@@ -82,6 +282,37 @@ func main() {
port = "8080" port = "8080"
} }
// Start server // Start server with structured logging
r.Run(":" + port) logger.Info("Server starting",
"port", port,
"mode", gin.Mode(),
)
ctx := context.Background()
go func() {
// Graceful shutdown handling
<-ctx.Done()
logger.Info("Shutdown signal received, stopping server...")
}()
err := r.Run(":" + port)
if err != nil {
logger.Error("Server failed to start", "error", err.Error())
os.Exit(1)
}
}
// isSensitiveEnvVar checks if an environment variable contains sensitive information
func isSensitiveEnvVar(env string) bool {
sensitivePrefixes := []string{
"PASSWORD", "SECRET", "KEY", "TOKEN", "CREDENTIAL",
"AWS_", "GITHUB_", "DOCKER_", "KUBERNETES_",
}
for _, prefix := range sensitivePrefixes {
if len(env) >= len(prefix) && env[:len(prefix)] == prefix {
return true
}
}
return false
} }

View File

@@ -2,7 +2,7 @@
BIN_DIR=bin BIN_DIR=bin
APP_NAME=hello-api APP_NAME=hello-api
VERSION=1.0.27 VERSION=1.0.36
build: build:
mkdir -p $(BIN_DIR) mkdir -p $(BIN_DIR)

21
scripts/quick-build.sh Normal file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
if [ ! -f go.mod ]; then
echo "go.mod not found in current directory"
exit 1
fi
# Проверяем, изменились ли зависимости
if [ ! -f go.sum ] || ! go mod verify >/dev/null 2>&1; then
echo "Dependencies changed, downloading..."
go mod download
fi
# Собираем для указанной платформы
if [ -n "$1" ] && [ -n "$2" ]; then
echo "Building for $1 $2..."
GOOS=$1 GOARCH=$2 go build -o "bin/hello-api-$1-$2" main.go
else
echo "Building for current platform..."
go build -o bin/hello-api main.go
fi

View File

@@ -17,7 +17,7 @@ get_version_interactive() {
echo "" echo ""
# Запрашиваем новую версию # Запрашиваем новую версию
read -p "Введите новую версию (формат X.Y.Z): " VERSION read -r -p "Введите новую версию (формат X.Y.Z): " VERSION
# Проверяем, что версия не пустая # Проверяем, что версия не пустая
if [ -z "$VERSION" ]; then if [ -z "$VERSION" ]; then
@@ -36,6 +36,9 @@ get_version_interactive() {
echo "📝 Подтверждение:" echo "📝 Подтверждение:"
echo " Текущая версия: $CURRENT_VERSION" echo " Текущая версия: $CURRENT_VERSION"
echo " Новая версия: $VERSION" echo " Новая версия: $VERSION"
if [ "$CURRENT_VERSION" == "$VERSION" ]; then
echo "⚠️ Новая версия совпадает с текущей. Возможно будет обновлен тег ..."
fi
echo "" echo ""
read -r -p "Продолжить? (y/N): " CONFIRM read -r -p "Продолжить? (y/N): " CONFIRM
@@ -68,11 +71,27 @@ if ! git rev-parse --git-dir > /dev/null 2>&1; then
exit 1 exit 1
fi fi
# Проверяем, что нет незакоммиченных изменений # Проверяем, существует ли уже тег с такой версией
# if ! git diff-index --quiet HEAD --; then if git tag -l "v$VERSION" | grep -q "v$VERSION"; then
# echo "Ошибка: Есть незакоммиченные изменения. Сначала закоммитьте их." echo "⚠️ Тег v$VERSION уже существует!"
# exit 1 echo ""
# fi read -r -p "Обновить существующий тег? (y/N): " UPDATE_TAG
if [[ ! $UPDATE_TAG =~ ^[Yy]$ ]]; then
echo "❌ Обновление тега отменено"
exit 0
fi
echo "🔄 Обновляем существующий тег..."
# Удаляем локальный тег
git tag -d "v$VERSION" 2>/dev/null || true
# Удаляем удаленный тег
git push origin ":refs/tags/v$VERSION" 2>/dev/null || true
echo "✅ Старый тег удален"
fi
# Обновляем версию в main.go # Обновляем версию в main.go
echo "📝 Обновляем версию в main.go..." echo "📝 Обновляем версию в main.go..."