Skip to content

Сборка и требования

Требования:

  • Go 1.26+
  • PostgreSQL, Redis
  • Make

Локальная сборка

bash
# Установка зависимостей
go mod download

# Линт/тест/сборка
go vet ./...
go test ./... -race
go build ./...

Линтеры

Используется golangci-lint v2.10.1 с дополнительными линтерами:

bash
# Установка
make install-lint

# Полный прогон
make lint

# Быстрый (только app + domain)
make lint-fast

# Архитектурная проверка (domain не импортирует infra/app)
make lint-arch

Включены линтеры: gosec (безопасность), bodyclose (закрытие тел HTTP-ответов), noctx (передача context в HTTP-запросы). Конфигурация — .golangci.yml.

Сканирование уязвимостей

bash
make vulncheck

Запускает govulncheck ./... — проверяет зависимости на известные CVE.

CI (.gitlab-ci.yml)

Этапы пайплайна:

ЭтапJobКогда
checklint (golangci-lint), lint-docs (redocly-cli через npm run lint-docs), test (go test + coverage), integration (Postgres+Redis)Каждый push
securitygovulncheckКаждый push
buildbuild (go build)Push без тега
buildbuild-image (Kaniko → Container Registry)Push в ветку v2/develop; в остальные ветки — вручную
buildbuild-release (bundle + upload в Package Registry), build-image-release (Kaniko → Container Registry), build-docs (сборка VitePress-документации)Push с тегом

Из одного пайплайна выходят два артефакта, и оба адресуются одной и той же версией:

АртефактКудаКто потребляет
Deployment bundle (.tar.gz)Generic PackagesVM + systemd через marv-ctl.sh (пин .marv-version)
OCI-образContainer RegistryKubernetes через Helm/Flux (пин image.tag)

Оба собираются только после зелёных check и security — образ публикуется в реестр не раньше, чем пройдут линтеры и тесты.

Шаблон Kaniko (.build-image-template) подключается через include из infra/deploy — тот же, что использует zircon.

Deployment Bundle

Бандл — самодостаточный архив для деплоя на сервер (Go на сервере не нужен):

bash
# Для текущей ОС
make bundle

# Для Linux (серверы)
make bundle-linux

# С явной версией
VERSION=1.2.3 make bundle

# Произвольная платформа
make bundle GOOS=linux GOARCH=arm64

Содержимое бандла:

marv-VERSION-OS-ARCH/
├── bin/
│   ├── marv                # основной сервер
│   ├── hgoose              # утилита миграций БД (goose v3)
│   └── config-migrator     # конвертер legacy-конфигов
├── scripts/
│   ├── deploy.sh           # управление (run, migrate, version, ...)
│   └── marv.service.template # шаблон systemd unit
├── migrations/
│   └── *.sql               # SQL-миграции
└── config/
    ├── config.example.yml  # пример конфигурации
    ├── bots.example.json   # пример конфигурации ботов
    ├── products.example.json # пример конфигурации продуктов
    └── .env.example        # пример переменных окружения

Параметры сборки:

  • CGO_ENABLED=0 — статическая линковка
  • -tags=go_json — ускоренный JSON через go_json
  • -ldflags="-s -w -X ...AppVersion=VERSION" — инъекция версии, strip debug info

OCI-образ

Второй артефакт того же пайплайна — контейнерный образ в GitLab Container Registry (registry.gitlab.hgpoint.com/servers/marv). Собирается Kaniko по корневому Dockerfile.

Схема тегов:

ПайплайнТегиVERSION в бинарнике
Push в ветку<branch>-<short-sha> (например v2-3f9c1a2b) и подвижный <branch><branch>-<short-sha>
Тег vX.Y.ZvX.Y.Z, плюс latest для SemVervX.Y.Z

<branch>-<short-sha> неизменяем и при этом читается человеком: видно ветку и коммит без похода в реестр. Подвижные <branch> и latest — только для локального docker pull; в Kubernetes всегда пинится неизменяемый тег или digest.

vX.Y.Z — та же строка, что и версия Generic Package и что game-репозиторий держит в .marv-version, поэтому один тег адресует и бандл, и образ.

Версия видна тремя способами:

bash
docker run --rm registry.gitlab.hgpoint.com/servers/marv:v2.3.6 -version
docker image inspect …:v2.3.6 --format '{{index .Config.Labels "org.opencontainers.image.version"}}'
docker image inspect …:v2.3.6 --format '{{index .Config.Labels "org.opencontainers.image.revision"}}'  # git sha

Что внутри образа:

  • marv, hgoose, config-migrator в /usr/local/bin
  • SQL-миграции в /app/migrations (для migrate-джобы: hgoose -dir /app/migrations)
  • только примеры конфигов в /app/configconfig.debug.yml и config.release.yml содержат живые креды и в образ не попадают. Рабочий конфиг приходит извне: ConfigMap в k8s, bind-mount локально
  • USER 65532:65532 — образ non-root, иначе Kubernetes с runAsNonRoot: true не запустит под

Приватный модуль servers/shared тянется по --build-arg CI_JOB_TOKEN. Токен живёт только в builder-стадии и в опубликованные слои не попадает.

Деплой на сервер

Деплой выполняется через Game Repository — см. Game Repository workflow.

Там описаны: создание Deploy Token, настройка сервера, marv-ctl.sh, обновление версии и конфигов.

deploy.sh

Скрипт-помощник для управления бандлом на сервере. Входит в состав бандла.

КомандаОписание
migrateПрименить все миграции
migrate-statusСтатус миграций
migrate-downОткатить одну миграцию
config-migrate <file>Мигрировать legacy-конфиг в новый формат на месте (флаг -w перезаписывает исходный файл)
runЗапустить сервер (GIN_MODE=release)
versionВерсия бинарников
bash
./scripts/deploy.sh migrate     # миграции
./scripts/deploy.sh run         # запуск
./scripts/deploy.sh version     # версия

Docker

Dockerfile (multi-stage build):

bash
# Сборка образа (CI_JOB_TOKEN — PAT с доступом к servers/shared)
docker build -t marv:latest --build-arg VERSION=1.2.3 --build-arg CI_JOB_TOKEN=<pat> .

# Запуск — конфиг обязательно монтируется, в образе лежат только примеры
docker run -p 8080:8080 -v ./config:/app/config marv:latest

Docker Compose (локальная разработка):

bash
docker-compose up -d

Поднимает marv + PostgreSQL 17 + Redis 7 с health-checks и пробросом портов; ./config монтируется в /app/config.

Запуск

bash
# Из исходников
go run ./cmd/marv

# Из бинарника
./marv

Перед деплоем:

  1. Применить миграции (hgoose up или ./scripts/deploy.sh migrate)
  2. Заполнить конфиг или переменные окружения
  3. Dev: PostgreSQL и Redis локальные. Release: PostgreSQL — отдельный сервер, Redis — обычно локальный