Вот несколько реальных и достаточно популярных подходов в 2025–2026 годах, как организовать доставку **бинарников**, **конфигов** и **systemd**-юнитов на сервер с использованием **Git + Terraform** (без полного перехода на контейнеры). | № | Подход | Сложность | Идемпотентность | Скорость деплоя | Рекомендую в 2026 | |----|--------------------------------------|-----------|------------------|------------------|--------------------| | 1 | Terraform provisioner + git clone | ★☆☆ | Плохая | Средняя | Нет (только PoC) | | 2 | Terraform + cloud-init/user-data | ★★☆ | Средняя | Медленно | Иногда (новые VM) | | 3 | Git → Artifact (zip/tar) → S3/HTTPS → systemd-tmpfiles + remote-exec | ★★★ | Хорошая | Быстро | Да, классика | | 4 | GitOps через Flux/ArgoCD | ★★★★ | Отличная | Очень быстро | Если уже есть k8s | | 5 | Git → CI → rsync/scp + webhook/reloader | ★★☆ | Средняя–хорошая | Очень быстро | Самый простой живой вариант сейчас | | 6 | Git → CI → deb/rpm → apt/yum + systemd | ★★★★ | Отличная | Средняя | Лучший долгосрочный вариант | ### Самые живые и практичные варианты на сегодня (январь 2026) #### Вариант А — Самый простой и быстрый (очень популярен в 2025–2026) ```bash # Структура репозитория my-service/ ├── bin/ │ └── myapp # ← бинарник ├── config/ │ └── config.yaml ├── systemd/ │ └── myapp.service ├── deploy.sh # опционально └── .github/workflows/deploy.yml ``` `.github/workflows/deploy.yml` пример: ```yaml name: Deploy to server on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Pack artifact run: tar czf artifact.tar.gz bin/ config/ systemd/ - name: Copy to server uses: appleboy/scp-action@v0.1.7 with: host: ${{ secrets.SERVER_IP }} username: deploy key: ${{ secrets.SSH_PRIVATE_KEY }} source: "artifact.tar.gz" target: "/opt/my-service.new" - name: Deploy & restart uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.SERVER_IP }} username: deploy key: ${{ secrets.SSH_PRIVATE_KEY }} script: | set -e cd /opt/my-service.new sudo rm -rf /opt/my-service.old sudo mv /opt/my-service /opt/my-service.old || true sudo mv /opt/my-service.new /opt/my-service sudo cp systemd/myapp.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now myapp.service ``` **Плюсы**: быстро, дёшево, понятно **Минусы**: не совсем идемпотентно, нет отката версий «из коробки» #### Вариант Б — Terraform как оркестратор (очень чистый и воспроизводимый) ```hcl variable "app_version" { default = "v1.2.3" } data "http" "release" { url = "https://github.com/your-org/my-service/releases/download/${var.app_version}/artifact.tar.gz" } resource "null_resource" "deploy" { triggers = { version = var.app_version } connection { type = "ssh" user = "deploy" private_key = file("~/.ssh/id_ed25519_deploy") host = "your-server.example.com" } provisioner "file" { content = data.http.release.response_body destination = "/tmp/artifact-${var.app_version}.tar.gz" } provisioner "remote-exec" { inline = [ "set -e", "mkdir -p /opt/my-service", "tar xzf /tmp/artifact-${var.app_version}.tar.gz -C /opt/my-service", "sudo cp /opt/my-service/systemd/myapp.service /etc/systemd/system/", "sudo systemctl daemon-reload", "sudo systemctl enable --now myapp.service", "rm -f /tmp/artifact-*.tar.gz" ] } } ``` Или ещё чище — положить артефакт в **S3**/**Artifactory**/**GHCR** и тянуть по https. #### Вариант В — Золотой стандарт на 2026 год (если позволяет время и масштаб) 1. CI делает deb/rpm-пакет (или tar.gz + manifest.json) 2. Публикует в Artifactory / Packagecloud / GitHub Releases / S3 3. Terraform только управляет инфраструктурой и желаемой версией 4. На сервере работает **tiny agent** (systemd-таймер + curl + bash) или **ansible-pull**, который раз в 1–5 минут проверяет новую версию и ставит её Пример минимального systemd-таймера + сервиса-апдейтера: ```ini # /etc/systemd/system/myapp-updater.timer [Unit] Description=Update myapp every 5 minutes [Timer] OnBootSec=3min OnUnitActiveSec=5min Unit=myapp-updater.service [Install] WantedBy=timers.target ``` ```ini # /etc/systemd/system/myapp-updater.service [Service] Type=oneshot ExecStart=/opt/myapp/update.sh ``` ### Краткие рекомендации Ситуация | Что выбрать в 2026 -------------------------------------|------------------------- Один-два сервера, быстро надо | Вариант А (GitHub Actions + scp + ssh) Средний проект, много серверов | Вариант Б (Terraform + releases) или Вариант А + Ansible-pull Хотите «по-взрослому», надолго | deb/rpm + свой маленький apt/yum репозиторий Уже есть Kubernetes | Flux/ArgoCD + kustomize/helm + git Удачи с деплоем! 🚀 Какой у тебя сейчас масштаб и какие ограничения (деньги, время, команда)? Могу предложить более точный вариант. ] } } } } } } ри 3 людях в команде, нулевом/очень маленьком бюджете и ~10 серверах самая разумная стратегия на 2026 год выглядит так: **Цель**: минимизировать время поддержки + количество мест, где может что-то сломаться **Принцип**: один раз настроил → дальше почти всё через git push ### Рекомендуемый вариант (топ-1 для вашей ситуации) **GitHub Actions → scp/rsync + atomic переключение + systemd** Почему именно это: - Стоимость ≈ 0 € (GitHub Actions free tier 2000 минут/месяц хватает с огромным запасом) - Минимум новых технологий - Работает на любых linux-серверах (даже очень старых) - Легко откатывать (оставляем предыдущую версию) - 3 человека реально поддерживают без боли #### Структура репозитория (самая практичная) ``` my-project/ ├── app/ # исходники │ └── main.go ├── deploy/ │ ├── bin/ # сюда кладём готовый бинарник при релизе (опционально) │ ├── config/ │ │ └── prod.yaml │ ├── systemd/ │ │ └── myapp.service │ └── versions/ │ └── current.txt # просто номер версии или git sha └── .github/workflows/ └── deploy.yml ``` #### Самый простой и надёжный deploy.yml (2026 версия) ```yaml name: Deploy to all servers on: push: branches: [ main ] workflow_dispatch: # можно запускать вручную jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.23' # или ваша версия - name: Build binary run: | GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" \ -o deploy/bin/myapp ./app - name: Pack artifact run: | cd deploy tar czf artifact.tar.gz bin/ config/ systemd/ versions/ - name: Upload artifact uses: actions/upload-artifact@v4 with: name: deployment-artifact path: deploy/artifact.tar.gz deploy: needs: build runs-on: ubuntu-latest strategy: matrix: server: [ "10.10.1.11", "10.10.1.12", "..." ] # ваши 10 ip/доменов # или лучше через переменные/файл, но для начала так проще steps: - uses: actions/download-artifact@v4 with: name: deployment-artifact - name: Deploy to ${{ matrix.server }} uses: appleboy/scp-action@v0.1.7 with: host: ${{ matrix.server }} username: deploy key: ${{ secrets.SSH_PRIVATE_KEY }} source: "artifact.tar.gz" target: "/opt/myapp.new" strip_components: 0 - name: Atomic switch & restart uses: appleboy/ssh-action@v1.0.3 with: host: ${{ matrix.server }} username: deploy key: ${{ secrets.SSH_PRIVATE_KEY }} script: | set -euo pipefail cd /opt/myapp.new sudo tar xzf artifact.tar.gz # Проверка что бинарник запускается (очень важно!) sudo /opt/myapp.new/bin/myapp --version || exit 1 sudo rm -rf /opt/myapp.old sudo mv /opt/myapp /opt/myapp.old 2>/dev/null || true sudo mv /opt/myapp.new /opt/myapp sudo cp /opt/myapp/systemd/myapp.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable myapp.service sudo systemctl restart myapp.service # Опционально: чистка старых версий через 1 день # find /opt -maxdepth 1 -name 'myapp.old.*' -mtime +1 -exec rm -rf {} \; ``` ### Альтернативы (если описанное выше по каким-то причинам не подходит) | Вариант | Сложность | Время настройки | Стоимость | Подходит если... | |-------------------------------|-----------|------------------|-----------|-----------------------------------------------| | GitHub Actions + scp (выше) | ★☆☆ | 1–3 дня | ~0€ | Хотите самый быстрый старт | | Ansible-pull из git каждые 5 мин | ★★☆ | 3–7 дней | ~0€ | Хотите более идемпотентно и конфиги в git | | Terraform + null_resource/ssh | ★★★ | 5–14 дней | ~0€ | Уже активно используете terraform для серверов| | Самопальный tiny-agent (curl+bash+systemd timer) | ★★☆ | 4–10 дней | ~0€ | Очень не любите внешние зависимости | | Docker + docker-compose pull | ★★☆ | 4–12 дней | ~0€ | Готовы перейти на контейнеры (рекомендую!) | ### Краткий совет по приоритетам 1. Сделайте сначала **один** сервер по схеме выше (очень быстро) 2. Добавьте простейшую проверку здоровья после рестарта `systemctl is-active --quiet myapp && curl -f http://localhost:8080/health || exit 1` 3. Только после этого масштабируйте на остальные 9 серверов 4. Параллельно думайте о переходе на **docker + docker compose pull** — это следующий логичный и очень популярный шаг для команд 3–8 человек в 2026 году (даже без kubernetes) Если скажете, на каком языке написано приложение и есть ли уже docker — смогу дать ещё более точный вариант.