vault backup: 2025-08-04 15:28:34

This commit is contained in:
Andrey Epifancev
2025-08-04 15:28:34 +04:00
parent 7e1fbcf087
commit e46521074c
3 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,549 @@
# Webhook Server на Go
## 1. Обзор проекта
### 1.1 Назначение
Webhook сервер на Go для автоматической сборки и деплоя Hugo сайта при изменениях в Git репозитории.
### 1.2 Ключевые функции
- Обработка webhook от Git (GitHub, GitLab, Gitea)
- Автоматическое клонирование/обновление репозитория
- Запуск Hugo сборки
- Валидация и безопасность
- Логирование и мониторинг
- Обработка ошибок и retry логика
## 2. Архитектура
### 2.1 Компонентная диаграмма
```mermaid
graph TB
A[Git Webhook] --> B[Webhook Handler]
B --> C[Validator]
C --> D[Git Client]
D --> E[Repository Manager]
E --> F[Hugo Builder]
F --> G[File System]
G --> H[Nginx Reload]
subgraph "Webhook Server"
B
C
D
E
F
end
subgraph "External"
A
G
H
end
```
### 2.2 Структура проекта
```
webhook-server/
├── cmd/
│ └── server/
│ └── main.go # Точка входа приложения
├── internal/
│ ├── handler/
│ │ ├── webhook.go # Обработчик webhook
│ │ └── health.go # Health check endpoint
│ ├── builder/
│ │ ├── hugo.go # Hugo сборка
│ │ └── git.go # Git операции
│ ├── config/
│ │ └── config.go # Конфигурация
│ ├── validator/
│ │ └── webhook.go # Валидация webhook
│ └── logger/
│ └── logger.go # Структурированное логирование
├── pkg/
│ ├── git/
│ │ └── client.go # Git клиент
│ └── metrics/
│ └── prometheus.go # Метрики Prometheus
├── configs/
│ ├── config.yaml # Конфигурация
│ └── nginx.conf # Nginx конфигурация
├── scripts/
│ ├── build.sh # Скрипт сборки
│ └── deploy.sh # Скрипт деплоя
├── go.mod
├── go.sum
├── Dockerfile
├── docker-compose.yml
└── README.md
```
## 3. Техническая реализация
### 3.1 Основные зависимости
```go
// go.mod
module webhook-server
go 1.21
require (
github.com/gin-gonic/gin v1.9.1
github.com/go-git/go-git/v5 v5.8.1
github.com/prometheus/client_golang v1.17.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/viper v1.17.0
gopkg.in/go-playground/webhooks.v5 v5.17.0
)
```
### 3.2 Конфигурация
```yaml
# configs/config.yaml
server:
port: 8080
host: "0.0.0.0"
git:
repository: "https://github.com/user/second-mind"
branch: "main"
webhook_secret: "your-webhook-secret"
ssh_key_path: "/root/.ssh/id_rsa"
hugo:
source_path: "/app/hugo-site"
output_path: "/var/www/html"
config_file: "config.toml"
base_url: "https://aepif.ru"
nginx:
config_path: "/etc/nginx/nginx.conf"
reload_command: "nginx -s reload"
logging:
level: "info"
format: "json"
metrics:
enabled: true
port: 9090
```
### 3.3 Основные компоненты
#### Webhook Handler
```go
// internal/handler/webhook.go
package handler
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
type WebhookHandler struct {
gitClient *git.Client
hugoBuilder *builder.HugoBuilder
validator *validator.WebhookValidator
logger *logrus.Logger
}
func (h *WebhookHandler) HandleWebhook(c *gin.Context) {
// Валидация webhook
if err := h.validator.Validate(c.Request); err != nil {
h.logger.WithError(err).Error("Webhook validation failed")
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Асинхронная обработка
go h.processWebhook()
c.JSON(http.StatusOK, gin.H{"status": "processing"})
}
func (h *WebhookHandler) processWebhook() {
// Клонирование/обновление репозитория
if err := h.gitClient.Pull(); err != nil {
h.logger.WithError(err).Error("Git pull failed")
return
}
// Hugo сборка
if err := h.hugoBuilder.Build(); err != nil {
h.logger.WithError(err).Error("Hugo build failed")
return
}
// Перезагрузка Nginx
if err := h.reloadNginx(); err != nil {
h.logger.WithError(err).Error("Nginx reload failed")
return
}
h.logger.Info("Deployment completed successfully")
}
```
#### Hugo Builder
```go
// internal/builder/hugo.go
package builder
import (
"os/exec"
"path/filepath"
"github.com/sirupsen/logrus"
)
type HugoBuilder struct {
sourcePath string
outputPath string
configFile string
logger *logrus.Logger
}
func (h *HugoBuilder) Build() error {
h.logger.Info("Starting Hugo build")
cmd := exec.Command("hugo",
"--source", h.sourcePath,
"--destination", h.outputPath,
"--config", filepath.Join(h.sourcePath, h.configFile),
"--minify",
"--cleanDestinationDir",
)
output, err := cmd.CombinedOutput()
if err != nil {
h.logger.WithError(err).WithField("output", string(output)).Error("Hugo build failed")
return err
}
h.logger.WithField("output", string(output)).Info("Hugo build completed")
return nil
}
```
#### Git Client
```go
// pkg/git/client.go
package git
import (
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/sirupsen/logrus"
)
type Client struct {
repositoryPath string
remoteURL string
branch string
logger *logrus.Logger
}
func (c *Client) Pull() error {
c.logger.Info("Starting git pull")
repo, err := git.PlainOpen(c.repositoryPath)
if err != nil {
return err
}
worktree, err := repo.Worktree()
if err != nil {
return err
}
err = worktree.Pull(&git.PullOptions{
RemoteName: "origin",
BranchName: plumbing.NewBranchReferenceName(c.branch),
})
if err != nil && err != git.NoErrAlreadyUpToDate {
c.logger.WithError(err).Error("Git pull failed")
return err
}
c.logger.Info("Git pull completed")
return nil
}
```
### 3.4 Метрики и мониторинг
```go
// pkg/metrics/prometheus.go
package metrics
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
var (
BuildDuration = promauto.NewHistogram(prometheus.HistogramOpts{
Name: "hugo_build_duration_seconds",
Help: "Duration of Hugo build in seconds",
})
BuildSuccess = promauto.NewCounter(prometheus.CounterOpts{
Name: "hugo_build_success_total",
Help: "Total number of successful builds",
})
BuildFailures = promauto.NewCounter(prometheus.CounterOpts{
Name: "hugo_build_failures_total",
Help: "Total number of failed builds",
})
WebhookRequests = promauto.NewCounter(prometheus.CounterOpts{
Name: "webhook_requests_total",
Help: "Total number of webhook requests",
})
)
```
## 4. Docker контейнеризация
### 4.1 Dockerfile
```dockerfile
# Многоэтапная сборка
FROM golang:1.21-alpine AS builder
# Установка зависимостей
RUN apk add --no-cache git ca-certificates tzdata
WORKDIR /app
# Копирование go.mod и go.sum
COPY go.mod go.sum ./
RUN go mod download
# Копирование исходного кода
COPY . .
# Сборка приложения
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/server
# Финальный образ
FROM alpine:latest
# Установка необходимых пакетов
RUN apk --no-cache add ca-certificates tzdata hugo git openssh-client nginx
# Создание пользователя
RUN addgroup -g 1000 -S appgroup && \
adduser -u 1000 -S appuser -G appgroup
WORKDIR /app
# Копирование бинарника
COPY --from=builder /app/main .
# Копирование конфигурации
COPY configs/ /app/configs/
# Создание директорий
RUN mkdir -p /var/www/html /root/.ssh && \
chown -R appuser:appgroup /app /var/www/html
# Переключение на пользователя
USER appuser
EXPOSE 8080 9090
CMD ["./main"]
```
### 4.2 Docker Compose
```yaml
# docker-compose.yml
version: '3.8'
services:
webhook-server:
build: .
ports:
- "8080:8080"
- "9090:9090"
volumes:
- ./configs:/app/configs
- /var/www/html:/var/www/html
- ~/.ssh:/root/.ssh:ro
environment:
- CONFIG_PATH=/app/configs/config.yaml
restart: unless-stopped
networks:
- webhook-network
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- /var/www/html:/usr/share/nginx/html
- ./configs/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- webhook-server
restart: unless-stopped
networks:
- webhook-network
networks:
webhook-network:
driver: bridge
```
## 5. Безопасность
### 5.1 Webhook валидация
- Проверка подписи webhook
- Валидация payload
- Rate limiting
- IP whitelist
### 5.2 Git безопасность
- SSH ключи для аутентификации
- Проверка подписи коммитов
- Ограничение доступа к репозиторию
### 5.3 Системная безопасность
- Запуск от непривилегированного пользователя
- Минимальные права доступа
- Регулярные обновления зависимостей
## 6. Мониторинг и логирование
### 6.1 Структурированное логирование
```go
// internal/logger/logger.go
func SetupLogger(level, format string) *logrus.Logger {
logger := logrus.New()
// Уровень логирования
if level, err := logrus.ParseLevel(level); err == nil {
logger.SetLevel(level)
}
// Формат логирования
if format == "json" {
logger.SetFormatter(&logrus.JSONFormatter{})
}
return logger
}
```
### 6.2 Health Check
```go
// internal/handler/health.go
func (h *HealthHandler) HealthCheck(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "healthy",
"timestamp": time.Now().Unix(),
"version": "1.0.0",
})
}
```
## 7. Развертывание
### 7.1 Скрипт сборки
```bash
#!/bin/bash
# scripts/build.sh
set -e
echo "Building webhook server..."
# Сборка Docker образа
docker build -t webhook-server:latest .
echo "Build completed successfully"
```
### 7.2 Скрипт деплоя
```bash
#!/bin/bash
# scripts/deploy.sh
set -e
echo "Deploying webhook server..."
# Остановка существующих контейнеров
docker-compose down
# Запуск новых контейнеров
docker-compose up -d
echo "Deployment completed successfully"
```
## 8. Тестирование
### 8.1 Unit тесты
```go
// internal/handler/webhook_test.go
func TestWebhookHandler_HandleWebhook(t *testing.T) {
// Тесты валидации webhook
// Тесты обработки ошибок
// Тесты успешной обработки
}
```
### 8.2 Integration тесты
```go
// tests/integration_test.go
func TestFullDeploymentFlow(t *testing.T) {
// Тест полного цикла деплоя
// Тест обработки ошибок
// Тест метрик
}
```
## 9. Документация API
### 9.1 Endpoints
**POST /webhook**
- Обработка webhook от Git
- Валидация подписи
- Асинхронная обработка
**GET /health**
- Health check endpoint
- Статус сервиса
- Версия приложения
**GET /metrics**
- Prometheus метрики
- Метрики сборки
- Метрики webhook
### 9.2 Примеры запросов
```bash
# Health check
curl http://localhost:8080/health
# Метрики
curl http://localhost:9090/metrics
# Webhook (пример)
curl -X POST http://localhost:8080/webhook \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: push" \
-d '{"ref":"refs/heads/main"}'
```