Kubernetes
O contêiner
Seção intitulada “O contêiner”A imagem é construída por apps/runner/Dockerfile, com contexto na raiz do repositório. O entrypoint
é apps/runner/docker-entrypoint.sh e o comando é:
node --import @rootpilot/otel/register apps/runner/dist/index.jsA imagem roda como root, e é por isso que o Compose monta ~/.aws em /root/.aws. Se o seu
cluster exige runAsNonRoot, essa é uma adaptação que você precisa fazer, e ela não está feita aqui.
Requisito 1: não existe probe HTTP
Seção intitulada “Requisito 1: não existe probe HTTP”O runner é cliente de saída. Ele não escuta em porta nenhuma, não expõe /healthz e não tem
endpoint de readiness.
Consequência direta: não configure httpGet em liveness ou readiness probes: todos vão falhar.
Se você precisa de um sinal, ele vem dos logs de boot (boot: ready) e do Fleet do control-plane, que
enxerga o runner conectado. A saúde por connector também é reportada no handshake, não por HTTP.
Requisito 2: graça de terminação maior que o drain
Seção intitulada “Requisito 2: graça de terminação maior que o drain”O runner trata SIGTERM drenando: ele para de aceitar trabalho novo, termina o que está em voo e só
então sai. O teto disso é RUNNER_DRAIN_TIMEOUT_MS, cujo default é 120 000 ms.
O default do Kubernetes para terminationGracePeriodSeconds é 30 s. Se você deixar assim, o
SIGKILL chega no meio do drain.
terminationGracePeriodSeconds: 150 # > RUNNER_DRAIN_TIMEOUT_MS (120s), com folgaUm reclaim duro sem drain (SIGKILL, OOM, spot) perde o estado aprendido desde o último flush. O
RUNNER_LEARNED_FLUSH_INTERVAL_MS (default 60 s) existe justamente para limitar essa perda, mas não
a elimina.
Requisito 3: nenhum volume persistente
Seção intitulada “Requisito 3: nenhum volume persistente”O runner é cattle e não tem estado durável. O cache SQLite do learned-store é :memory: por default.
Não crie PVC. Se você apontar RUNNER_LEARNED_STORE_PATH para um caminho em disco, saiba que está
criando um cache, não uma fonte de verdade: a fonte de verdade é o control-plane.
Requisito 4: identidade sem segredo na imagem
Seção intitulada “Requisito 4: identidade sem segredo na imagem”Este é o ponto em que Kubernetes muda o desenho, e para melhor.
GKE: gke-oidc
Seção intitulada “GKE: gke-oidc”O runner lê o token OIDC projetado da ServiceAccount do Kubernetes e o envia como atestação. Nada secreto entra na imagem: o token é um JWT de vida curta, com audiência fixa, que o kubelet projeta.
O caminho default é /var/run/secrets/tokens/gke-oidc/token, configurável por
RUNNER_GKE_TOKEN_PATH. Ou seja, o pod precisa de um volume projected com serviceAccountToken
montado exatamente ali.
Se o volume não estiver montado, o erro é explícito e diz isso:
RUNNER_ATTESTATION_MODE=gke-oidc: failed to read projected KSA token at/var/run/secrets/tokens/gke-oidc/token (is the Workload Identity token volume mounted?)EKS: aws-sts, e não eks-oidc
Seção intitulada “EKS: aws-sts, e não eks-oidc”O aws-sts assina um GetCallerIdentity com a cadeia de credenciais default do SDK, que no EKS
é o IRSA. Isso significa que a ServiceAccount anotada com o role IAM já basta, sem token de bootstrap
e sem humano no navegador.
Ele exige AWS_REGION explicitamente. Sem ela o boot falha com
RUNNER_ATTESTATION_MODE=aws-sts requires AWS_REGION. A região não é adivinhada de propósito,
porque o control-plane só aceita região da própria allowlist e um palpite viraria um
attestation_invalid que se lê como problema de credencial.
Requisito 5: segredos
Seção intitulada “Requisito 5: segredos”Prefira o secret manager que você já opera a Secrets do Kubernetes:
RUNNER_SECRET_STORE_MODE=aws (AWS Secrets Manager) ou vault (HashiCorp Vault KV v2). Os dois
resolvem por workload identity, sem chave estática. Veja Secret stores.
Para as credenciais de leitura da AWS, RUNNER_AWS_CRED_MODE=chain faz o SDK resolver por IRSA
direto, sem passar chave nenhuma pelo cluster.
Requisito 6: egress
Seção intitulada “Requisito 6: egress”Só saída, nada de entrada. Se você usa NetworkPolicy, a lista de destinos está em Pré-requisitos. Lembre que a allowlist declarada nos manifests dos connectors é documentação, não enforcement: para os connectors nativos, quem aplica egress control é o cluster.
O que ainda falta para um chart existir
Seção intitulada “O que ainda falta para um chart existir”Sendo explícito sobre o gap, já que a pergunta vai aparecer: um chart de verdade precisaria de
decisões que este repositório ainda não tomou: runAsNonRoot e a mudança de /root/.aws, valores
de resources (não há benchmark versionado), e a forma canônica de expor a escolha de atestação por
provedor. Enquanto isso não existir, escrever os manifests do lado de quem instala é o caminho
honesto.