Gitea Actions: сборка образа + деплой на список прокси-нод

- .gitea/workflows/build.yml — cargo build --release + docker build/push в
  ghcr.io/nineap/netrunner-proxy:latest (Dockerfile сам не компилирует Rust,
  ждёт уже готовый target/release/netrunner-server).
- .gitea/workflows/deploy.yml — только вручную (workflow_dispatch), параметр
  target: имя ноды из nodes.json или "all". Job "resolve" фильтрует список,
  job "deploy" — matrix по результату, каждая нода видна в прогоне отдельной
  строкой. Деплой пересоздаёт контейнер (pull+rm+run), не просто restart —
  иначе новый образ не подхватится.
- nodes.json — список нод (name/host/proxy_port/decoy_host), шаблон с
  CHANGE_ME — заполнить реальными IP.

Нужные секреты: GHCR_TOKEN (тот же, что и в остальных репо), PROXY_NODES_SSH_KEY
(общий master-ключ на все ноды), PROXY_INTERNAL_SECRET, BACKEND_URL (те же
значения, что уже настроены у бэкенда).
This commit is contained in:
2026-07-09 15:27:18 +07:00
parent e44bc4f660
commit c835ac983a
3 changed files with 165 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
# Собирает netrunner-server (release-бинарник) и пушит Docker-образ в ghcr.io.
# Dockerfile сам не компилирует Rust — он просто копирует уже готовый
# target/release/netrunner-server (см. Dockerfile), поэтому cargo build идёт
# отдельным шагом перед docker build, не внутри него.
#
# Нужен секрет GHCR_TOKEN — настоящий GitHub PAT с правом write:packages
# (автотокен Gitea для ghcr.io не годится, см. остальные .gitea/workflows/
# в других репозиториях — та же причина).
name: Build & Push Proxy Image
on:
push:
branches: [main]
tags: ["v*"]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: Swatinem/rust-cache@v2
- name: Build release binary
run: cargo build --release -p netrunner-server
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GHCR_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ghcr.io/nineap/netrunner-proxy:latest
+103
View File
@@ -0,0 +1,103 @@
# Деплой на прокси-ноды из nodes.json. Список серверов — сам файл в корне
# репозитория (name/host/proxy_port/decoy_host на каждую ноду), поддерживать
# его руками при добавлении/выводе серверов.
#
# Запуск только вручную (workflow_dispatch) — параметр target: имя ноды из
# nodes.json (поле "name") или "all" для обновления сразу всех. Job "resolve"
# фильтрует список по этому параметру и отдаёт job'у "deploy" как matrix —
# каждая нода тогда видна в прогоне отдельной строкой, с отдельным логом.
# GH/Gitea Actions не поддерживают выпадающий список (type: choice) с
# вариантами из файла — только статичные в самом yaml, а список нод меняется
# независимо от workflow, поэтому просто текстовое поле, значение — точное
# имя из nodes.json.
#
# Каждый деплой пересоздаёт контейнер (pull нового образа + rm + run) — не
# просто restart, иначе новый образ не подхватится, раз контейнер уже создан
# со старым слоем.
#
# Секреты (общие на все ноды — один master-ключ, как и при первичном
# провижининге через netrunner-backend, см. NodeService::provision_node_via_ssh):
# - PROXY_NODES_SSH_KEY — приватный SSH-ключ (root на все ноды)
# - PROXY_INTERNAL_SECRET — тот же секрет, что и PROXY_INTERNAL_SECRET у бэкенда
# - BACKEND_URL — публичный адрес control plane (WEB_APP_BASE_URL у бэкенда)
# - GHCR_TOKEN — тот же, что и в build.yml
name: Deploy Proxy Nodes
on:
workflow_dispatch:
inputs:
target:
description: 'Имя ноды из nodes.json ("name"), или "all" — обновить сразу все'
required: true
default: "all"
jobs:
resolve:
runs-on: ubuntu-24.04
outputs:
targets: ${{ steps.filter.outputs.targets }}
steps:
- uses: actions/checkout@v4
- name: Filter nodes.json by input
id: filter
run: |
set -e
command -v jq >/dev/null || (apt-get update && apt-get install -y jq)
target="${{ github.event.inputs.target }}"
if [ "$target" = "all" ]; then
filtered=$(jq -c '.' nodes.json)
else
filtered=$(jq -c --arg n "$target" '[.[] | select(.name == $n)]' nodes.json)
fi
count=$(echo "$filtered" | jq 'length')
if [ "$count" -eq 0 ]; then
echo "Нода '$target' не найдена в nodes.json" >&2
exit 1
fi
echo "targets=$filtered" >> "$GITHUB_OUTPUT"
deploy:
needs: resolve
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.resolve.outputs.targets) }}
runs-on: ubuntu-24.04
steps:
- name: Deploy to ${{ matrix.name }} (${{ matrix.host }})
uses: appleboy/ssh-action@v1
with:
host: ${{ matrix.host }}
username: root
key: ${{ secrets.PROXY_NODES_SSH_KEY }}
script: |
set -e
echo "🚀 Деплой на ${{ matrix.name }} (${{ matrix.host }}:${{ matrix.proxy_port }})"
echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
docker pull ghcr.io/nineap/netrunner-proxy:latest
docker stop netrunner-proxy 2>/dev/null || true
docker rm netrunner-proxy 2>/dev/null || true
docker run -d \
--name netrunner-proxy \
--restart always \
--network host \
--cap-add NET_ADMIN --cap-add NET_RAW --cap-add DAC_OVERRIDE \
--device /dev/net/tun:/dev/net/tun \
-e PROXY_INTERNAL_SECRET="${{ secrets.PROXY_INTERNAL_SECRET }}" \
ghcr.io/nineap/netrunner-proxy:latest \
./netrunner-proxy \
--port "${{ matrix.proxy_port }}" \
--decoy-host "${{ matrix.decoy_host }}" \
--require-auth \
--backend-url "${{ secrets.BACKEND_URL }}" \
--health-port 9091
docker image prune -f
echo "✅ ${{ matrix.name }} обновлена."
+14
View File
@@ -0,0 +1,14 @@
[
{
"name": "nl-1",
"host": "CHANGE_ME_IP_1",
"proxy_port": 443,
"decoy_host": "www.debian.org"
},
{
"name": "sg-1",
"host": "CHANGE_ME_IP_2",
"proxy_port": 8443,
"decoy_host": "ubuntu.com"
}
]