Pular para o conteúdo

Troubleshooting

no basic auth credentials ou denied no docker pull

O registry é privado e você ainda não autenticou, ou a identidade que está puxando não é a que autorizamos. Veja Autenticar antes do pull.

Se o pull falha dentro do orquestrador mas funciona no seu terminal, a identidade é outra: quem puxa ali é a plataforma (task execution role, role do node group, service account), não você. Nos informe qual é para autorizarmos.

certificate has expired

O certificado do seu tenant venceu. Ele não se renova sozinho: solicite o par novo ao RootPilot, substitua o conteúdo montado em /certs e recicle as réplicas.

Para não ser pego de novo, o notAfter sai no log a cada boot:

{"level":"info","message":"using provisioned cert","context":"runner","notAfter":"..."}

is not in the cert's altnames

Você conectou por um hostname que não está no SAN do certificado do túnel. Mesmo que ele resolva para o IP certo, o TLS recusa. Em produção o hostname é tunnel.rootpilot.sh.

Nada acontece, e não há erro

Confirme que existe um túnel de control-plane escutando no RUNNER_TUNNEL_URL. Em desenvolvimento o default é :8443 no host; no Linux, o Compose já mapeia host.docker.internal via host-gateway.

Ciclo 1006 → exited 0 → restart

O túnel do outro lado está reiniciando. Estabilize-o e o runner para de ciclar. O exited 0 é o timer de reconexão ser unref’d; o restart: unless-stopped o traz de volta quando o túnel volta.

O runner valida a configuração por schema e morre com o motivo. Os mais comuns:

Mensagem O que fazer
either provide RUNNER_CERT_PEM+RUNNER_KEY_PEM (provisioned cert) or RUNNER_ENROLL_URL Escolha um dos dois caminhos de identidade.
RUNNER_ATTESTATION_MODE=bootstrap-token requires RUNNER_BOOTSTRAP_TOKEN Falta o token. O fail-fast é intencional: sem ele o sintoma vira 401 em loop, que parece problema de rede.
RUNNER_ATTESTATION_MODE=aws-sts requires AWS_REGION A região não é adivinhada de propósito.
RUNNER_SECRET_STORE_MODE=vault requires RUNNER_VAULT_ADDR Configuração de Vault incompleta.
attestation mode 'eks-oidc' not implemented eks-oidc não existe. No EKS, use aws-sts.
op "…" claimed by both datadog and grafana Os dois providers de observabilidade registrados. Escolha um em RUNNER_OBSERVABILITY.
Could not locate the bindings file A imagem foi construída com --ignore-scripts. O better-sqlite3 é addon nativo e precisa do postinstall.

Sintomas típicos: entries.map is not a function, ou “op não implementada”.

Você está em synthetic, que é o default e é apenas um seed de 3 operações com formatos que não batem com os connectors reais.

  • Para dados reais: RUNNER_CONNECTORS=real mais as chaves.
  • Para o catálogo inteiro sem credencial: RUNNER_CONNECTORS=demo.

O sinal está no log de boot:

connector not served {connectorId: "azion", missing: ["AZION_TOKEN"]}

Três causas, em ordem de frequência:

  1. A chave não chegou ao container. O pass-through do Compose é por nome e explícito: variável ausente no host é chave omitida no container. Confira se o nome está na lista do docker-compose.yml.
  2. O nome está diferente. O connector azion declara AZION_TOKEN; um cofre com AZION_API_TOKEN produz exatamente o mesmo sintoma de chave ausente. Confira os nomes exatos em Credenciais por connector.
  3. O segredo não existe no store. Nos backends remotos, “não encontrado” resolve para undefined em vez de exceção, de propósito, para o modelo lazy funcionar.
skipped: no cluster configured (EKS_CLUSTER)

Falta EKS_CLUSTER. Vale distinguir: o connector aparece como não-configurado no Fleet, que é diferente de quebrado, e igualmente cego.

O master switch sozinho não basta: o exporter default é none. Veja Telemetria.

Esta é a pergunta de suporte mais frequente, e a resposta importa: null aqui significa “não sei”, e nunca “é zero”. A distinção é deliberada, e veio de uma classe de incidente em que um 0 fabricado foi lido como saúde.

Três regras que o edge segue:

1. Antes de devolver null, tenta a outra fonte. Ter taxa de erro não encerra a leitura de latência: se os percentis não vierem prontos e houver spans crus disponíveis, eles são calculados a partir dali, e o resultado diz de onde veio (percentileSource: 'spans').

2. O null que sobrevive carrega o código do motivo. Campos como percentilesUnavailable e instancesUnavailable existem para que “não foi emitido” e “não consultei” parem de ter a mesma cara.

3. Payload vazio prova se a pergunta existia. Um nome de serviço que não bate com nenhum serviço de APM volta com serviceResolved: false e a lista de candidatos, em vez do mesmo null geral que um serviço real e silencioso produziria.

E métrica derivada de denominador zero é null, nunca 0: uma razão sem denominador é indefinida, e 0% é o oposto de “não sei”: leva à ação oposta.

Não é bug. O Datadog manda todo stderr para status:error, então uma busca por erro pode devolver linhas cujo texto diz outra coisa.

A borda expõe a divergência com textLevel e levelMismatch, em vez de reescrever o level. A classificação da fonte é um fato sobre a fonte, e corrigi-la em silêncio apagaria informação.

Se o certificado passou de 6 minutos além do vencimento (5 de graça do control-plane, 1 de margem para skew), a identidade é irrecuperável: a atestação de renovação prova posse com o certificado que morreu.

O runner sai do processo de propósito, para que o supervisor suba um substituto que enrolla do zero. Confirme que o seu supervisor está configurado para isso. Sem ele, o efeito é um runner que some.

Mensagem do lado do control-plane:

presented cert expired beyond the renewal grace window

Do lado do Agent, a mesma situação aparece assim — e a segunda linha só existe quando o host ficou sem contar o tempo (suspensão, snapshot, container sem CPU):

{"level":"error","message":"identity expired beyond the renewal grace window — pausing reconnects"}
{"level":"warn","message":"renewal deadline slipped — wall-clock advanced while this process was not running"}

Enquanto isso o Agent para de reconectar, em vez de repetir o handshake que já se sabe recusado. As quedas desse período saem rotuladas identity_expired, e não network_error: um certificado vencido fecha o socket sem aviso, o que parece queda de rede e manda investigar o lado errado.

Esperado num reclaim duro (SIGKILL, OOM, spot sem drain). O flush periódico (RUNNER_LEARNED_FLUSH_INTERVAL_MS, default 60 s) limita a perda; não a elimina.

Lembre também que o learned-store local é cache: a fonte de verdade é o control-plane. Em Kubernetes, dimensione terminationGracePeriodSeconds acima de RUNNER_DRAIN_TIMEOUT_MS (default 120 s) para que o drain complete.

Não existe probe HTTP, porque o runner é cliente de saída. Os sinais disponíveis são:

  • Logs de boot: boot: liveness, boot: ready, e os connector not served.
  • O Fleet do control-plane, que enxerga o runner conectado e o status por connector reportado no handshake.
  • OTel, se ligado corretamente.