
Ahoj, Habr! Predstavujem vám preklad článku autora .
Dnes si povieme, ako Docker využíva diskový priestor hostiteľskej mašiny, a tiež sa pozrieme na to, ako uvoľniť priestor od zbytočných obrazov a kontajnerov.

Celkové využitie
Docker je skvelá vec, dnes o tom sotva niekto pochybujem. Pred niekoľkými rokmi nás tento produkt oboznámil s úplne novým spôsobom výstavby, dodávania a prevádzkovania akéhokoľvek prostredia, pričom značné úspory zdrojov CPU a RAM sú nepopierateľné. Okrem toho (a pre niekoho to bude dokonca najdôležitejšie) Docker nám umožnil neuveriteľne zjednodušiť a zjednotiť správu životného cyklu používaných pracovných prostredí.
Ale za všetky tieto výhody moderného života sa musí platiť. Keď spúšťame kontajnery, sťahujeme alebo vytvárame vlastné obrazy, rozvíjame zložené ekosystémy, musíme za to zaplatiť. A platíme aj diskovým priestorom.
Ak ste sa nikdy nezamýšľali nad tým, koľko miesta skutočne zaberal Docker na vašej mašine, môžete byť nepríjemne prekvapení výstupom z tohto príkazu:
$ docker system df 
Tento príkaz zobrazuje využitie disku Dockera z rôznych aspektov:
- obrazy (images) – celková veľkosť obrazov, ktoré boli stiahnuté z úložísk obrazov a postavené vo vašej sústave;
- kontajnery (containers) – celkové množstvo diskového priestoru využívané spustenými kontajnermi (ide o celkový objem úrovní čítania-písania všetkých kontajnerov);
- miestne objemy (local volumes) – objem lokálnych úložísk pripojených k kontajnerom;
- cache zostavy (build cache) – dočasné súbory generované procesom zostavovania obrazov (pri použití nástroja BuildKit, dostupného od Docker verzie 18.09).
Vsadím sa, že už po tomto jednoduchom výpočte máte chuť vyčistiť disk od neporiadku a vrátiť si cenné gigabajty späť (pripomínam: zvlášť ak za tieto gigabajty každý mesiac platíte nájom).
Využitie disku kontajnermi
Pri každom vytvorení kontajnera na hostiteľskej mašine sa v adresári /var/lib/docker vytvorí niekoľko súborov a adresárov, medzi ktorými stojí za zmienku nasledovné:
- Adresár /var/lib/docker/containers/ID_kontejneru – pri použití štandardného ovládača logovania sa doň ukladajú protokoly udalostí vo formáte JSON. Príliš podrobné logy, ako aj logy, ktoré nikto nečíta a nezpracováva inými spôsobmi, často spôsobujú preplnenie diskov.
- Adresár /var/lib/docker/overlay2 – obsahuje vrstvy čítania-zápisu kontajnerov (overlay2 – preferovaný ovládač v väčšine distribúcií Linuxu). Ak kontajner ukladá dáta vo svojom súborovom systéme, budú umiestnené práve v tomto adresári.
Predstavme si systém, na ktorom je nainštalovaný úplne čistý Docker, ktorý sa nikdy nezapojil do spúšťania kontajnerov a súvisiacich obrazov. Jeho správa o využití diskového priestoru 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 0BSpustíme nejaký kontajner, napríklad NGINX:
$ docker container run --name www -d -p 8000:80 nginx:1.16Čo sa deje s diskom:
- obraz (images) zaberá 126 MB, to je ten NGINX, ktorý sme spustili v kontajneri;
- kontajnery (containers) 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 0BPodľa výstupu, ešte nemáme priestor, ktorý by sme mohli oslobodiť. Keďže 2 bajty sú úplne nezmyselné, predstavme si, že náš NGINX nečakane vytvoril 100 megabajtov dát a vytvoril vo vnútri seba 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]Opäť preskúmame využitie diskového priestoru na hostiteľovi. Uvidíme, že kontajner (containers) zaberá tam 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 0BMyslím, že váš zvedavý mozog už kladie otázku, kde je náš súbor test.img. Poďme ho hľadať:
$ 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.imgBez toho, aby sme sa púšťali do podrobností, môžeme poznamenať, že súbor test.img sa pohodlne nachádza na úrovni zápisu a čítania spravovanej ovládačom overlay2. Ak však zastavíme náš kontajner, hostiteľ nám naznačí, že tento priestor je vlastne možné 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 0BAko to môžeme urobiť? Odstránením kontajnera, ktoré povedie k vyčisteniu príslušného priestoru na úrovni zápisu a čítania.
Pomocou nasledujúcej príkazu môžete odstrániť všetky nainštalované kontajnery jedným krokom a vyčistiť svoj disk od všetkých nimi vytvorených súborov na úrovni zápisu a čítania:
$ docker container prune
WARNING! Toto odstráni všetky zastavené kontajnery.
Ste si istí, že chcete pokračovať? [y/N] y
Odstránené kontajnery:
5e7f8e5097ace9ef5518ebf0c6fc2062ff024efb495f11ccc89df21ec9b4dcc2
Celkový uvoľnený priestor: 104.9MBTakže sme uvoľnili 104.9 megabajtov odstránením kontajnera. Ale keďže už nepoužívame predtým stiahnutý obraz, ten sa tiež stáva 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 0BUpozornenie: pokiaľ je obraz použitý aspoň jedným kontajnerom, tento trik nebudete môcť použiť.
Podpríkaz prune, ktorý sme použili vyššie, účinkuje len na zastavených kontajneroch. 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)Poznámky na okraj: ak pri spustení kontajnera použijete parameter —rm, všetok diskový priestor, ktorý obsadil, bude pri jeho zastavení uvoľnený.
Používanie disku obrazmi
Pár rokov dozadu bola veľkosť obrazu niekoľkých stoviek megabajtov úplne normálna: obraz Ubuntu vážil 600 megabajtov a obraz Microsoft .Net niekoľko gigabajtov. V tých časoch stiahnutie jediného obrazu mohlo vážne narušiť váš voľný priestor na disku, aj keď ste zdieľali úrovne medzi obrazmi. Dnes – chvála veľkým – obrazy vážia omnoho menej, ale aj v tomto prípade môžete rýchlo zaplniť existujúce zdroje, ak neprijmete niektoré opatrenia.
Existuje niekoľko typov obrazov, ktoré nie sú priamo viditeľné pre koncového používateľa:
- medzivrstva obrazy, na základe ktorých sú vytvorené iné obrazy – nemôžu byť odstránené, ak používate kontajnery založené na týchto "iných" obrazoch;
- zanechané obrazy – to sú také medzivrstva obrazy, na ktoré sa neodkazuje žiadny z bežiacich kontajnerov – môžu byť odstránené.
- Pomocou nasledujúcej príkazovej línie môžete skontrolovať prítomnosť zanechaných obrazov vo vašom systéme:
$ docker image ls -f dangling=true
REPOSITORY TAG IMAGE ID CREATED SIZE
none none 21e658fe5351 pred 12 minútami 71.3MBMôžete ich odstrániť nasledujúcim spôsobom:
$ docker image rm $(docker image ls -f dangling=true -q)Môžeme tiež použiť subpríkaz prune:
$ docker image prune
UPOZORNENIE! Toto odstráni všetky zanechané obrazy.
Ste si istí, že chcete pokračovať? [y/N] y
Odstránené obrazy:
vymazané: sha256:143407a3cb7efa6e95761b8cd6cea25e3f41455be6d5e7cda
vymazané: sha256:738010bda9dd34896bac9bbc77b2d60addd7738ad1a95e5cc
vymazané: sha256:fa4f0194a1eb829523ecf3bad04b4a7bdce089c8361e2c347
vymazané: sha256:c5041938bcb46f78bf2f2a7f0a0df0eea74c4555097cc9197
vymazané: sha256:5945bb6e12888cf320828e0fd00728947104da82e3eb4452f
Celkový oslobodený priestor: 12.9kBAk by sme chceli odstrániť všetky obrazy (a nie iba zanechané) jedným príkazom, môžeme to urobiť takto:
$ docker image rm $(docker image ls -q)Používanie disku pomocou objemov
Objemy (volumes) sa používajú na ukladanie údajov mimo súborového systému kontajnera. Napríklad, ak chceme uchovať výsledky práce nejakého aplikácie, aby sme ich mohli použiť inak. Častým príkladom sú databázy.
Poďme spustiť kontajner MongoDB, pripojiť k nemu externý objem a obnoviť z neho zálohu databázy (tá bude dostupná 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 sa budú nachádzať na hostiteľskom počítači v adresári /var/lib/docker/volumes. Ale prečo nie na úrovni čítania/písania kontajnera? Pretože v Dockerfile obrazu MongoDB je adresár /data/db (v ktorom MongoDB predvolene ukladá svoje údaje) definovaný ako objem (volume).

Poznámky na okraji: mnohé obrazy, pri ktorých práci by mali byť vytvorené údaje, používajú objemy (volumes) na uchovávanie týchto údajov.
Keď sa nabažíme s MongoDB a zastavíme (možno aj odstránime) kontajner, objem nebude odstránený. Bude aj naďalej zaberáť naše cenné diskové miesto, pokiaľ ho výslovne neodstránime takýmto príkazom:
$ docker volume rm $(docker volume ls -q)Alebo môžeme použiť už známy subpríkaz prune:
$ docker volume prune
UPOZORNENIE! Toto odstráni všetky miestne objemy, ktoré nie sú používané aspoň jedným kontajnerom.
Ste si istý, že chcete pokračovať? [y/N] y
Odstránené objemy:
d50b6402eb75d09ec17a5f57df4ed7b520c448429f70725fc5707334e5ded4d5
8f7a16e1cf117cdfddb6a38d1f4f02b18d21a485b49037e2670753fa34d115fc
599c3dd48d529b2e105eec38537cd16dac1ae6f899a123e2a62ffac6168b2f5f
...
732e610e435c24f6acae827cd340a60ce4132387cfc512452994bc0728dd66df
9a3f39cc8bd0f9ce54dea3421193f752bda4b8846841b6d36f8ee24358a85bae
045a9b534259ec6c0318cb162b7b4fca75b553d4e86fc93faafd0e7c77c79799
c6283fe9f8d2ca105d30ecaad31868410e809aba0909b3e60d68a26e92a094da
Celkový uvoľnený priestor: 25.82GB
luc@saturn:~$Použitie disku pre cache zostavenia obrazov
V Docker 18.09 prešiel proces vytvárania obrazov niektorými zmenami vďaka nástroju BuildKit. S pomocou tohto nástroja sa zvyšuje rýchlosť procesu, optimalizuje sa správa úložiska a bezpečnosti. Tu sa nebudeme zaoberať všetkými detailmi tohto skvelého nástroja, ale zameriame sa na to, ako ovplyvňuje otázky používania diskového priestoru.
Predpokladajme, že máme úplne jednoduchú aplikáciu Node.Js:
- súbor index.js spúšťa jednoduchý HTTP server, ktorý reaguje reťazcom na každý prijatý požiadavok:
- súbor package.json definuje závislosti, z ktorých sa používa iba expressjs na spustenie HTTP servera:
$ 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(), 'Dostali sme požiadavku'));
});
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 zostavenie 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"]Poďme zostaviť obraz bežným spôsobom, bez použitia BuildKit:
$ docker build -t app:1.0 .Ak skontrolujeme použitie diskového priestoru, uvidíme, že miesto zaberajú iba základný obraz (node:13-alpine) a konečný obraz (app:1.0):
TYPU CELKOVO AKTÍVNE VEĽKOSŤ MOŽNÉ UVOĽNIŤ
Obrázky 2 0 109.3MB 109.3MB (100%)
Kontajnery 0 0 0B 0B
Miestne objemy 0 0 0B 0B
Cache zostavenia 0 0 0B 0BPoďme zostaviť druhú verziu našej aplikácie, už s použitím BuildKit. Na to stačí nastaviť premennú DOCKER_BUILDKIT na hodnotu 1:
$ DOCKER_BUILDKIT=1 docker build -t app:2.0 .Ak teraz skontrolujeme využitie disku, uvidíme, že teraz je zapojená cache zostavenia (build-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.949kBNa jeho vyčistenie použijeme 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.949kBVyčistiť všetko!
Takže sme sa pozreli na čistenie diskového priestoru zaplneného kontajnermi, obrázkami a objemami. V tomto nám pomáha subpríkaz prune. Môže sa však používať aj na systémovej úrovni docker a vyčistí všetko, čo len môže:
$ 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 diskový priestor na stroji s Dockerom, periodické spúšťanie tohto príkazu by sa malo stať vaším zvykom.
Zdroj: habr.com
