Dicas do Docker: Limpe sua máquina de lixo

Dicas do Docker: Limpe sua máquina de lixo

Olá, Habr! Apresento a vocês a tradução do artigo "Dicas do Docker: Limpe sua Máquina Local" autor Luc Juggery.

Hoje vamos discutir como o Docker utiliza o espaço em disco da máquina host e como liberar esse espaço de fragmentos não utilizados de imagens e contêineres.


Dicas do Docker: Limpe sua máquina de lixo

Consumo total

Docker é uma ferramenta incrível, e hoje em dia, poucos duvidam disso. Apenas alguns anos atrás, esse produto nos ofereceu uma nova maneira de construir, entregar e executar qualquer ambiente, permitindo economizar significativamente nos recursos de CPU e memória. Além disso (e para alguns, isso pode ser o mais importante), o Docker nos permitiu simplificar e unificar incrivelmente a gestão do ciclo de vida dos ambientes de trabalho utilizados.

No entanto, por todas essas maravilhas da vida moderna, devemos pagar um preço. Quando executamos contêineres, baixamos ou criamos nossas próprias imagens, ou implantamos ecossistemas complexos, acabamos pagando. E pagamos, entre outras coisas, com espaço em disco.

Se você nunca se perguntou quanto espaço realmente está ocupado na sua máquina pelo Docker, pode ficar desagradavelmente surpreendido com a saída deste comando:

$ docker system df

Dicas do Docker: Limpe sua máquina de lixo

Aqui está exibido o uso de disco do Docker em várias categorias:

  • imagens (images) – o tamanho total das imagens que foram baixadas dos repositórios de imagens e construídas no seu sistema;
  • contêineres (containers) – o volume total de espaço em disco utilizado pelos contêineres em execução (referindo-se ao volume total das camadas de leitura e gravação de todos os contêineres);
  • volumes locais (local volumes) – o volume dos armazenamento locais montados em contêineres;
  • cache de construção (build cache) – arquivos temporários gerados durante o processo de construção de imagens (ao usar a ferramenta BuildKit, disponível a partir do Docker versão 18.09).

Aposto que, já após essa simples listagem, você está ansioso para limpar o disco do lixo e recuperar preciosos gigabytes (nota do tradutor: especialmente se você paga aluguel mensalmente por esses gigabytes).

Uso de disco pelos contêineres

Toda vez que um contêiner é criado na máquina host, vários arquivos e diretórios são criados no diretório /var/lib/docker, entre os quais vale a pena destacar os seguintes:

  • O diretório /var/lib/docker/containers/ID_do_conteiner – ao usar o driver de log padrão, os logs de eventos são salvos aqui em formato JSON. Logs muito detalhados, assim como aqueles que ninguém lê ou processa de outras formas, costumam causar a cheia dos discos.
  • O diretório /var/lib/docker/overlay2 – contém as camadas de leitura e gravação dos contêineres (overlay2 – é o driver preferido na maioria das distribuições Linux). Se um contêiner armazena dados em seu sistema de arquivos, é neste diretório que eles serão colocados.

Vamos imaginar um sistema onde o Docker esteja instalado pela primeira vez, não tendo sido utilizado para executar contêineres ou construir imagens. Seu relatório de uso de espaço em disco será assim:

$ docker system df
TIPO           TOTAL      ATIVO     TAMANHO    RECUPERÁVEL
Imagens        0          0          0B         0B
Contêineres    0          0          0B         0B
Volumes Locais 0          0          0B         0B
Cache de Build 0          0          0B         0B

Vamos executar algum contêiner, por exemplo, o NGINX:

$ docker container run --name www -d -p 8000:80 nginx:1.16

O que acontece com o disco:

  • as imagens (images) ocupam 126 MB, é o próprio NGINX que executamos no contêiner;
  • os contêineres (containers) ocupam apenas 2 bytes.

$ docker system df
TIPO           TOTAL      ATIVO     TAMANHO    RECUPERÁVEL
Imagens        1          1          126M       0B (0%)
Contêineres    1          1          2B         0B (0%)
Volumes Locais 0          0          0B         0B
Cache de Build 0          0          0B         0B

