
Ahoj, Habr! Představuji vám překlad článku autora .
Dnes si promluvíme o tom, jak Docker využívá diskový prostor hostitelské mašiny, a také se podíváme na to, jak uvolnit prostor od zbytků nepoužívaných obrazů a kontejnerů.

Celková spotřeba
Docker je skvělá věc, dnes asi málokdo o tom pochybuje. Před několika lety tento produkt přinesl zcela nový způsob, jak budovat, dodávat a spouštět jakékoli prostředí a umožnil výrazně šetřit procesorové a paměťové zdroje. Kromě toho (což může být pro někoho nejdůležitější) nám Docker výrazně zjednodušil a sjednotil správu životního cyklu používaných pracovních prostředí.
Nicméně, za všechny tyto výhody moderního života musíme platit. Když spouštíme kontejnery, stahujeme nebo vytváříme vlastní obrazy, nasazujeme složité ekosystémy, musíme platit. A platíme také diskovým prostorem.
Pokud jste se nikdy nezamysleli nad tím, kolik místa je skutečně obsazeno na vaší mašině Dockerem, můžete být nepříjemně překvapeni výstupem tohoto příkazu:
$ docker system df 
Zde je zobrazeno využití disku Dockerem v různých ohledech:
- obrazy (images) – celková velikost obrazů, které byly staženy z úložišť obrazů a vytvořeny ve vaší systému;
- kontejnery (containers) – celkový objem diskového prostoru využívaného spuštěnými kontejnery (jde o celkový objem vrstvových čtení a zápisů všech kontejnerů);
- lokální objemy (local volumes) – objem místních úložišť, které jsou připojeny k kontejnerům;
- mezipaměť sestavení (build cache) – dočasné soubory generované procesem sestavování obrazů (při použití nástroje BuildKit, dostupného od Docker verze 18.09).
Sázím se, že už po tomto jednoduchém výčtu toužíte vyčistit disk od nepořádku a vrátit k životu cenné gigabajty (pozn. překl. zejména pokud za tyto gigabajty každý měsíc platíte nájem).
Využití disku kontejnery
Při každém vytvoření kontejneru na hostitelské mašině se v adresáři /var/lib/docker vytváří několik souborů a adresářů, mezi nimiž stojí za zmínku následující:
- Katalog /var/lib/docker/containers/ID_kontejneru – při použití standardního ovladače pro logování se sem ukládají zápisy událostí ve formátu JSON. Příliš podrobné logy, a také logy, které nikdo nečte a nezpracovává jiným způsobem, často způsobují přetížení disků.
- Katalog /var/lib/docker/overlay2 – obsahuje vrstvy čtení-zápisu kontejnerů (overlay2 – preferovaný ovladač ve většině distribucí Linuxu). Pokud kontejner ukládá data do svého souborového systému, umístí se právě do tohoto katalogu.
Představme si systém, na kterém je nainstalován zcela čistý Docker, který nikdy nebyl použit k spuštění kontejnerů a sestavování obrazů. Jeho zpráva o využití diskového prostoru by vypadala 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 0BSpusťme nějaký kontejner, například NGINX:
$ docker container run --name www -d -p 8000:80 nginx:1.16Co se stane s diskem:
- obrázky (images) zabírají 126 MB, je to ten NGINX, který jsme spustili v kontejneru;
- kontejner (containers) zabírá směšné 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 0BPodle výstupu, zatím nemáme žádný prostor, který bychom mohli uvolnit. Protože 2 bajty jsou naprosto směšné, představme si, že náš NGINX nečekaně zapsal někam 100 megabajtů dat a vytvořil uvnitř sebe soubor test.img o této velikosti.
$ docker exec -ti www
dd if=/dev/zero of=test.img bs=1024 count=0 seek=$[1024*100]Opět prozkoumáme využití diskového prostoru na hostiteli. Uvidíme, že kontejner (containers) zabírá tam 100 megabajtů.
$ 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áš zvídavý mozek už si klade otázku, kde se našel náš soubor test.img. Pojďme ho hledat:
$ 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 podrobností lze poznamenat, že soubor test.img se pohodlně umístil na úrovni pro čtení a zápis, kterou spravuje ovladač overlay2. Pokud však zastavíme náš kontejner, hostitel nám naznačí, že tento prostor lze v zásadě uvolnit:
# 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 0BJak to můžeme udělat? Smazáním kontejneru, což povede k vyčištění odpovídajícího prostoru na úrovni pro čtení a zápis.
Pomocí následujícího příkazu můžete odstranit všechny nainstalované kontejnery najednou a vyčistit váš disk od všech souborů, které vytvořily na úrovni pro čtení a zápis:
$ docker container prune
WARNING! Toto odstraní všechny zastavené kontejnery.
Jste si jisti, že chcete pokračovat? [y/N] y
Odstraněné kontejnery:
5e7f8e5097ace9ef5518ebf0c6fc2062ff024efb495f11ccc89df21ec9b4dcc2
Celkový uvolněný prostor: 104.9MBTakže jsme uvolnili 104,9 megabajtů odstraněním kontejneru. Ale protože již nepoužíváme stažený obraz, také se stává kandidátem na odstranění a uvolnění našich zdrojů:
$ 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 0BPozor: dokud je obraz používán alespoň jedním kontejnerem, nebudete moci použít tento trik.
Podpříkaz prune, který jsme použili výše, má efekt pouze na zastavené kontejnery. Pokud chceme odstranit nejen zastavené, ale i běžící kontejnery, měli bychom použít některý z těchto příkazů:
# Historical command
$ docker rm -f $(docker ps –aq)
# More recent command
$ docker container rm -f $(docker container ls -aq)Poznámky na okraj: pokud při spuštění kontejneru použijete volbu —rm, uvolní se veškerý diskový prostor, který zabíralo po jeho zastavení.
Použití disku obrazy
Před několika lety byla velikost obrazu o několik stovek megabajtů naprosto normální: obraz Ubuntu vážil 600 megabajtů, zatímco obraz Microsoft .Net vážil několik gigabajtů. V těch starých časech mohl stáhnout pouze jeden obraz způsobit velkou škodu vašemu volnému prostoru na disku, i když jste sdíleli úrovně mezi obrazy. Dnes – díky velkým – obrazy váží mnohem méně, ale i tak může rychle zaplnit dostupné zdroje, pokud se nepřijmou určitá opatření.
Existuje několik typů obrazů, které nejsou přímo viditelné pro koncového uživatele:
- intermediární obrazy, na jejichž základě jsou sestaveny další obrazy – nelze je odstranit, pokud používáte kontejnery založené na těchto "dalších" obrazech;
- zavěšené obrazy – to jsou takové intermediární obrazy, na které se nevztahuje žádný spuštěný kontejner – lze je odstranit.
- Pomocí následujícího příkazu můžete zkontrolovat, zda ve vaší soustavě existují zavěšené obrazy:
$ docker image ls -f dangling=true
REPOSITORY TAG IMAGE ID CREATED SIZE
none none 21e658fe5351 před 12 minutami 71.3MBMůžete je odstranit následujícím způsobem:
$ docker image rm $(docker image ls -f dangling=true -q)Můžeme také použít podpříkaz prune:
$ docker image prune
WARNING! Tímto se odstraní všechny zavěšené obrazy.
Opravdu chcete pokračovat? [y/N] y
Odstraněné obrazy:
deleted: sha256:143407a3cb7efa6e95761b8cd6cea25e3f41455be6d5e7cda
deleted: sha256:738010bda9dd34896bac9bbc77b2d60addd7738ad1a95e5cc
deleted: sha256:fa4f0194a1eb829523ecf3bad04b4a7bdce089c8361e2c347
deleted: sha256:c5041938bcb46f78bf2f2a7f0a0df0eea74c4555097cc9197
deleted: sha256:5945bb6e12888cf320828e0fd00728947104da82e3eb4452f
Celkově uvolněný prostor: 12.9kBPokud bychom chtěli odstranit všechny obrazy (a nejen zavěšené) jedním příkazem, můžeme to provést takto:
$ docker image rm $(docker image ls -q)Používání disku pomocí objemů
Objemy (volumes) se používají pro ukládání dat mimo souborový systém kontejneru. Například pokud chceme uchovat výsledky práce nějaké aplikace, abychom je mohli využít jinde. Častým příkladem jsou databáze.
Spusťme kontejner MongoDB, připojme k němu externí objem, a obnovme z něj zálohu databáze (máme ji k dispozici v souboru 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
--jsonArrayData budou umístěna na hostitelské stroji v adresáři /var/lib/docker/volumes. Ale proč ne na úrovni čtení-zápisu kontejneru? Protože v Dockerfile obrazu MongoDB je adresář /data/db (ve kterém MongoDB ve výchozím nastavení ukládá svá data) definován jako objem (volume).

Poznámky na okraji: mnohé obrazy, které při své činnosti vytvářejí data, používají objemy (volumes) k uchování těchto dat.
Když si s MongoDB pohráme a zastavíme (nebo dokonce odstraníme) kontejner, objem nebude odstraněn. Bude i nadále zabírat náš cenný diskový prostor, dokud jej výslovně neodstraníme tímto příkazem:
$ docker volume rm $(docker volume ls -q)Nebo můžeme použít už známý nám podpříkaz prune:
$ docker volume prune
UPOZORNĚNÍ! Toto odstraní všechny místní svazky, které nejsou používány alespoň jedním kontejnerem.
Opravdu chcete pokračovat? [y/N] y
Odstraněné svazky:
d50b6402eb75d09ec17a5f57df4ed7b520c448429f70725fc5707334e5ded4d5
8f7a16e1cf117cdfddb6a38d1f4f02b18d21a485b49037e2670753fa34d115fc
599c3dd48d529b2e105eec38537cd16dac1ae6f899a123e2a62ffac6168b2f5f
...
732e610e435c24f6acae827cd340a60ce4132387cfc512452994bc0728dd66df
9a3f39cc8bd0f9ce54dea3421193f752bda4b8846841b6d36f8ee24358a85bae
045a9b534259ec6c0318cb162b7b4fca75b553d4e86fc93faafd0e7c77c79799
c6283fe9f8d2ca105d30ecaad31868410e809aba0909b3e60d68a26e92a094da
Celkově získaný prostor: 25.82GB
luc@saturn:~$Využití disku pro cache sestavení obrazů
Ve Dockeru 18.09 došlo k některým změnám v procesu vytváření obrazů díky nástroji BuildKit. Tento nástroj zrychluje proces, optimalizuje správu úložiště a zabezpečení. Zde nebudeme zkoumat všechny podrobnosti tohoto skvělého nástroje, pouze se zastavíme u toho, jak ovlivňuje využívání diskového prostoru.
Předpokládejme, že máme velmi jednoduchou aplikaci Node.Js:
- soubor index.js spouští jednoduchý HTTP server, který na každý přijatý požadavek odpovídá řetězcem:
- soubor package.json určuje závislosti, přičemž pro spuštění HTTP serveru se používá pouze expressjs:
$ 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 pro sestavení obrazu vypadá takto:
FROM node:13-alpine
COPY package.json \/app\/package.json
RUN cd \/app && npm install
COPY . \/app\/\nWORKDIR \/app
EXPOSE 80
CMD ["npm", "start"]Pojďme sestavit obraz obvyklým způsobem, bez použití BuildKit:
$ docker build -t app:1.0 .Pokud zkontrolujeme využití diskového prostoru, uvidíme, že místo zabírá pouze základní obraz (node:13-alpine) a konečný obraz (app:1.0):
TYPE CELKEM AKTIVNÍ VELIKOST MOŽNÉ ZÍSKAT
Obrázky 2 0 109.3MB 109.3MB (100%)
Kontejnery 0 0 0B 0B
Místní svazky 0 0 0B 0B
Cache sestavení 0 0 0B 0BPojďme sestavit druhou verzi naší aplikace, již s použitím BuildKit. K tomu potřebujeme pouze nastavit proměnnou DOCKER_BUILDKIT na hodnotu 1:
$ DOCKER_BUILDKIT=1 docker build -t app:2.0 .Pokud nyní zkontrolujeme využití disku, uvidíme, že nyní je zapojen cache sestavení (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.949kBK jeho vyčištění použijeme následující příkaz:
$ docker builder prune
WARNING! Tímto odstraníte všechny visící objekty z mezipaměti.
Jste si jisti, že chcete pokračovat? [y/N] y
Odstraněné objekty mezipaměti:
rffq7b06h9t09xe584rn4f91e
ztexgsz949ci8mx8p5tzgdzhe
3z9jeoqbbmj3eftltawvkiayi
Celkově získaný prostor: 8.949kBVyčistit vše!
Prozkoumali jsme vyčištění diskového prostoru obsazeného kontejnery, obrazy a svazky. K tomu nám pomáhá podřízený příkaz prune. Může se však používat i na systémové úrovni Dockeru a vyčistí vše, co může:
$ docker system prune
WARNING! Tímto odstraníte:
- všechny zastavené kontejnery
- všechny sítě, které nejsou používány alespoň jedním kontejnerem
- všechny visící obrazy
- všechny visící mezipaměti
Jste si jisti, že chcete pokračovat? [y/N]Pokud z nějakého důvodu šetříte diskový prostor na stroji s Dockerem, pak byste si měli zvyknout na pravidelné spouštění tohoto příkazu.
Zdroj: habr.com
