# Деплой на прокси-ноды из 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 у бэкенда # - GITEA_REGISTRY_TOKEN — тот же, что и в build.yml (Container Registry Gitea, # не ghcr.io — каждая нода тянет образ напрямую с gitea.netrunner-vpn.com) # # Repo Variable (vars.*, не secret — публичный URL, не даёт доступа сам по себе): # - BACKEND_URL — публичный адрес control plane (WEB_APP_BASE_URL у бэкенда) # # Job update-observability-targets (см. ниже) обновляет список scrape-таргетов # для центрального Prometheus (netrunner-data/docker-compose.observability.yml, # job "netrunner-proxy-nodes") при КАЖДОМ прогоне (независимо от input target, # т.к. использует полный nodes.json) — ему нужны СВОИ копии секретов/vars # VPS с данными, продублировать в Settings этого репозитория (те же значения, # что уже есть в netrunner-data): # - vars.DATA_VPS_IP # - secrets.DATA_SSH_PRIVATE_KEY 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.GITEA_REGISTRY_TOKEN }}" | docker login gitea.netrunner-vpn.com -u ${{ github.actor }} --password-stdin docker pull gitea.netrunner-vpn.com/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 }}" \ gitea.netrunner-vpn.com/nineap/netrunner-proxy:latest \ ./netrunner-proxy \ --port "${{ matrix.proxy_port }}" \ --decoy-host "${{ matrix.decoy_host }}" \ --require-auth \ --backend-url "${{ vars.BACKEND_URL }}" \ --health-port 9091 \ --metrics-port 9093 docker image prune -f echo "✅ ${{ matrix.name }} обновлена." # Независимо от того, какая конкретно нода деплоилась (target может быть # одной нодой, не "all") — список scrape-таргетов всегда генерится из ПОЛНОГО # nodes.json, чтобы центральный Prometheus не терял из виду остальные ноды. update-observability-targets: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Generate targets/nodes.json from nodes.json run: node scripts/generate-prometheus-targets.mjs nodes.json > nodes.targets.json - name: Upload to observability VPS uses: appleboy/scp-action@v0.1.7 with: host: ${{ vars.DATA_VPS_IP }} username: root key: ${{ secrets.DATA_SSH_PRIVATE_KEY }} source: "nodes.targets.json" target: "/root/netrunner-data/observability/targets" strip_components: 0 - name: Rename to nodes.json (file_sd_configs ждёт именно это имя) uses: appleboy/ssh-action@v1 with: host: ${{ vars.DATA_VPS_IP }} username: root key: ${{ secrets.DATA_SSH_PRIVATE_KEY }} script: mv /root/netrunner-data/observability/targets/nodes.targets.json /root/netrunner-data/observability/targets/nodes.json