Ir para o conteúdo

Implementar com GitLab CI e reiniciar uma encomenda

Este exemplo compila um projeto Node.js, envia o resultado por SFTP com palavra-passe e reinicia uma encomenda da Zaroz Cloud através da API do Kernel. A palavra-passe SFTP transfere os ficheiros; um token de API detalhado e separado controla apenas o reinício.

Podes consultar Get Order Status e Toggle Order na referência OpenAPI do Kernel.

O que precisas

No painel da encomenda, recolhe o anfitrião, porto, utilizador, palavra-passe e caminho SFTP.

Cria um token dedicado com estas duas autorizações, ambas limitadas à encomenda exata:

  • orders.read — permite esperar que o servidor pare.
  • orders.server.toggle — permite parar e iniciar o servidor.

Não atribuas acesso ao terminal, faturação, bases de dados ou a todas as encomendas.

Adicionar variáveis CI/CD protegidas

No GitLab, abre Settings → CI/CD → Variables e adiciona:

Variável Tipo Opções 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

Gera ZAROZ_SFTP_KNOWN_HOSTS num computador de confiança e confirma a impressão digital do anfitrião. Não uses StrictHostKeyChecking=no numa pipeline de produção.

Protege o ambiente de implementação

As variáveis protegidas só estão disponíveis para branches ou tags protegidos. Protege também o ambiente de produção para que um merge request não fiável não consiga extrair credenciais.

Adicionar .gitlab-ci.yml

O exemplo espera que npm run build produza a pasta dist/. Adapta o comando e a pasta ao teu projeto.

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

Porque espera entre parar e iniciar

O endpoint altera o estado pretendido, mas o Kubernetes ainda precisa de tempo para terminar a carga. Iniciar imediatamente pode competir com a terminação. Consultar o estado evita essa corrida e deixa um erro útil no GitLab.

Se o teu software suporta recarregamento gradual, prefere-o. Um ciclo de paragem e arranque interrompe jogadores ou utilizadores ativos.

Adaptar o envio

O lote SFTP substitui ficheiros correspondentes, mas não elimina ficheiros remotos que desapareceram de dist/. Para um espelho exato, implementa em pastas com versão e muda a versão ativa no script de arranque da aplicação.

Nunca envies segredos a partir do repositório. Guarda-os no painel Zaroz ou em variáveis CI/CD protegidas.

Resolução de problemas

A API devolve 403

Confirma que ambas as autorizações usam o UUID em ZAROZ_ORDER_ID e que o proprietário do token ainda pode controlar a encomenda.

O SFTP apresenta um erro de chave do anfitrião

Atualiza ZAROZ_SFTP_KNOWN_HOSTS apenas depois de confirmares a nova impressão digital por um canal de confiança.

O envio funciona, mas o reinício não

Confirma orders.server.toggle, além de orders.read, e verifica se o token expirou.

O servidor fica em Stopping mais de 60 segundos

Deixa o job falhar em vez de alternar repetidamente. Inspeciona a encomenda no painel e repete depois da paragem completa.