De acordo com a saída, ainda não temos espaço que possamos liberar. Como 2 bytes é absolutamente insignificante, vamos imaginar que nosso NGINX, surpreendendo a todos, escreveu 100 Megabytes de dados em algum lugar e criou um arquivo test.img exatamente desse tamanho.

$ docker exec -ti www 
  dd if=/dev/zero of=test.img bs=1024 count=0 seek=$[1024*100]

Vamos investigar novamente o uso de espaço em disco no host. Veremos que o contêiner (containers) ocupa 100 Megabytes lá.

$ docker system df
TIPO           TOTAL      ATIVO     TAMANHO    RECUPERÁVEL
Imagens        1          1          126M       0B (0%)
Contêineres    1          1          104.9MB    0B (0%)
Volumes Locais 0          0          0B         0B
Cache de Build 0          0          0B         0B

Imagino que sua mente curiosa já esteja se perguntando onde está o nosso arquivo test.img. Vamos procurá-lo:

$ find /var/lib/docker -type f -name test.img
/var/lib/docker/overlay2/83f177...630078/merged/test.img
/var/lib/docker/overlay2/83f177...630078/diff/test.img

Sem entrar em detalhes, podemos notar que o arquivo test.img está convenientemente localizado em um nível de leitura-gravação, gerenciado pelo driver overlay2. Se pararmos nosso contêiner, o host nos indicará que esse espaço pode ser liberado.

# Stopping the www container
$ docker stop www

# Visualizing the impact on the disk usage
$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          1          126M       0B (0%)
Containers     1          0          104.9MB    104.9MB (100%)
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Como podemos fazer isso? Através da remoção do contêiner, o que resultará na limpeza do espaço correspondente no nível de leitura-gravação.

Com o seguinte comando, você pode remover todos os contêineres instalados de uma vez e limpar seu disco de todos os arquivos que eles criaram no nível de leitura-gravação:

$ docker container prune
WARNING! Isso removerá todos os contêineres parados.
Você tem certeza de que deseja continuar? [y/N] y
Contêineres Excluídos:
5e7f8e5097ace9ef5518ebf0c6fc2062ff024efb495f11ccc89df21ec9b4dcc2

Espaço total recuperado: 104.9MB

Assim, liberamos 104,9 Megabytes com a remoção do contêiner. Mas como já não estamos utilizando a imagem baixada anteriormente, ela também se torna uma candidata para remoção e liberação dos nossos recursos:

$ docker system df
TIPO           TOTAL      ATIVO     TAMANHO     RECUPERÁVEL
Imagens       1          0          126M       126M (100%)
Contêineres    0          0          0B         0B
Volumes Locais 0          0          0B         0B
Cache de Build 0          0          0B         0B

Atenção: enquanto a imagem estiver sendo usada por pelo menos um contêiner, você não poderá usar esse truque.

O subcomando prune que usamos acima tem efeito apenas em contêineres parados. Se quisermos remover não apenas os parados, mas também os contêineres em execução, devemos usar um destes comandos:

# Historical command
$ docker rm -f $(docker ps –aq)

# More recent command
$ docker container rm -f $(docker container ls -aq)

Notas à margem: se ao iniciar o contêiner você usar o parâmetro —rm, então ao pará-lo todo o espaço em disco que ele ocupava será liberado.

Uso de disco por imagens

Há alguns anos, um tamanho de imagem de algumas centenas de megabytes era perfeitamente normal: a imagem do Ubuntu pesava 600 Megabytes, enquanto a imagem do Microsoft .Net – alguns Gigabytes. Naqueles tempos remotos, baixar apenas uma imagem poderia causar um grande dano ao seu espaço livre no disco, mesmo que você estivesse compartilhando camadas entre imagens. Hoje - graças aos grandes avanços - as imagens pesam muito menos, mas mesmo assim, é possível rapidamente ocupar os recursos disponíveis se precauções não forem tomadas.

