Tipy Docker: Vyčistite svoj počítač od odpadu

Tipy Docker: Vyčistite svoj počítač od odpadu

Čau Habr! Do pozornosti dávam preklad článku "Tipy Docker: Vyčistite svoj lokálny počítač" autora Luc Juggery.

Dnes si povieme, ako Docker využíva diskový priestor hostiteľského počítača a tiež prídeme na to, ako tento priestor oslobodiť od zvyškov nepoužitých obrázkov a kontajnerov.


Tipy Docker: Vyčistite svoj počítač od odpadu

Celková spotreba

Docker je super vec, o tom dnes pochybuje asi málokto. Len pred niekoľkými rokmi nám tento produkt poskytol úplne nový spôsob budovania, poskytovania a prevádzkovania akéhokoľvek prostredia, čo nám umožňuje výrazne šetriť zdroje CPU a RAM. Okrem toho (a pre niektorých to bude najdôležitejšia vec) nám Docker umožnil neuveriteľne zjednodušiť a zjednotiť správu životného cyklu našich produkčných prostredí.

Všetky tieto pôžitky moderného života však majú svoju cenu. Keď spúšťame kontajnery, sťahujeme alebo vytvárame vlastné obrázky a nasadzujeme komplexné ekosystémy, musíme platiť. A platíme okrem iného aj priestorom na disku.

Ak ste nikdy nepremýšľali o tom, koľko miesta Docker v skutočnosti zaberá na vašom počítači, možno budete nepríjemne prekvapení výstupom tohto príkazu:

$ docker system df

Tipy Docker: Vyčistite svoj počítač od odpadu

Toto ukazuje využitie disku Docker v rôznych kontextoch:

  • obrázky – celková veľkosť obrázkov, ktoré boli stiahnuté z archívov obrázkov a zabudované do vášho systému;
  • kontajnery – celkové množstvo diskového priestoru využívaného spustenými kontajnermi (čo znamená celkový objem vrstiev na čítanie a zápis všetkých kontajnerov);
  • miestne objemy – objem miestneho skladu namontovaného na kontajneroch;
  • build cache – dočasné súbory generované procesom vytvárania obrazu (pomocou nástroja BuildKit, dostupného od verzie Docker 18.09).

Stavím sa, že po tomto jednoduchom prevode túžite vyčistiť svoj disk od odpadu a priviesť späť k životu vzácne gigabajty (poznámka: najmä ak za tieto gigabajty platíte nájom každý mesiac).

Využitie disku kontajnermi

Zakaždým, keď vytvoríte kontajner na hostiteľskom počítači, v adresári /var/lib/docker sa vytvorí niekoľko súborov a adresárov, medzi ktorými stojí za zmienku nasledujúce:

  • Adresár /var/lib/docker/containers/container_ID – pri použití štandardného ovládača protokolovania sa tu ukladajú protokoly udalostí vo formáte JSON. Príliš podrobné protokoly, ako aj protokoly, ktoré nikto nečíta ani inak nespracováva, často spôsobujú zaplnenie diskov.
  • Adresár /var/lib/docker/overlay2 obsahuje vrstvy kontajnera na čítanie a zápis (overlay2 je preferovaný ovládač vo väčšine distribúcií Linuxu). Ak kontajner ukladá údaje vo svojom súborovom systéme, umiestnia sa do tohto adresára.

Predstavme si systém, na ktorom je nainštalovaný nedotknutý Docker, ktorý sa nikdy nepodieľal na spúšťaní kontajnerov alebo budovaní obrazov. Správa o využití miesta na disku bude vyzerať takto:

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         0          0          0B         0B
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Poďme spustiť nejaký kontajner, napríklad NGINX:

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

Čo sa stane s diskom:

  • obrázky zaberajú 126 MB, ide o rovnaký NGINX, ktorý sme spustili v kontajneri;
  • kontajnery zaberajú smiešne 2 bajty.

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          1          126M       0B (0%)
Containers     1          1          2B         0B (0%)
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Súdiac podľa záveru, zatiaľ nemáme priestor, ktorý by sme mohli uvoľniť. Keďže 2 bajty sú úplne frivolné, predstavme si, že náš NGINX niekde nečakane zapísal 100 megabajtov dát a vytvoril v sebe súbor test.img presne tejto veľkosti.

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

