Saltar a contenido

Despliega con GitLab CI y reinicia un pedido

Este ejemplo compila un proyecto Node.js, sube el resultado por SFTP con contraseña y reinicia un pedido de Zaroz Cloud mediante la API del Kernel. La contraseña SFTP transfiere archivos; un token de API granular e independiente solo controla el reinicio.

Puedes consultar Get Order Status y Toggle Order en la referencia OpenAPI del Kernel.

Qué necesitas

Desde el panel del pedido, obtén el host, puerto, usuario, contraseña y ruta de destino SFTP.

Crea un token dedicado con estos dos permisos, ambos limitados al pedido exacto:

  • orders.read: permite esperar a que el servidor se detenga.
  • orders.server.toggle: permite detenerlo y arrancarlo.

No le des acceso a terminal, facturación, bases de datos ni a todos los pedidos.

Añade variables CI/CD protegidas

En GitLab, abre Settings → CI/CD → Variables y añade:

Variable Tipo Opciones recomendadas
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

Genera ZAROZ_SFTP_KNOWN_HOSTS desde un equipo de confianza y comprueba la huella del host antes de guardarlo. No uses StrictHostKeyChecking=no en producción.

Protege el entorno de despliegue

Las variables protegidas solo se entregan a ramas o tags protegidos. Protege también el entorno de producción para que un merge request no fiable no pueda extraer las credenciales.

Añade .gitlab-ci.yml

El ejemplo espera que npm run build genere dist/. Adapta ambos a tu proyecto.

.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"

Por qué espera entre detener y arrancar

El endpoint cambia el estado deseado, pero Kubernetes aún necesita tiempo para apagar la carga. Arrancar de inmediato puede competir con la terminación. Consultar el estado evita esa carrera y deja un error útil en GitLab.

Si tu software admite una recarga gradual, prefiérela. Un ciclo de parada y arranque interrumpe a jugadores o usuarios activos.

Adapta la subida

El lote SFTP sobrescribe archivos coincidentes, pero no elimina archivos remotos que ya no estén en dist/. Si necesitas una copia exacta, despliega en directorios versionados y cambia la versión activa desde el script de arranque de tu aplicación.

No subas secretos desde el repositorio. Guárdalos en el panel de Zaroz o como variables CI/CD protegidas.

Solución de problemas

La API devuelve 403

Comprueba que ambos permisos están limitados al UUID de ZAROZ_ORDER_ID y que el propietario del token aún puede controlar el pedido.

SFTP muestra un error de clave de host

Actualiza ZAROZ_SFTP_KNOWN_HOSTS solo después de verificar la nueva huella por un canal de confianza.

La subida funciona pero el reinicio no

Comprueba que elegiste orders.server.toggle, además de orders.read, y que el token no ha caducado.

El servidor permanece en Stopping más de 60 segundos

Deja que el job falle en lugar de alternarlo repetidamente. Revisa el pedido en el panel y reintenta cuando termine de detenerse.