Existem vários tipos de imagens que não são diretamente visíveis para o usuário final:

  • imagens intermediárias, com base nas quais outras imagens são criadas – elas não podem ser removidas se você estiver utilizando contêineres baseados nessas "outras" imagens;
  • imagens pendentes – são aquelas imagens intermediárias que não são referenciadas por nenhum dos contêineres em execução – elas podem ser removidas.
  • Com o seguinte comando, você pode verificar a presença de imagens pendentes em seu sistema:

$ docker image ls -f dangling=true
REPOSITORY  TAG      IMAGE ID         CREATED             SIZE
none      none   21e658fe5351     12 minutes ago      71.3MB

Você pode removê-las da seguinte forma:

$ docker image rm $(docker image ls -f dangling=true -q)

Podemos também usar o subcomando prune:

$ docker image prune
AVISO! Isso removerá todas as imagens pendentes.
Você tem certeza de que deseja continuar? [y/N] y
Imagens deletadas:
deleted: sha256:143407a3cb7efa6e95761b8cd6cea25e3f41455be6d5e7cda
deleted: sha256:738010bda9dd34896bac9bbc77b2d60addd7738ad1a95e5cc
deleted: sha256:fa4f0194a1eb829523ecf3bad04b4a7bdce089c8361e2c347
deleted: sha256:c5041938bcb46f78bf2f2a7f0a0df0eea74c4555097cc9197
deleted: sha256:5945bb6e12888cf320828e0fd00728947104da82e3eb4452f

Espaço total recuperado: 12.9kB

Se por acaso quisermos remover todas as imagens (e não apenas as pendentes) com um único comando, podemos fazer assim:

$ docker image rm $(docker image ls -q)

Uso de disco com volumes

Volumes são usados para armazenar dados fora do sistema de arquivos do contêiner. Por exemplo, se quisermos manter os resultados do trabalho de um aplicativo para utilizar de outra forma. Um exemplo comum são os bancos de dados.

Vamos rodar um contêiner MongoDB, montar um volume externo a ele e restaurar a partir de um backup do banco de dados (que está disponível no arquivo bck.json):

# Running a mongo container
$ docker run --name db -v $PWD:/tmp -p 27017:27017 -d mongo:4.0

# Importing an existing backup (from a huge bck.json file)
$ docker exec -ti db mongoimport 
  --db 'test' 
  --collection 'demo' 
  --file /tmp/bck.json 
  --jsonArray

Os dados estarão na máquina host no diretório /var/lib/docker/volumes. Mas por que não no nível de leitura-gravação do contêiner? Porque no Dockerfile da imagem MongoDB, o diretório /data/db (onde o MongoDB armazena seus dados por padrão) é definido como um volume.

Dicas do Docker: Limpe sua máquina de lixo

Notas à margem: muitas imagens que geram dados durante sua execução utilizam volumes para armazenar esses dados.

Quando nos divertirmos com o MongoDB e pararmos (ou até mesmo removermos) o contêiner, o volume não será deletado. Ele continuará ocupando nosso precioso espaço em disco até que o removamos explicitamente com o seguinte comando:

$ docker volume rm $(docker volume ls -q)

Ou podemos usar o subcomando prune que já conhecemos:

$ docker volume prune
ATENÇÃO! Isso removerá todos os volumes locais que não estão sendo usados por pelo menos um contêiner.
Você tem certeza de que deseja continuar? [y/N] y
Volúmenes deletados:
d50b6402eb75d09ec17a5f57df4ed7b520c448429f70725fc5707334e5ded4d5
8f7a16e1cf117cdfddb6a38d1f4f02b18d21a485b49037e2670753fa34d115fc
599c3dd48d529b2e105eec38537cd16dac1ae6f899a123e2a62ffac6168b2f5f
...
732e610e435c24f6acae827cd340a60ce4132387cfc512452994bc0728dd66df
9a3f39cc8bd0f9ce54dea3421193f752bda4b8846841b6d36f8ee24358a85bae
045a9b534259ec6c0318cb162b7b4fca75b553d4e86fc93faafd0e7c77c79799
c6283fe9f8d2ca105d30ecaad31868410e809aba0909b3e60d68a26e92a094da

