Zum Inhalt

Mit GitLab CI ausrollen und eine Bestellung neu starten

Dieses Beispiel baut ein Node.js-Projekt, lädt das Ergebnis per passwortgeschütztem SFTP hoch und startet eine Zaroz-Cloud-Bestellung über die Kernel-API neu. Das SFTP-Passwort überträgt Dateien; ein getrenntes, fein abgestuftes API-Token darf nur den Neustart steuern.

Die Endpunkte Get Order Status und Toggle Order findest du in der Kernel-OpenAPI-Referenz.

Voraussetzungen

Notiere im Bestell-Dashboard SFTP-Host, Port, Benutzer, Passwort und Zielpfad.

Erstelle ein eigenes API-Token mit genau diesen beiden Freigaben für genau diese Bestellung:

  • orders.read – der Job kann auf den Stillstand warten.
  • orders.server.toggle – der Job kann den Server stoppen und starten.

Vergib weder Terminal-, Abrechnungs- oder Datenbankzugriff noch kontoweite Rechte.

Geschützte CI/CD-Variablen anlegen

Öffne in GitLab Settings → CI/CD → Variables und füge hinzu:

Variable Typ Empfohlene Optionen
ZAROZ_API_TOKEN Variable Masked, protected
ZAROZ_ORDER_ID Variable Protected
ZAROZ_SFTP_HOST Variable Protected
ZAROZ_SFTP_PORT Variable Protected
ZAROZ_SFTP_USER Variable Protected
ZAROZ_SFTP_PATH Variable Protected
ZAROZ_SFTP_PASSWORD Variable Masked, protected
ZAROZ_SFTP_KNOWN_HOSTS File Protected

Erzeuge ZAROZ_SFTP_KNOWN_HOSTS auf einem vertrauenswürdigen Rechner und prüfe den Host-Fingerabdruck. Verwende in einer Deployment-Pipeline niemals StrictHostKeyChecking=no.

Deployment-Umgebung schützen

Geschützte Variablen stehen nur geschützten Branches oder Tags zur Verfügung. Schütze auch die Produktionsumgebung, damit ein fremder Merge Request keine Credentials auslesen kann.

.gitlab-ci.yml hinzufügen

Das Beispiel erwartet, dass npm run build das Verzeichnis dist/ erzeugt. Passe beides an dein Projekt an.

.gitlab-ci.yml
stages:
  - build
  - deploy

build:
  stage: build
  image: node:22-alpine
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 hour

deploy-production:
  stage: deploy
  image: alpine:3.22
  needs:
    - job: build
      artifacts: true
  environment:
    name: production
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
  before_script:
    - apk add --no-cache curl jq lftp openssh-client
    - install -d -m 700 ~/.ssh
    - cp "$ZAROZ_SFTP_KNOWN_HOSTS" ~/.ssh/known_hosts
    - chmod 600 ~/.ssh/known_hosts
  script:
    - |
      export LFTP_PASSWORD="$ZAROZ_SFTP_PASSWORD"
      lftp -e "
        set cmd:fail-exit true;
        set sftp:connect-program \"ssh -a -x -o StrictHostKeyChecking=yes\";
        open --env-password --user \"$ZAROZ_SFTP_USER\" -p \"$ZAROZ_SFTP_PORT\" \"sftp://$ZAROZ_SFTP_HOST\";
        mirror --reverse --verbose --no-perms dist/ \"$ZAROZ_SFTP_PATH\";
        bye
      "
      unset LFTP_PASSWORD
    - |
      api() {
        curl --fail-with-body --silent --show-error \
          -H "Authorization: Bearer $ZAROZ_API_TOKEN" \
          -H 'Accept: application/json' \
          "$@"
      }

      API="https://kernel.zaroz.cloud/api/v1/orders/$ZAROZ_ORDER_ID"

      api -X POST \
        -H 'Content-Type: application/json' \
        -d '{"active":false}' \
        "$API/toggle"

      stopped=false
      for attempt in $(seq 1 30); do
        state="$(api "$API/status" | jq -r '.state')"
        echo "Waiting for stop: $state"

        case "$state" in
          Suspended|NotProvisioned)
            stopped=true
            break
            ;;
          Failed)
            echo "The order entered Failed state; refusing to start it automatically"
            exit 1
            ;;
        esac

        sleep 2
      done

      if [ "$stopped" != true ]; then
        echo "The order did not stop within 60 seconds"
        exit 1
      fi

      api -X POST \
        -H 'Content-Type: application/json' \
        -d '{"active":true}' \
        "$API/toggle"

      echo "Deployment uploaded and start requested"

Warum der Job zwischen Stopp und Start wartet

Der Endpunkt ändert den Sollzustand; Kubernetes braucht weiterhin Zeit zum Beenden. Ein sofortiger Start kann mit der Terminierung kollidieren. Die Statusabfrage verhindert dieses Rennen und hinterlässt in GitLab einen verständlichen Fehler.

Unterstützt deine Software einen sanften Reload, solltest du diesen bevorzugen. Ein Stopp/Start unterbricht aktive Spieler oder Benutzer.

Upload anpassen

Der SFTP-Batch überschreibt vorhandene Dateien, löscht aber keine entfernten Dateien aus dist/. Für eine exakte Spiegelung kannst du in versionierte Verzeichnisse ausrollen und die aktive Version über dein Startskript umschalten.

Lade keine Secrets aus dem Repository hoch. Bewahre sie im Zaroz-Dashboard oder in geschützten CI/CD-Variablen auf.

Fehlerbehebung

Die API antwortet mit 403

Prüfe, ob beide Freigaben auf dieselbe UUID in ZAROZ_ORDER_ID begrenzt sind und der Token-Besitzer die Bestellung weiterhin steuern darf.

SFTP meldet einen Host-Key-Fehler

Aktualisiere ZAROZ_SFTP_KNOWN_HOSTS erst, nachdem du den neuen Fingerabdruck über einen vertrauenswürdigen Kanal geprüft hast.

Upload funktioniert, Neustart aber nicht

Prüfe orders.server.toggle zusätzlich zu orders.read und das Ablaufdatum des Tokens.

Der Server bleibt länger als 60 Sekunden in Stopping

Lass den Job fehlschlagen, statt wiederholt umzuschalten. Prüfe die Bestellung im Dashboard und starte das Deployment nach dem vollständigen Stopp erneut.