Pozrime sa znova na využitie miesta na disku na hostiteľovi. Uvidíme, že kontajner (kontajnery) tam zaberá 100 megabajtov.

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          1          126M       0B (0%)
Containers     1          1          104.9MB    0B (0%)
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Myslím, že váš zvedavý mozog sa už pýta, kde sa nachádza náš súbor test.img. Hľadajme to:

$ 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

Bez toho, aby sme zachádzali do podrobností, môžeme si všimnúť, že súbor test.img je pohodlne umiestnený na úrovni čítania a zápisu, riadený ovládačom overlay2. Ak zastavíme náš kontajner, hostiteľ nám povie, že tento priestor možno v zásade uvoľniť:

# 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

Ako to môžeme urobiť? Vymazaním kontajnera, čo bude znamenať vymazanie zodpovedajúceho priestoru na úrovni čítania a zápisu.

Pomocou nasledujúceho príkazu môžete jedným ťahom odstrániť všetky nainštalované kontajnery a vyčistiť disk od všetkých súborov na čítanie a zápis, ktoré vytvorili:

$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
5e7f8e5097ace9ef5518ebf0c6fc2062ff024efb495f11ccc89df21ec9b4dcc2

Total reclaimed space: 104.9MB

Vymazaním kontajnera sme teda uvoľnili 104,9 megabajtov. Ale keďže predtým stiahnutý obrázok už nepoužívame, stáva sa tiež kandidátom na odstránenie a uvoľnenie našich zdrojov:

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          0          126M       126M (100%)
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Poznámka: Pokiaľ obrázok používa aspoň jeden kontajner, tento trik nebudete môcť použiť.

Čiastkový príkaz prune, ktorý sme použili vyššie, má vplyv len na zastavené kontajnery. Ak chceme odstrániť nielen zastavené, ale aj spustené kontajnery, mali by sme použiť jeden z týchto príkazov:

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

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

Vedľajšie poznámky: ak použijete parameter -rm pri spúšťaní kontajnera, potom keď sa zastaví, uvoľní sa všetko miesto na disku, ktoré zaberal.

Používanie obrazov diskov

Pred niekoľkými rokmi bola veľkosť obrázka niekoľko stoviek megabajtov úplne normálna: obrázok Ubuntu vážil 600 megabajtov a obrázok Microsoft .Net vážil niekoľko gigabajtov. V tých chlpatých dňoch si sťahovanie len jedného obrázka mohlo vybrať veľkú daň na vašom voľnom mieste na disku, aj keď medzi obrázkami zdieľate úrovne. Dnes - chvála veľkej - obrázky vážia oveľa menej, ale aj tak môžete rýchlo zaplniť dostupné zdroje, ak neurobíte nejaké opatrenia.

Existuje niekoľko typov obrázkov, ktoré koncový používateľ priamo nevidí:

  • prechodné obrázky, na základe ktorých sa zhromažďujú ďalšie obrázky - nemožno ich odstrániť, ak používate kontajnery založené na týchto „iných“ obrázkoch;
  • visiace obrázky sú prechodné obrázky, na ktoré neodkazuje žiadny spustený kontajner – možno ich odstrániť.
  • Pomocou nasledujúceho príkazu môžete skontrolovať visiace obrázky vo vašom systéme:

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

Môžete ich odstrániť nasledujúcim spôsobom:

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

Môžeme použiť aj podpríkaz prune:

$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Deleted Images:
deleted: sha256:143407a3cb7efa6e95761b8cd6cea25e3f41455be6d5e7cda
deleted: sha256:738010bda9dd34896bac9bbc77b2d60addd7738ad1a95e5cc
deleted: sha256:fa4f0194a1eb829523ecf3bad04b4a7bdce089c8361e2c347
deleted: sha256:c5041938bcb46f78bf2f2a7f0a0df0eea74c4555097cc9197
deleted: sha256:5945bb6e12888cf320828e0fd00728947104da82e3eb4452f

Total reclaimed space: 12.9kB

Ak zrazu chceme jedným príkazom vymazať všetky obrázky úplne (a nielen visieť), potom môžeme urobiť toto:

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

Využitie disku podľa zväzkov

Zväzky sa používajú na ukladanie údajov mimo súborový systém kontajnera. Napríklad, ak chceme uložiť výsledky aplikácie, aby sme ich mohli použiť iným spôsobom. Bežným príkladom sú databázy.