Total de espaço recuperado: 25.82GB
luc@saturn:~$

Uso de disco para cache de builds de imagens

No Docker 18.09, o processo de criação de imagens passou por algumas mudanças graças à ferramenta BuildKit. Com essa ferramenta, a velocidade do processo aumenta, e a gestão de armazenamento e segurança se otimiza. Aqui, não abordaremos todos os detalhes dessa ferramenta incrível, mas nos concentraremos em como ela afeta o uso do espaço em disco.

Suponha que temos um aplicativo Node.Js muito simples:

  • o arquivo index.js inicia um servidor HTTP simples que responde com uma string a cada requisição recebida:
  • o arquivo package.json define as dependências, das quais usamos apenas o expressjs para rodar o servidor HTTP:

$ cat index.js
var express = require('express');
var util    = require('util');
var app = express();
app.get('/', function(req, res) {
  res.setHeader('Content-Type', 'text/plain');
  res.end(util.format("%s - %s", new Date(), 'Recebido Request'));
});
app.listen(process.env.PORT || 80);

$ cat package.json
    {
      "name": "testnode",
      "version": "0.0.1",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "dependencies": {
        "express": "^4.14.0"
      }
    }

O Dockerfile para construir a imagem é assim:

FROM node:13-alpine
COPY package.json /app/package.json
RUN cd /app && npm install
COPY . /app/
WORKDIR /app
EXPOSE 80
CMD ["npm", "start"]

Vamos construir a imagem de maneira convencional, sem usar o BuildKit:

$ docker build -t app:1.0 .

Se verificarmos o uso de espaço em disco, veremos que o espaço é ocupado apenas pela imagem base (node:13-alpine) e pela imagem final (app:1.0):

TIPO            TOTAL       ATIVO      TAMANHO      RECUPERÁVEL
Imagens         2           0          109.3MB     109.3MB (100%)
Contêineres     0           0          0B          0B
Volumes Locais  0           0          0B          0B
Cache de Build  0           0          0B          0B

Agora, vamos construir a segunda versão do nosso aplicativo, já utilizando o BuildKit. Para isso, precisamos apenas definir a variável DOCKER_BUILDKIT como 1:

$ DOCKER_BUILDKIT=1 docker build -t app:2.0 .

Se agora verificarmos o uso do disco, veremos que o cache de build (build-cache) está participando:

$ docker system df
TIPO           TOTAL      ATIVO     TAMANHO    RECUPERÁVEL
Imagens       2          0          109.3MB    109.3MB (100%)
Contêineres   0          0          0B         0B
Volumes Locais 0          0          0B         0B
Cache de Compilação 11         0          8.949kB    8.949kB

Para limpá-lo, usaremos o seguinte comando:

$ docker builder prune
AVISO! Isso removerá todo o cache de compilação pendente.
Você tem certeza de que deseja continuar? [y/N] y
Objetos de cache de compilação excluídos:
rffq7b06h9t09xe584rn4f91e
ztexgsz949ci8mx8p5tzgdzhe
3z9jeoqbbmj3eftltawvkiayi

Espaço total recuperado: 8.949kB

Limpar tudo!

Então, revisamos a limpeza do espaço em disco ocupado por contêineres, imagens e volumes. Para isso, usamos a subcomando prune. Mas ele pode ser usado no nível do sistema do docker e limpará tudo o que conseguir:

$ docker system prune
AVISO! Isso removerá:
  - todos os contêineres parados
  - todas as redes não utilizadas por pelo menos um contêiner
  - todas as imagens pendentes
  - todo o cache de compilação pendente

Você tem certeza de que deseja continuar? [y/N]

Se você, por algum motivo, está economizando espaço em disco em uma máquina com Docker, é bom tornar o uso periódico desse comando um hábito.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster