Também disponível em: English · Español · Français · العربية
Arquivo .dockerignore: gerador e verificador de caminhos
Escreva um .dockerignore, verifique qualquer caminho contra ele e veja lado a lado o que o git teria feito com o arquivo idêntico.
O que é um arquivo .dockerignore
O .dockerignore fica ao lado do seu Dockerfile e lista o que não deve ser enviado ao builder. Todo o contexto de build é empacotado e entregue antes de a primeira instrução rodar, então um node_modules esquecido ou um diretório .git custa tempo de upload em cada build, acaba dentro da imagem se algo o copiar, e quebra o cache de camadas silenciosamente, porque o contexto muda sempre que aqueles arquivos mudam.
Ele se parece exatamente com um .gitignore: um padrão por linha, uma cerquilha para comentários, um ponto de exclamação para abrir exceções. É aí que mora o problema. Os dois arquivos são processados por códigos completamente diferentes, e as mesmas linhas podem dar respostas opostas. Nada avisa, porque os dois arquivos são válidos nos dois lugares.
Esta página roda os dois motores ao mesmo tempo. Escreva o seu .dockerignore, informe um caminho, e ela mostra o que o comparador do Docker decide, o que as regras do git decidem, qual linha foi a responsável em cada caso e — a parte que explica tudo — com qual caminho cada um realmente casou.
Como usar
- Cole ou escreva o arquivo. Abaixo aparece cada linha com a forma que assume depois da limpeza e como será comparada: como string exata, prefixo, sufixo ou padrão. Os botões de exemplo carregam os quatro casos em que os dois arquivos divergem, mais um em que concordam.
- Informe um caminho. Relativo ao contexto de build e com barras normais. Marque a caixa se for uma pasta; isso só importa para as regras do git, e a ferramenta explica por quê.
- Leia os dois veredictos. Cada painel nomeia a linha que decidiu e o caminho com que ela casou. Quando divergem, é uma diferença real de comportamento e não um detalhe de exibição.
As quatro diferenças que pegam todo mundo
A primeira ninguém espera, e a própria bateria de testes do Docker a deixa registrada. Exclua tudo com asterisco duplo, reinclua um diretório com um ponto de exclamação, e um arquivo dentro desse diretório é enviado ao builder. Dê ao git as mesmas duas linhas e o arquivo continua ignorado, porque o git percorre o caminho de cima para baixo e nunca olha dentro de um diretório que já excluiu. O comparador do Docker continua avaliando padrões depois que um ancestral casa, então a exceção posterior ainda se aplica. As mesmas duas linhas, resultados opostos.
A segunda é a que mais custa tempo de build. Um padrão sem curinga é comparado ao caminho por igualdade de strings, e a cada diretório acima dele por vez; nada além disso. Então uma linha com node_modules exclui o que está na raiz do seu contexto e nenhum outro. A cópia aninhada dentro de um pacote é empacotada e enviada em todo build. Num .gitignore essa mesma linha casa em qualquer profundidade, que é exatamente por que o arquivo parece estar funcionando. Ponha dois asteriscos e uma barra na frente e o Docker alcança também as aninhadas.
A terceira é um caractere que desaparece. Todo padrão passa pela função de limpeza de caminhos do Go antes de ser usado, e essa função apaga a barra final. Então uma linha terminada em barra não fica restrita a diretórios aqui: é o mesmo padrão sem a barra, e vai casar igualmente com um arquivo de mesmo nome. No git, a barra final é justamente o que restringe um padrão aos diretórios.
A quarta é um caractere que não significa nada. A barra inicial é removida na leitura do arquivo, e os comentários do próprio código do Docker dizem que as duas grafias são equivalentes. No git, a barra inicial ancora o padrão ao diretório onde o arquivo está, e omiti-la é o que faz o padrão casar em qualquer profundidade. O mesmo caractere: decisivo de um lado, inerte do outro.
Limitações honestas
Isto compara, não constrói. Diz se um caminho seria enviado ao builder; não sabe se o arquivo existe, quanto o seu contexto realmente pesa nem o que o seu Dockerfile faz com nada disso. O Dockerfile e o próprio .dockerignore são sempre enviados, digam o que disserem os padrões, porque o builder precisa deles.
Os caminhos são tratados como separados por barras normais, que é com o que o builder de Linux trabalha. O comportamento reproduzido aqui é o do comparador do próprio Docker, e vale dizer com todas as letras: não existe especificação deste formato. O comparador é a definição, e a documentação não chega a descrevê-lo — os documentos citam uma função da biblioteca padrão do Go cujas regras de padrão não têm curinga recursivo algum, enquanto a implementação compila cada padrão para uma expressão regular e admite um. Vinte e três dos casos de teste da própria implementação de referência dependem desse comportamento.
Há uma regra que parece uma diferença e não é. O Docker passa os colchetes direto para uma expressão regular, então uma classe de caracteres é negada com um acento circunflexo em vez do ponto de exclamação que um glob de shell usaria; só que o git também aceita o circunflexo, de modo que as duas grafias se comportam igual dos dois lados. Está aqui porque é o óbvio de supor, e supor isso seria um erro.
Por fim, um comentário só conta como comentário quando a cerquilha é o primeiríssimo caractere da linha. Coloque um único espaço antes e ela deixa de ser comentário para virar um padrão que casa com um arquivo daquele nome. Essa ordem vem direto da implementação de referência, que procura a cerquilha antes de aparar os espaços.
Por que é grátis?
Comparar um caminho com uma lista de padrões são algumas centenas de linhas de manipulação de strings, e o seu navegador faz isso enquanto você digita. Nenhum servidor vê o seu arquivo, então não há nada a medir nem conta a criar.
Nada é enviado. O que você colar fica nesta aba.