From 2aa66447dd60220cada382299b67ea5c2dc8badc Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Mon, 4 Aug 2025 15:23:03 +0400 Subject: [PATCH] vault backup: 2025-08-04 15:23:03 --- Идеи/Переезд на Hugo/Webhook Server на Go.md | 549 +++++++++++++++++++ 1 file changed, 549 insertions(+) create mode 100644 Идеи/Переезд на Hugo/Webhook Server на Go.md diff --git a/Идеи/Переезд на Hugo/Webhook Server на Go.md b/Идеи/Переезд на Hugo/Webhook Server на Go.md new file mode 100644 index 0000000..4065b5b --- /dev/null +++ b/Идеи/Переезд на Hugo/Webhook Server на Go.md @@ -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"}' +``` \ No newline at end of file