Docker Tipy: Vyčistěte svůj počítač od nevyžádaného odpadu

Docker Tipy: Vyčistěte svůj počítač od nevyžádaného odpadu

Čau Habr! Předkládám vaší pozornosti překlad článku "Tipy Docker: Vyčistěte místní počítač" autor Luc Juggery.

Dnes si povíme, jak Docker využívá diskový prostor hostitelského počítače, a také přijdeme na to, jak tento prostor uvolnit od zbytků nepoužitých obrázků a kontejnerů.


Docker Tipy: Vyčistěte svůj počítač od nevyžádaného odpadu

Celková spotřeba

Docker je super věc, o tom dnes pochybuje asi málokdo. Jen před několika lety nám tento produkt poskytl zcela nový způsob, jak budovat, dodávat a provozovat jakékoli prostředí, což nám umožňuje výrazně šetřit zdroje CPU a RAM. Kromě toho (a pro některé to bude to nejdůležitější) nám Docker umožnil neuvěřitelně zjednodušit a sjednotit správu životního cyklu našich produkčních prostředí.

Všechny tyto požitky moderního života však něco stojí. Když provozujeme kontejnery, stahujeme nebo vytváříme vlastní obrázky a nasazujeme složité ekosystémy, musíme platit. A platíme mimo jiné prostorem na disku.

Pokud jste nikdy nepřemýšleli o tom, kolik místa Docker ve skutečnosti zabírá na vašem počítači, můžete být nepříjemně překvapeni výstupem tohoto příkazu:

$ docker system df

Docker Tipy: Vyčistěte svůj počítač od nevyžádaného odpadu

To ukazuje využití disku Docker v různých kontextech:

  • obrázky – celková velikost obrázků, které byly staženy z úložišť obrázků a vytvořeny ve vašem systému;
  • kontejnery – celkové množství místa na disku využívané spuštěnými kontejnery (což znamená celkový objem vrstev pro čtení a zápis všech kontejnerů);
  • místní objemy – objem místního úložiště namontovaného na kontejnerech;
  • build cache – dočasné soubory generované procesem vytváření image (pomocí nástroje BuildKit, dostupného od Docker verze 18.09).

Vsadím se, že po tomto jednoduchém převodu toužíte vyčistit svůj disk od odpadu a vrátit drahocenné gigabajty zpět k životu (poznámka: zvláště pokud za tyto gigabajty platíte nájem každý měsíc).

Využití disku kontejnery

Pokaždé, když vytvoříte kontejner na hostitelském počítači, vytvoří se v adresáři /var/lib/docker několik souborů a adresářů, mezi nimiž stojí za zmínku následující:

  • Adresář /var/lib/docker/containers/container_ID – při použití standardního ovladače protokolování se zde ukládají protokoly událostí ve formátu JSON. Příliš podrobné protokoly a také protokoly, které nikdo nečte ani jinak nezpracovává, často způsobují zaplnění disků.
  • Adresář /var/lib/docker/overlay2 obsahuje vrstvy pro čtení a zápis kontejneru (overlay2 je preferovaný ovladač ve většině distribucí Linuxu). Pokud kontejner ukládá data ve svém systému souborů, pak budou umístěna do tohoto adresáře.

Představme si systém, na kterém je nainstalován nedotčený Docker, který se nikdy nepodílel na spouštění kontejnerů nebo vytváření obrazů. Jeho zpráva o využití místa na disku bude vypadat 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

Pojďme spustit nějaký kontejner, například NGINX:

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

Co se stane s diskem:

  • obrázky zabírají 126 MB, jedná se o stejný NGINX, který jsme spustili v kontejneru;
  • kontejnery zabírají 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         0B

Soudě podle závěru zatím nemáme žádný prostor, který bychom mohli uvolnit. Protože 2 bajty jsou naprosto lehkomyslné, představme si, že náš NGINX někam nečekaně zapsal 100 megabajtů dat a vytvořil v sobě soubor test.img přesně této velikosti.

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

Podívejme se znovu na využití místa na disku na hostiteli. Uvidíme, že kontejner (kontejnery) tam zabírá 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         0B

Myslím, že váš zvídavý mozek už přemýšlí, kde se nachází náš soubor test.img. Pojďme to 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.img

Aniž bychom zacházeli do podrobností, můžeme si všimnout, že soubor test.img je pohodlně umístěn na úrovni čtení a zápisu, řízené ovladačem overlay2. Pokud zastavíme náš kontejner, hostitel nám řekne, ž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         0B

Jak to můžeme udělat? Smazáním kontejneru, což bude znamenat uvolnění odpovídajícího místa na úrovni čtení i zápisu.

Pomocí následujícího příkazu můžete odstranit všechny nainstalované kontejnery jedním tahem a vyčistit disk od všech jimi vytvořených souborů pro čtení a zápis:

$ 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

Smazáním kontejneru jsme tedy uvolnili 104,9 megabajtů. Ale protože již nepoužíváme dříve stažený obrázek, stává se také kandidátem na smazá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         0B

Poznámka: Dokud je obrázek používán alespoň jedním kontejnerem, nebudete moci tento trik použít.

Dílčí příkaz prune, který jsme použili výše, má vliv pouze na zastavené kontejnery. Pokud chceme smazat nejen zastavené, ale i spuštěné kontejnery, měli bychom použít jeden z těchto příkazů:

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

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

Postranní poznámky: pokud při spouštění kontejneru použijete parametr -rm, pak se při jeho zastavení uvolní veškeré místo na disku, které zabíral.

Použití obrazů disků

Před několika lety byla velikost obrázku několik set megabajtů zcela normální: obrázek Ubuntu vážil 600 megabajtů a obrázek Microsoft .Net vážil několik gigabajtů. V oněch chlupatých dnech si stažení pouze jednoho obrázku mohlo vybrat velkou daň na volném místě na disku, i když sdílíte úrovně mezi obrázky. Dnes - chvála velké - obrázky váží mnohem méně, ale i tak můžete rychle zaplnit dostupné zdroje, pokud neučiníte nějaká opatření.

Existuje několik typů obrázků, které koncový uživatel přímo nevidí:

  • přechodné obrázky, na jejichž základě se shromažďují další obrázky - nelze je smazat, pokud používáte kontejnery založené na těchto „jiných“ obrázcích;
  • visící obrázky jsou přechodné obrázky, na které se neodkazuje žádný z běžících kontejnerů – lze je smazat.
  • Pomocí následujícího příkazu můžete zkontrolovat visící obrázky ve vašem systému:

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

Můžete je odstranit následujícím způsobem:

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

Můžeme také použít dílčí pří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

Pokud najednou chceme smazat všechny obrázky úplně (a nejen visící) jedním příkazem, můžeme to udělat:

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

Využití disku podle svazků

Svazky se používají k ukládání dat mimo souborový systém kontejneru. Například pokud chceme uložit výsledky aplikace, abychom je mohli použít jiným způsobem. Běžným příkladem jsou databáze.

Spustíme kontejner MongoDB, připojíme externí svazek ke kontejneru a obnovíme 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 
  --jsonArray

Data budou umístěna na hostitelském počítači v adresáři /var/lib/docker/volumes. Ale proč ne na úrovni čtení a zápisu kontejneru? Protože v Dockerfile obrazu MongoDB je adresář /data/db (kam MongoDB standardně ukládá svá data) definován jako svazek.

Docker Tipy: Vyčistěte svůj počítač od nevyžádaného odpadu

Vedlejší poznámka: mnoho obrázků, které musí produkovat data, používá k uložení těchto dat objemy.

Když si dostatečně pohrajeme s MongoDB a zastavíme (nebo možná i smažeme) kontejner, svazek se nesmaže. Bude i nadále zabírat naše vzácné místo na disku, dokud jej explicitně neodstraníme příkazem, jako je tento:

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

No, nebo můžeme použít dílčí příkaz prune, který je nám již známý:

$ 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žití disku pro mezipaměť sestavení obrazu

V Dockeru 18.09 doznal proces vytváření obrázků díky nástroji BuildKit několik změn. Tato věc zvyšuje rychlost procesu a optimalizuje ukládání dat a správu zabezpečení. Zde nebudeme uvažovat o všech podrobnostech tohoto úžasného nástroje, zaměříme se pouze na to, jak řeší otázky využití místa na disku.

Řekněme, že máme úplně jednoduchou aplikaci Node.Js:

  • soubor index.js spustí jednoduchý HTTP server, který odpoví řádkem na každý přijatý požadavek:
  • soubor package.json definuje závislosti, z nichž pouze expressjs se používá ke spuštění HTTP serveru:

$ 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 vytvoření obrazu vypadá 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"]

Vytvořme obrázek obvyklým způsobem, bez použití BuildKit:

$ docker build -t app:1.0 .

Pokud zkontrolujeme využití místa na disku, můžeme vidět, že místo zabírá pouze základní obraz (uzel:13-alpine) a cílový obraz (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

Pojďme vytvořit druhou verzi naší aplikace pomocí BuildKit. K tomu stačí nastavit proměnnou DOCKER_BUILDKIT na 1:

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

Pokud nyní zkontrolujeme využití disku, uvidíme, že je zde nyní zahrnuta mezipaměť sestavení (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

Chcete-li jej vymazat, použijte následující pří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

Vymazat vše!

Podívali jsme se tedy na vyčištění místa na disku obsazeného kontejnery, obrazy a svazky. V tom nám pomáhá dílčí příkaz prune. Ale lze jej použít také na úrovni dockerového systému a vyčistí vše, co 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]

Pokud z nějakého důvodu šetříte místo na disku na počítači se systémem Docker, pak by se pravidelné spouštění tohoto příkazu mělo stát zvykem.

Zdroj: www.habr.com

Přidat komentář