Informação do sistema
Nossa empresa executa um aplicativo empacotado em uma imagem Docker baseada na imagem arm32v7/python:3.11-bullseye, que tem cerca de 800 MB de tamanho, em dispositivos Linux incorporados (sistema operacional Debian 9) no local.
Esses dispositivos ("dispositivos de ponta" doravante) têm memória interna limitada; os dispositivos são padronizados e possuem aproximadamente 6 GB de memória eMMC cada, e quase todo o espaço é alocado para overlayfs, que também é onde o Docker é configurado para armazenar seus dados.
daemon.json do dockerd:
{
"graph": "/overlayfs/docker",
"dns": [
"8.8.8.8"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
O tamanho total da imagem do aplicativo que a empresa usa é de 839 MB após pull - verifiquei isso docker image ls
em outro dispositivo de ponta que também está funcionando em produção.
O problema
Ao puxar a imagem do registro para o dispositivo de borda, fico sem espaço no estágio de extração - embora o espaço disponível seja significativamente maior que o tamanho da imagem.
Mensagem de erro (o caminho real é diferente em execuções diferentes):
write /var/lib/docker/vfs/dir/< long hash here >/usr/lib/arm-linux-gnueabihf/libicudata.a: no space left on device
Isso começou a acontecer recentemente, sem alterações na imagem - a mesma imagem foi implantada nos mesmos dispositivos antes, com pouca diferença no espaço disponível (cerca de 4 GB estão disponíveis em todos os dispositivos em condições normais).
Durante a extração, verifiquei repetidamente o espaço disponível restante df -h
e descobri que ele consome todos os ~ 4 GB de espaço disponível antes de morrer.
df -h
saída antes de iniciar o pull:
Filesystem Size Used Avail Use% Mounted on
devtmpfs 494M 0 494M 0% /dev
tpmfs 504M 48M 457M 10% /run
/dev/mmcblk0p2 446M 344M 75M 83% /
/dev/mmcblk0p3 6.6G 2.5G 3.9G 39% /overlayfs
overlay 6.6G 2.5G 3.9G 39% /var
overlay 6.6G 2.5G 3.9G 39% /etc
overlay 6.6G 2.5G 3.9G 39% /home
overlay 6.6G 2.5G 3.9G 39% /root
overlay 6.6G 2.5G 3.9G 39% /sbin
overlay 6.6G 2.5G 3.9G 39% /bin
overlay 6.6G 2.5G 3.9G 39% /usr
overlay 6.6G 2.5G 3.9G 39% /lib
overlay 6.6G 2.5G 3.9G 39% /tmp
overlay 6.6G 2.5G 3.9G 39% /mnt
overlay 6.6G 2.5G 3.9G 39% /opt
overlay 6.6G 2.5G 3.9G 39% /media
tmpfs 504M 4.0K 504M 1% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 504M 0 504M 0% /sys/fs/cgroup
tmpfs 101M 0 101M 0% /run/user/1001
df -h
saída logo antes da falha de pull:
Filesystem Size Used Avail Use% Mounted on
devtmpfs 494M 0 494M 0% /dev
tpmfs 504M 48M 457M 10% /run
/dev/mmcblk0p2 446M 344M 75M 83% /
/dev/mmcblk0p3 6.6G 6.2G 193M 98% /overlayfs
overlay 6.6G 6.2G 193M 98% /var
overlay 6.6G 6.2G 193M 98% /etc
overlay 6.6G 6.2G 193M 98% /home
overlay 6.6G 6.2G 193M 98% /root
overlay 6.6G 6.2G 193M 98% /sbin
overlay 6.6G 6.2G 193M 98% /bin
overlay 6.6G 6.2G 193M 98% /usr
overlay 6.6G 6.2G 193M 98% /lib
overlay 6.6G 6.2G 193M 98% /tmp
overlay 6.6G 6.2G 193M 98% /mnt
overlay 6.6G 6.2G 193M 98% /opt
overlay 6.6G 6.2G 193M 98% /media
tmpfs 504M 4.0K 504M 1% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 504M 0 504M 0% /sys/fs/cgroup
tmpfs 101M 0 101M 0% /run/user/1001
Isso leva à seguinte questão:
Por que isso acontece e como posso evitar que isso aconteça ou contornar isso ?
Até agora eu tentei o seguinte:
- Removendo o sistema docker e imagens. Resultado: 0B recuperado.
- Removendo completamente tudo no VFS do Docker (/var/lib/docker/vfs/dir/). Resultado: recuperou todo o espaço que o pull consumiu, mas não resolveu o problema - em outro pull acontece exatamente a mesma coisa.
- docker salva em um arquivo tar.gz e carrega o docker no dispositivo de destino. Resultado: Acontece exatamente a mesma coisa que ao puxar.
- Reconstrua a imagem diretamente em um dispositivo de borda. A mesma coisa acontece ao extrair a imagem base.
Não encontrei nenhuma maneira de limitar o espaço (temporário?) que o Docker usa para extração.
A causa raiz do problema no meu caso foi que o daemon Docker nos sistemas afetados parou de funcionar com o driver de armazenamento overlay2 e começou a funcionar com o driver de armazenamento VFS. Isso pode ser identificado por meio de
docker info
ou, se o dockerd estiver inativo, verificando se os arquivos estão presentes em /var/lib/docker/vfs/dir/ (ou se ele existe).O VFS consome mais armazenamento para as mesmas imagens, conforme página de documentação do Docker no driver de armazenamento VFS .
Como o modo VFS nunca foi planejado para ser habilitado no cenário de produção (ou, em nosso caso, nunca), a imagem do aplicativo nunca foi testada com o dockerd emparelhado com esse driver de armazenamento, e a imagem resultante no VFS realmente excede o espaço disponível.
A solução
Neste cenário específico, a solução é adicionar manualmente o seguinte ao /etc/docker/daemon.json:
"storage-driver": "overlay2"
Exemplo daemon.json apenas com o driver de armazenamento declarado:
Infelizmente, esse problema também significa que é provável que overlay2 tenha parado de funcionar por algum motivo no dispositivo de destino, já que é um dos primeiros drivers de armazenamento que o dockerd tenta carregar, mas se assumirmos que o kernel suporta overlayfs e que o dockerd não é executado sob um próprio contêiner, corrigindo isso está fora do escopo desta questão.
No meu caso particular, o dockerd provavelmente tentou montar seu armazenamento em /var/lib/docker ou algum outro diretório que já foi montado com OverlayFS. Isso não é compatível com o docker, então o especifiquei manualmente para colocar todos os dados em uma pasta específica em overlayfs/ usando a opção de gráfico .
Aqui está meu daemon.json que permitiu ao dockerd usar o driver overlay2: