FNSP Web Page

O .dockerignore: o ficheiro que quase ninguém escreve

Naquele docker build . que toda a gente escreve, o ponto final não quer dizer «o Dockerfile está aqui». Quer dizer: empacota esta pasta inteira e envia-a. Acontece antes de o Docker ler uma única linha do Dockerfile.

Contei os ficheiros deste projeto para ver o que isso significa:

node_modules          54 077 ficheiros   895 MB
.next                  3 004 ficheiros   340 MB
.git                   1 262 ficheiros     4 MB
src, public, prisma      118 ficheiros

a pasta inteira                           1,3 GB

Sem um .dockerignore, são 1,3 GB e cerca de 58 mil ficheiros a viajar em cada construção, para uma imagem que precisa de 118 deles.

1. O que isso custa, além do tempo

O tempo é o menor dos problemas — aquela linha do «a enviar o contexto» que ninguém lê. O que dói é a cache das camadas.

Um COPY . . produz uma camada com uma impressão digital do que foi copiado. Se qualquer coisa no contexto mudar, essa camada muda, e tudo o que vem a seguir é reconstruído. Com o .next dentro do contexto, basta ter tido o servidor de desenvolvimento a correr para que cada build recomece do zero, sem razão nenhuma.

2. O problema a sério é outro

O .env. Se ele estiver no contexto e houver um COPY . ., vai para dentro da imagem — e aqui está a parte que apanha muita gente:

COPY . .
RUN rm .env    # não serve de nada

As camadas são cumulativas. O rm cria uma camada nova onde o ficheiro não aparece, mas a camada anterior continua lá dentro, inteira, dentro da imagem que se publicou. Quem tiver a imagem consegue extraí-la:

docker save a-minha-imagem -o imagem.tar
tar -xf imagem.tar
# e ler as camadas uma a uma

Um segredo que entrou numa camada está publicado. A única forma de o tirar é construir a imagem outra vez sem ele — e rodar o segredo, porque já lá esteve.

3. O node_modules é o que engana

Parece só peso a mais, e não é. Um COPY . . leva o node_modules da máquina de quem constrói para dentro da imagem, por cima do que o npm ci lá instalou.

Enquanto forem módulos em JavaScript puro, ninguém dá por nada. Assim que um deles trouxer binários compilados — e há sempre um — ficam binários de Windows ou de macOS dentro de uma imagem Alpine, e o erro aparece no arranque, longe da causa.

4. Como se escreve

A sintaxe é a do .gitignore, com ! para voltar a incluir. Este é o deste site, quase por inteiro:

.git
.vscode
node_modules

# Compilado localmente; a imagem constrói o seu.
.next
*.tsbuildinfo

# Segredos. Em produção as variáveis vêm do ambiente.
.env
.env.*

# Documentação e ferramentas de migração: não pertencem à imagem.
*.md
!README.md
deploy
fixtures
scripts

Repare no par *.md seguido de !README.md: fica tudo de fora menos um. É a construção que mais falta faz e que menos gente conhece.

5. Não é o .gitignore

São listas com propósitos diferentes, e copiar uma para a outra dá sempre problemas nos dois sentidos:

  • Coisas que o Git ignora e a imagem precisa — um ficheiro gerado no momento da construção, uma pasta de recursos produzida por outra ferramenta.

  • Coisas que o Git segue e a imagem não quer — documentação, capturas de ecrã, fixtures de teste, os scripts de migração que já correram. Tudo isso está no repositório com toda a razão, e não tem nada que fazer dentro de um contentor de produção.

6. Ver o que entrou mesmo

Não é preciso adivinhar. Constrói-se uma imagem descartável que copia o contexto e conta:

docker build -f- . <<'FIM'
FROM busybox
COPY . /ctx
RUN find /ctx -type f | wc -l
FIM

O -f- lê o Dockerfile da entrada padrão e o . continua a ser o contexto. Se aquele número vier na casa das dezenas de milhar, já se sabe o que falta.

O resumo

O .dockerignore escreve-se uma vez e resolve três coisas ao mesmo tempo: builds que deixam de reconstruir tudo sem motivo, imagens que não levam lá dentro o que a máquina de quem as construiu tinha, e segredos que não ficam presos numa camada para sempre. Para um ficheiro de vinte linhas, é bom negócio.

Comentários

Ainda ninguém comentou este artigo.

Voltar ao blog

Gostávamos de saber quantas pessoas visitam o site, com o Google Analytics. Sem a sua autorização não corre nada. Política de Privacidade.