A compilação do Docker não chega a uma dependência privada: verifique isto
Um pacote privado que o host consegue buscar ainda pode falhar dentro da compilação. Nomeie o builder, prove a rota e monte então o token como segredo de compilação.
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.