Um pacote privado que na sua máquina se resolve sem problemas pode falhar dentro da compilação com um 404 ou um tempo limite, e o Dockerfile raramente é a causa. O passo de compilação corre noutro espaço de nomes de rede, com outra vista do DNS e outro armazém de credenciais do que a shell em que testou. Percorra estas verificações por ordem e pare na primeira que falhar, porque cada verificação seguinte assume que a anterior passou. Cada passo nomeia o comando que resolve a questão.

Comece por nomear o builder, não o Dockerfile

O BuildKit pode ser local, estar num contentor ou correr noutra máquina, e cada um tem a sua própria rede predefinida. Execute docker buildx ls e leia o nó marcado com um asterisco antes de alterar seja o que for. Um docker-container controlador ou um builder na nuvem não partilha a rota privada do seu portátil só porque escreveu lá o comando. Se o builder ativo for remoto, cada verificação restante tem de correr contra esse host e não contra a sua estação de trabalho.

O builder transporta também a sua própria configuração de resolver e as suas variáveis de proxy. Ambas são lidas no momento da compilação e não são herdadas do terminal que a iniciou.

Prove o caminho de rede a partir de dentro de um passo de compilação

Escreva um estágio descartável que resolva o host da dependência e abra uma ligação para ele. É o único teste que responde à pergunta pelo builder e não pela sua shell.

FROM alpine:3.20
RUN apk add --no-cache curl bind-tools  && getent hosts registry.example.internal  && curl -sS -o /dev/null -w "%{http_code}
" https://registry.example.internal/simple/

Compile esse ficheiro com o mesmo builder, modo de rede e montagens de segredos que a sua compilação real usa: docker buildx build --builder remote0 -f Dockerfile.probe --progress=plain .. Se getent não imprimir nada, a falha está na resolução de nomes e nenhuma credencial a corrige. Se o nome for resolvido mas o curl relatar um tempo limite, o obstáculo é a rota ou a política de saída à frente do registo.

Apague a sonda assim que responder. É um estágio de diagnóstico e nunca deve ser etiquetado nem enviado.

Monte a credencial em vez de a copiar

Quando a rota funcionar, a autenticação é a falha seguinte da lista. Uma montagem de segredo do BuildKit expõe um ficheiro a um único RUN passo sem o escrever numa camada, que é o que a ferramenta de dependências precisa e o que a imagem não deve guardar.

RUN --mount=type=secret,id=npmrc,target=/root/.npmrc     npm ci --omit=dev

O segredo tem de ser fornecido de fora do Dockerfile: docker buildx build --secret id=npmrc,src=/home/me/.npmrc .. O ficheiro fica no cliente e nunca entra no histórico da imagem. Um ARG ou um ENV com o mesmo token não fazem este trabalho, porque ambos ficam registados na configuração da imagem.

Uma imagem sem root precisa do seu próprio caminho de destino, como /home/app/.npmrc ou o ficheiro equivalente para pip, Maven ou Cargo. O destino da montagem tem de corresponder ao utilizador que executa o comando, senão a ferramenta reporta um ficheiro de configuração em falta que na realidade existe.

Audite o que a ferramenta de dependências deixa na imagem

Uma montagem temporária mantém a credencial fora de uma camada, mas não impede a ferramenta de escrever outra coisa. Os gestores de pacotes deixam ficheiros de bloqueio, diretórios de cache e por vezes o URL do registo já resolvido.

Leia o sistema de ficheiros final em vez de confiar no Dockerfile. docker history --no-trunc image:tag lista cada comando de camada, e docker run --rm image:tag sh -c "ls -a /root" mostra o que sobreviveu no contentor em execução. Mesmo quando o ficheiro foi apenas montado, um token escrito numa linha de registo durante npm ci continua a ser uma fuga.

Leia também o registo de compilação, porque --progress=plain imprime a saída dos comandos à letra. Se o token aparecer aí, rode-o antes de qualquer outra coisa e passe-o por um ficheiro que a ferramenta leia em silêncio.

Verifique que a imagem de execução já não precisa do caminho privado

A compilação e a aplicação em execução são dois consumidores diferentes da mesma dependência, e só o primeiro precisa do caminho privado. Uma imagem terminada deve arrancar, resolver as suas dependências de execução e servir tráfego sem a credencial de compilação.

Teste-o onde o registo privado estiver inacessível, ou simplesmente inicie o contentor com --network none e confirme que arranca sem o segredo montado. Um contentor que só arranca quando o segredo de compilação está presente continua ligado ao ambiente de compilação.

Se o contentor precisar mesmo do registo em tempo de execução, é uma decisão de acesso separada, e pertence ao armazém de segredos do orquestrador e não à compilação. Documente os dois caminhos em separado para que ninguém tente reparar um pull de execução com uma flag de compilação. Quando as cinco verificações passam, o sintoma original tem uma causa nomeada em cada camada em vez de uma suposição sobre a rede do Docker.

Artigos relacionados