2026-01-13 00:11:31 +03:00
2026-01-13 00:11:31 +03:00

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Вот несколько реальных и достаточно популярных подходов в 20252026 годах, как организовать доставку **бинарников**, **конфигов** и **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)

#### Вариант А — Самый простой и быстрый (очень популярен в 20252026)

```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**, который раз в 15 минут проверяет новую версию и ставит её

                                                                                                                                                                                                                                                                          Пример минимального 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 (выше)   | ★☆☆       | 13 дня          | ~0€       | Хотите самый быстрый старт                    |
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Ansible-pull из git каждые 5 мин | ★★☆     | 37 дней         | ~0€       | Хотите более идемпотентно и конфиги в git     |
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Terraform + null_resource/ssh | ★★★       | 514 дней        | ~0€       | Уже активно используете terraform для серверов|
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Самопальный tiny-agent (curl+bash+systemd timer) | ★★☆ | 410 дней     | ~0€       | Очень не любите внешние зависимости           |
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Docker + docker-compose pull  | ★★☆       | 412 дней        | ~0€       | Готовы перейти на контейнеры (рекомендую!)    |

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    ### Краткий совет по приоритетам

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    1. Сделайте сначала **один** сервер по схеме выше (очень быстро)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    2. Добавьте простейшую проверку здоровья после рестарта  
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       `systemctl is-active --quiet myapp && curl -f http://localhost:8080/health || exit 1`
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       3. Только после этого масштабируйте на остальные 9 серверов
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       4. Параллельно думайте о переходе на **docker + docker compose pull** — это следующий логичный и очень популярный шаг для команд 38 человек в 2026 году (даже без kubernetes)

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       Если скажете, на каком языке написано приложение и есть ли уже docker — смогу дать ещё более точный вариант.
Description
No description provided
Readme 30 KiB