# 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"}' ```