Spustíme kontajner MongoDB, pripojíme externý zväzok ku kontajneru a obnovíme z neho zálohu databázy (máme ju k dispozícii v súbore 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

Údaje budú umiestnené na hostiteľskom počítači v adresári /var/lib/docker/volumes. Ale prečo nie na úrovni čítania a zápisu kontajnera? Pretože v Dockerfile obrazu MongoDB je adresár /data/db (kde MongoDB štandardne ukladá svoje dáta) definovaný ako zväzok.

Tipy Docker: Vyčistite svoj počítač od odpadu

Vedľajšia poznámka: veľa obrázkov, ktoré musia produkovať údaje, používa objemy na ukladanie týchto údajov.

Keď sa dostatočne pohráme s MongoDB a zastavíme (alebo možno aj vymažeme) kontajner, zväzok sa nevymaže. Bude naďalej zaberať naše vzácne miesto na disku, kým ho explicitne neodstránime príkazom, ako je tento:

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

Alebo môžeme použiť čiastkový príkaz prune, ktorý je nám už známy:

$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
d50b6402eb75d09ec17a5f57df4ed7b520c448429f70725fc5707334e5ded4d5
8f7a16e1cf117cdfddb6a38d1f4f02b18d21a485b49037e2670753fa34d115fc
599c3dd48d529b2e105eec38537cd16dac1ae6f899a123e2a62ffac6168b2f5f
...
732e610e435c24f6acae827cd340a60ce4132387cfc512452994bc0728dd66df
9a3f39cc8bd0f9ce54dea3421193f752bda4b8846841b6d36f8ee24358a85bae
045a9b534259ec6c0318cb162b7b4fca75b553d4e86fc93faafd0e7c77c79799
c6283fe9f8d2ca105d30ecaad31868410e809aba0909b3e60d68a26e92a094da

Total reclaimed space: 25.82GB
luc@saturn:~$

Použitie disku na vyrovnávaciu pamäť na vytváranie obrázkov

V Dockeri 18.09 prešiel proces vytvárania obrázkov niekoľkými zmenami vďaka nástroju BuildKit. Táto vec zvyšuje rýchlosť procesu a optimalizuje ukladanie dát a správu bezpečnosti. Tu nebudeme brať do úvahy všetky detaily tohto úžasného nástroja; zameriame sa len na to, ako rieši problémy s využitím miesta na disku.

Povedzme, že máme úplne jednoduchú aplikáciu Node.Js:

  • súbor index.js spúšťa jednoduchý HTTP server, ktorý odpovedá riadkom na každú prijatú požiadavku:
  • súbor package.json definuje závislosti, z ktorých iba expressjs sa používa na spustenie servera 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(), 'Got 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"
      }
    }

Dockerfile na vytvorenie obrazu vyzerá takto:

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

Vytvorme obrázok obvyklým spôsobom bez použitia BuildKit:

$ docker build -t app:1.0 .

Ak skontrolujeme využitie miesta na disku, môžeme vidieť, že miesto zaberá iba základný obrázok (node:13-alpine) a cieľový obrázok (app:1.0):

TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         2          0          109.3MB    109.3MB (100%)
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Poďme zostaviť druhú verziu našej aplikácie pomocou BuildKit. Aby sme to dosiahli, stačí nastaviť premennú DOCKER_BUILDKIT na 1:

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

Ak teraz skontrolujeme využitie disku, uvidíme, že je tam teraz zahrnutá vyrovnávacia pamäť zostavenia (buid-cache):

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         2          0          109.3MB    109.3MB (100%)
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    11         0          8.949kB    8.949kB

Ak ho chcete vymazať, použite nasledujúci príkaz:

$ docker builder prune
WARNING! This will remove all dangling build cache.
Are you sure you want to continue? [y/N] y
Deleted build cache objects:
rffq7b06h9t09xe584rn4f91e
ztexgsz949ci8mx8p5tzgdzhe
3z9jeoqbbmj3eftltawvkiayi

Total reclaimed space: 8.949kB

Zmazať všetko!

Pozreli sme sa teda na vyčistenie miesta na disku, ktoré zaberajú kontajnery, obrázky a zväzky. Pomáha nám v tom čiastkový príkaz prune. Môže sa však použiť aj na úrovni systému docker a vyčistí všetko, čo sa dá:

$ docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all dangling build cache

Are you sure you want to continue? [y/N]

Ak z nejakého dôvodu šetríte miesto na disku na počítači Docker, pravidelné spúšťanie tohto príkazu by sa malo stať zvykom.

Zdroj: hab.com

Pridať komentár