
Salut, Habr! Vă prezint traducerea articolului autor .
Astăzi vom discuta despre cum Docker folosește spațiul pe disc al mașinii gazdă și cum putem elibera acel spațiu de resturile imaginilor și containerelor neutilizate.

Consum total
Docker este o unealtă genială, cred că astăzi puțini contestă acest lucru. Cu doar câțiva ani în urmă, acest produs ne-a oferit o modalitate complet nouă de a construi, livra și rula orice mediu, economisind semnificativ resursele CPU și RAM. În plus (iar pentru unii poate fi chiar cel mai important), Docker ne-a permis să simplificăm și să unificăm incredibil gestionarea ciclului de viață al mediilor de lucru utilizate.
Cu toate acestea, pentru toate aceste avantaje ale vieții moderne trebuie să plătim. Atunci când lansăm containere, descărcăm sau creăm propriile imagini, desfășurăm ecosisteme complexe, plătim. Și plătim, printre altele, în spațiu pe disc.
Dacă nu v-ați gândit niciodată la cât de mult loc este de fapt ocupat pe mașina dumneavoastră de Docker, s-ar putea să fiți neplăcut surprinși de rezultatul acestei comenzi:
$ docker system df 
Aici este afișat utilizarea discului de către Docker din diferite perspective:
- imagini (images) – dimensiunea totală a imaginilor care au fost descărcate din depozitele de imagini și construite în sistemul dumneavoastră;
- containere (containers) – volumul total de spațiu pe disc utilizat de containerele active (se referă la volumul total al straturilor de citire-scriere ale tuturor containerele);
- volume locale (local volumes) – volumul stocărilor locale montate pe containere;
- cache de construire (build cache) – fișiere temporare generate de procesul de construire a imaginilor (atunci când se utilizează instrumentul BuildKit, disponibil începând cu versiunea 18.09 a Docker).
Sunt sigur că deja după această simplă enumerare doriți cu ardoare să curățați discul de murdărie și să aduceți la viață gigabite prețioase (mențiune: mai ales dacă pentru aceste gigabite plătiți o chirie pe lună).
Utilizarea discului de către containere
Fiecare dată când creați un container pe mașina gazdă, în directorul /var/lib/docker sunt create mai multe fișiere și directoare, dintre care merită menționate următoarele:
- Catalogul /var/lib/docker/containers/ID_containerului – când se utilizează driverul standard de înregistrare, jurnalele de evenimente în format JSON sunt salvate aici. Jurnalele prea detaliate, precum și jurnalele care nu sunt citite și nu sunt procesate în alte moduri, devin adesea cauza umplerii discurilor.
- Catalogul /var/lib/docker/overlay2 – conține straturi de citire-scriere ale containerelor (overlay2 – driverul preferat în majoritatea distribuțiilor Linux). Dacă un container salvează date în sistemul său de fișiere, atunci acestea vor fi plasate în acest director.
Să ne imaginăm un sistem pe care este instalat un Docker curat, care nu a fost niciodată implicat în rularea containerelor și construirea imaginilor. Raportul său privind utilizarea spațiului pe disc va arăta astfel:
$ docker system df
TIP TOTAL ACTIV DIMENSIUNE RECUPERABIL
Imagini 0 0 0B 0B
Contenere 0 0 0B 0B
Volume locale 0 0 0B 0B
Cache de construcție 0 0 0B 0BSă rulăm un container, de exemplu, NGINX:
$ docker container run --name www -d -p 8000:80 nginx:1.16Ce se întâmplă cu discul:
- imaginile (images) ocupă 126 MB, acesta fiind NGINX-ul pe care l-am pornit în container;
- containerele (containers) ocupă un umil 2 biți.
$ docker system df
TIP TOTAL ACTIV DIMENSIUNE RECUPERABIL
Imagini 1 1 126M 0B (0%)
Contenere 1 1 2B 0B (0%)
Volume locale 0 0 0B 0B
Cache de construcție 0 0 0B 0BDin rezultatul afișat, nu avem încă spațiu pe care să îl putem recupera. Deoarece 2 biți sunt complet nesemnificativi, să ne imaginăm că NGINX-ul nostru a scris în mod neașteptat 100 MB de date și a creat în interiorul său un fișier test.img de exact această dimensiune.
$ docker exec -ti www
dd if=/dev/zero of=test.img bs=1024 count=0 seek=$[1024*100]Să cercetăm din nou utilizarea spațiului pe disc pe gazdă. Vom observa că containerul (containers) ocupă acum 100 MB.
$ docker system df
TIP TOTAL ACTIV DIMENSIUNE RECUPERABIL
Imagini 1 1 126M 0B (0%)
Contenere 1 1 104.9MB 0B (0%)
Volume locale 0 0 0B 0B
Cache de construcție 0 0 0B 0BCred că mintea dumneavoastră curioasă se întreabă deja unde se află fișierul nostru test.img. Să-l căutăm:
$ 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.imgFără a intra în detalii, se poate menționa că fișierul test.img este convenabil plasat în zona de citire-scriere gestionată de driverul overlay2. Dacă vom opri containerul nostru, gazda ne va sugera că acest loc poate fi, de fapt, eliberat:
# 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 0BCum putem face acest lucru? Prin ștergerea containerului, care va duce la curățarea corespunzătoarei zone de citire-scriere.
Cu ajutorul următoarei comenzi, puteți șterge toate containerele instalate dintr-o dată și curățați discul de toate fișierele create de acestea în zona de citire-scriere:
$ docker container prune
WARNING! Aceasta va șterge toate containerele oprite.
Sunteți sigur că doriți să continuați? [y/N] y
Containere șterse:
5e7f8e5097ace9ef5518ebf0c6fc2062ff024efb495f11ccc89df21ec9b4dcc2
Spațiu total recuperat: 104.9MBAșadar, am eliberat 104,9 Megabyți prin ștergerea containerului. Dar, deoarece nu mai folosim imaginea descărcată anterior, aceasta devine de asemenea un candidat pentru ștergere și pentru eliberarea resurselor noastre:
$ docker system df
TIP TOTAL ACTIV DIMENSIUNE RECUPERABIL
Imagini 1 0 126M 126M (100%)
Containere 0 0 0B 0B
Volume locale 0 0 0B 0B
Cache de construire 0 0 0B 0BAtenție: până când imaginea este utilizată de cel puțin un container, nu veți putea folosi acest truc.
Subcomanda prune, pe care am folosit-o mai sus, are efect doar asupra containerelor oprite. Dacă dorim să ștergem nu doar containerele oprite, ci și pe cele care sunt în execuție, trebuie să folosim una dintre aceste comenzi:
# Historical command
$ docker rm -f $(docker ps –aq)
# More recent command
$ docker container rm -f $(docker container ls -aq)Note pe margine: dacă la lansarea containerului se folosește parametrul —rm, la oprirea sa va fi eliberat tot spațiul pe disc pe care l-a ocupat.
Utilizarea discului de către imagini
Acum câțiva ani, dimensiunea unei imagini de câteva sute de megabytes era complet normală: imaginea Ubuntu cântărea 600 Megabytes, iar imaginea Microsoft .Net câteva Gigabytes. În acele vremuri, descărcarea unei singure imagini putea provoca daune semnificative spațiului liber de pe disc, chiar și atunci când partajați nivelurile între imagini. Astăzi – laudă marilor – imaginile cântăresc mult mai puțin, dar chiar și așa, resursele existente pot fi rapid umplute, dacă nu se iau anumite măsuri de precauție.
Există mai multe tipuri de imagini, care nu sunt vizibile direct utilizatorului final:
- Imaginile intermediare, pe baza cărora sunt create alte imagini - nu pot fi șterse dacă utilizați containere bazate pe aceste 'alte' imagini;
- Imaginile suspendate - sunt acele imagini intermediare la care nu se referă niciunul dintre containerele active - acestea pot fi șterse.
- Cu ajutorul următoarei comenzi puteți verifica dacă există imagini suspendate în sistemul dvs.:
$ docker image ls -f dangling=true
REPOSITORY TAG IMAGE ID CREATED SIZE
none none 21e658fe5351 acum 12 minute 71.3MBLe puteți șterge astfel:
$ docker image rm $(docker image ls -f dangling=true -q)Putem folosi și subcomanda prune:
$ docker image prune
ATENȚIE! Aceasta va șterge toate imaginile suspendate.
Sunteți sigur că doriți să continuați? [y/N] y
Imagini șterse:
șters: sha256:143407a3cb7efa6e95761b8cd6cea25e3f41455be6d5e7cda
șters: sha256:738010bda9dd34896bac9bbc77b2d60addd7738ad1a95e5cc
șters: sha256:fa4f0194a1eb829523ecf3bad04b4a7bdce089c8361e2c347
șters: sha256:c5041938bcb46f78bf2f2a7f0a0df0eea74c4555097cc9197
șters: sha256:5945bb6e12888cf320828e0fd00728947104da82e3eb4452f
Spațiu total recuperat: 12.9kBDacă dorim să ștergem toate imaginile (nu doar imaginile suspendate) cu o comandă, putem face astfel:
$ docker image rm $(docker image ls -q)Utilizarea discului cu volume
Volumele sunt utilizate pentru a stoca date dincolo de sistemul de fișiere al containerului. De exemplu, dacă dorim să păstrăm rezultatele unei aplicații pentru a le folosi ulterior. Un exemplu comun sunt bazele de date.
Să rulăm un container MongoDB, să-i montăm un volum extern și să restaurăm un backup al bazei de date (disponibil în fișierul 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
--jsonArrayDatele vor fi pe mașina gazdă în directorul /var/lib/docker/volumes. Dar de ce nu la nivel de citire-scriere al containerului? Pentru că în Dockerfile-ul imaginii MongoDB, directorul /data/db (unde MongoDB își stochează datele în mod implicit) este definit ca volum.

Notație: multe imagini care generează date utilizează volume pentru a păstra aceste date.
Când ne-am jucat cu MongoDB și oprim (sau poate chiar ștergem) containerul, volumului nu îi va fi atribuită ștergerea. Acesta va continua să ocupe spațiul de disc valoros până când nu îl vom șterge explicit cu comanda:
$ docker volume rm $(docker volume ls -q)Sau putem folosi subcomanda prune pe care o știm deja:
$ docker volume prune
AVERTISMENT! Acest lucru va elimina toate volumele locale care nu sunt utilizate de cel puțin un container.
Ești sigur că vrei să continui? [y/N] y
Volume șterse:
d50b6402eb75d09ec17a5f57df4ed7b520c448429f70725fc5707334e5ded4d5
8f7a16e1cf117cdfddb6a38d1f4f02b18d21a485b49037e2670753fa34d115fc
599c3dd48d529b2e105eec38537cd16dac1ae6f899a123e2a62ffac6168b2f5f
...
732e610e435c24f6acae827cd340a60ce4132387cfc512452994bc0728dd66df
9a3f39cc8bd0f9ce54dea3421193f752bda4b8846841b6d36f8ee24358a85bae
045a9b534259ec6c0318cb162b7b4fca75b553d4e86fc93faafd0e7c77c79799
c6283fe9f8d2ca105d30ecaad31868410e809aba0909b3e60d68a26e92a094da
Spațiul total recuperat: 25.82GB
luc@saturn:~$Utilizarea discului pentru cache-ul construcțiilor de imagini
În Docker 18.09, procesul de creare a imaginilor a suferit unele modificări datorită instrumentului BuildKit. Acest instrument crește viteza procesului, optimizează gestionarea stocării și a securității. Nu vom analiza toate detaliile acestui instrument minunat, ci ne vom concentra asupra modului în care acesta afectează utilizarea spațiului pe disc.
Să presupunem că avem o aplicație Node.Js foarte simplă:
- fișierul index.js rulează un server HTTP simplu care răspunde cu un mesaj la fiecare cerere primită:
- fișierul package.json definește dependențele, dintre care se folosește doar expressjs pentru a rula serverul 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(), 'Am primit cererea'));
});
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 pentru construirea imaginii arată așa:
FROM node:13-alpine
COPY package.json \/app\/package.json
RUN cd \/app && npm install
COPY . \/app\/\nWORKDIR \/app
EXPOSE 80
CMD ["npm", "start"]Să construim imaginea în mod obișnuit, fără a folosi BuildKit:
$ docker build -t app:1.0 .Dacă verificăm utilizarea spațiului pe disc, vom observa că locul este ocupat doar de imaginea de bază (node:13-alpine) și de imaginea finală (app:1.0):
TIP TOTAL ACTIV DIMENSIUNE RECUPERABIL
Imagini 2 0 109.3MB 109.3MB (100%)
Containere 0 0 0B 0B
Volume locale 0 0 0B 0B
Cache de construcție 0 0 0B 0BSă construim a doua versiune a aplicației noastre, acum folosind BuildKit. Pentru aceasta, trebuie doar să setăm variabila DOCKER_BUILDKIT la 1:
$ DOCKER_BUILDKIT=1 docker build -t app:2.0 .Dacă acum verificăm utilizarea discului, vom observa că acum există și cache-ul construcției (build-cache):
$ docker system df
TIP TOTAL ACTIVE SIZE RECLAIMABLE
Imagini 2 0 109.3MB 109.3MB (100%)
Containeere 0 0 0B 0B
Volume locale 0 0 0B 0B
Cache de build 11 0 8.949kB 8.949kBPentru a-l curăți, folosim următoarea comandă:
$ docker builder prune
AVERTISMENT! Aceasta va elimina toate cache-urile de build care nu mai sunt utilizate.
Ești sigur că vrei să continui? [y/N] y
Obiecte de cache de build șterse:
rffq7b06h9t09xe584rn4f91e
ztexgsz949ci8mx8p5tzgdzhe
3z9jeoqbbmj3eftltawvkiayi
Spațiu total recuperat: 8.949kBCurăță tot!
Așadar, am analizat curățarea spațiului pe disc ocupat de containere, imagini și volume. În acest scop, ne ajută subcomanda prune. Dar aceasta poate fi utilizată și la nivelul sistemului docker, curățând tot ce poate:
$ docker system prune
AVERTISMENT! Aceasta va elimina:
- toate containerele oprite
- toate rețelele care nu sunt folosite de cel puțin un container
- toate imaginile neutilizate
- toate cache-urile de build neutilizate
Ești sigur că vrei să continui? [y/N]Dacă din anumite motive economisești spațiu pe disc pe o mașină cu Docker, atunci ar trebui să-ți faci un obicei din a rula periodic această comandă.
Sursa: habr.com
