Docker Tips: Ачысціце сваю машыну ад хламу

Docker Tips: Ачысціце сваю машыну ад хламу

Прывітанне, Хабр! Уяўляю вашай увазе пераклад артыкула "Docker Tips: Clean Up Your Local Machine" аўтара Luc Juggery.

Сёння мы пагаворым пра тое, як Docker выкарыстоўвае дыскавую прастору хаставой машыны, а таксама разбярэмся ў тым, як гэтая прастора вызваліць ад шмаццёў невыкарыстоўваных вобразаў і кантэйнераў.


Docker Tips: Ачысціце сваю машыну ад хламу

Агульнае спажыванне

Docker - крутая штука, напэўна сёння мала хто ў гэтым сумняваецца. Усяго некалькі гадоў таму гэты прадукт даў нам зусім новы спосаб пабудовы, дастаўкі і запуску любога асяроддзя, дазваляючы значна зэканоміць рэсурсы працэсара і аператыўнай памяці. У дадатак да гэтага (а для кагосьці гэта будзе нават найважнейшым) Docker дазволіў нам неверагодна спрасціць і ўніфікаваць кіраванне жыццёвым цыклам выкарыстоўваных працоўных асяроддзяў.

Аднак, за ўсе гэтыя любаты сучаснага жыцця даводзіцца плаціць. Калі мы запускаем кантэйнеры, спампоўваем ці ствараем уласныя выявы, разгортваем складаныя экасістэмы, нам прыходзіцца плаціць. І плацім мы, у тым ліку, дыскавай прасторай.

Калі вы ніколі не задумваліся аб тым, колькі ж месцы рэальна занята на вашай машыне Docker'ом, то можаце быць непрыемна здзіўлены высновай гэтай каманды:

$ docker system df

Docker Tips: Ачысціце сваю машыну ад хламу

Тут адлюстравана выкарыстанне дыска Docker'ам у розных разрэзах:

  • вобразы (images) – агульны памер вобразаў, якія былі запампаваны са сховішчаў вобразаў і пабудаваны ў вашай сістэме;
  • кантэйнеры (containers) – агульны аб'ём дыскавай прасторы, які выкарыстоўваецца запушчанымі кантэйнерамі (маецца на ўвазе агульны аб'ём пластоў чытання-запісы ўсіх кантэйнераў);
  • лакальныя тамы (local volumes) - аб'ём лакальных сховішчаў, прымантаваных да кантэйнераў;
  • кэш зборкі (build cache) – часовыя файлы, згенераваныя працэсам пабудовы выяў (пры выкарыстанні прылады BuildKit, даступнага пачынальна з Docker версіі 18.09).

Гатовы паспрачацца, што ўжо пасля гэтага простага пераліку вы гарыце жаданнем пачысціць дыск ад смецця і вярнуць да жыцця каштоўныя гігабайты (заўв. перакл.: асабліва, калі за гэтыя гігабайты вы штомесяц пералічваеце арэндную плату).

Выкарыстанне дыска кантэйнерамі

Кожны раз пры стварэнні кантэйнера на хаставой машыне ў каталогу /var/lib/docker ствараецца некалькі файлаў і каталогаў, сярод якіх варта адзначыць наступныя:

  • Каталог /var/lib/docker/containers/ID_кантэйнера - пры выкарыстанні стандартнага драйвера лагавання менавіта сюды захоўваюцца часопісы падзей у JSON-фармаце. Занадта падрабязныя логі, а таксама логі, якія ніхто не чытае і не апрацоўвае іншымі спосабамі, часта становяцца прычынай перапаўнення дыскаў.
  • Каталог /var/lib/docker/overlay2 – утрымоўвае пласты чытання-запісы кантэйнераў (overlay2 – упадабаныя драйвер у большасці дыстрыбутываў Linux). Калі кантэйнер захоўвае дадзеныя ў сваёй файлавай сістэме, то менавіта ў гэтым каталогу яны і будуць размешчаны.

Давайце ўявім сабе сістэму, на якой усталяваны некранута чысты Docker, ні разу не які ўдзельнічаў у запуску кантэйнераў і зборцы выяў. Яго справаздача аб выкарыстанні дыскавай прасторы будзе выглядаць так:

$ 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

Запусцім які-небудзь кантэйнер, напрыклад, NGINX:

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

Што адбываецца з дыскам:

  • выявы (images) займаюць 126 Мб, гэта той самы NGINX, які мы запусцілі ў кантэйнеры;
  • кантэйнеры (containers) займаюць смешныя 2 байта.

$ 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

Мяркуючы па выснове, у нас яшчэ няма прасторы, якую мы маглі б вызваліць. Бо 2 байта гэта зусім несур'ёзна, давайце ўявім, што наш NGINX нечакана для ўсіх напісаў кудысьці 100 Мегабайт дадзеных і стварыў у сабе файл test.img менавіта такога памеру.

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

Зноў даследуем выкарыстанне дыскавай прасторы на хасце. Мы ўбачым, што кантэйнер (containers) займае там 100 мегабайт.

$ 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

Думаю, ваш дапытлівы мозг ужо задаецца пытаннем, дзе ж знаходзіцца наш файл test.img. Давайце яго пашукаем:

$ 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

Не ўдаючыся ў падрабязнасці можна адзначыць, што файл test.img зручна размясціўся на ўзроўні чытання-запісы, які кіруецца драйверам overlay2. Калі ж мы спынім наш кантэйнер, то хост падкажа нам, што гэтае месца, у прынцыпе, можна вызваліць:

# 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

Як мы можам гэта зрабіць? Выдаленнем кантэйнера, якое пацягне за сабой ачыстку адпаведнай прасторы на ўзроўні чытання-запісы.

З дапамогай наступнай каманды вы можаце выдаліць усе ўсталяваныя кантэйнеры адным махам і ачысціць ваш дыск ад усіх створаных імі на ўзроўні чытання-запісу файлаў:

$ 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

Такім чынам, мы вызвалілі 104,9 Мегабайта выдаленнем кантэйнера. Але паколькі мы ўжо не выкарыстоўваем запампаваны раней вобраз, то ён таксама становіцца кандыдатам на выдаленне і вызваленне нашых рэсурсаў:

$ 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

Увага: датуль, пакуль выява выкарыстоўваецца хоць бы адным кантэйнерам, вы не зможаце выкарыстоўваць гэты трук.

Субкаманда prune, якую мы выкарыстоўвалі вышэй, дае эфект толькі на спыненых кантэйнерах. Калі мы жадаем выдаліць не толькі спыненыя, але і запушчаныя кантэйнеры, варта выкарыстоўваць адну з гэтых каманд:

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

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

Нататкі на палях: калі пры запуску кантэйнера выкарыстоўваць параметр -rm, то пры ім прыпынку будуць вызваленая ўся дыскавая прастора, якое ён займаў.

Выкарыстанне дыска вобразамі

Некалькі гадоў таму памер выявы ў некалькі сотняў мегабайт быў цалкам нармалёвым: выява Ubuntu важыў 600 Мегабайт, а выява Microsoft. Net – некалькі Гігабайт. У тыя кудлатыя часы запампоўка адной толькі выявы магло нанесці вялікія страты вашаму вольнаму месцу на дыску, нават калі вы расшарвалі ўзроўні паміж вобразамі. Сёння - хвала вялікім - выявы важаць нашмат менш, але нават у гэтым выпадку можна хутка забіць наяўныя рэсурсы, калі не прымаць некаторых мер засцярогі.

Ёсць некалькі тыпаў выяў, якія наўпрост не бачныя канчатковаму карыстачу:

  • intermediate вобразы, на аснове якіх сабраны іншыя вобразы ў - яны не могуць быць выдаленыя, калі вы выкарыстоўваеце кантэйнеры на базе гэтых самых "іншых" вобразаў;
  • dangling вобразы - гэта такія intermediate вобразы, на якія не спасылаецца ні адзін з запушчаных кантэйнераў - яны могуць быць выдаленыя.
  • З дапамогай наступнай каманды вы можаце праверыць наяўнасць у вашай сістэме dangling вобразаў:

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

Выдаліць іх можна наступным спосабам:

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

Мы можам выкарыстоўваць таксама субкаманду 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

Калі мы раптам захочам выдаліць наогул усе выявы (а не толькі dangling) адной камандай, то можна зрабіць так:

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

Выкарыстанне дыска тамамі

Тома (volumes) ужываюцца для захоўвання дадзеных за межамі файлавай сістэмы кантэйнера. Напрыклад, калі мы хочам захаваць вынікі працы якога-небудзь прыкладання, каб выкарыстоўваць іх неяк яшчэ. Частым прыкладам з'яўляюцца базы даных.

Давайце запусцім кантэйнер MongoDB, прымантаваны да яго вонкавы па стаўленні да кантэйнера том, і адновім з яго бэкап базы дадзеных (у нас ён даступны ў файле 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

Дадзеныя будуць знаходзіцца на хаставой машыне ў каталогу /var/lib/docker/volumes. Але чаму не на ўзроўні чытання-запісы кантэйнера? Таму што ў Dockerfile выявы MongoDB каталог /data/db (у якім MongoDB па змаўчанні захоўвае свае дадзеныя) вызначаны як том (volume).

Docker Tips: Ачысціце сваю машыну ад хламу

Нататкі на палях: шматлікія выявы, у выніку працы якіх павінны стварацца дадзеныя, выкарыстоўваюць тамы (volumes) для захавання гэтых самых дадзеных.

Калі мы найграемся з MongoDB і спынім (а можа нават і выдалім) кантэйнер, тым не будзе выдалены. Ён працягне займаць нашу каштоўную дыскавую прастору датуль, пакуль мы відавочна не выдалім яго такой камандай:

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

Ну ці мы можам выкарыстоўваць ужо знаёмую нам субкаманду prune:

$ 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:~$

Выкарыстанне дыска для кэша зборкі выяў

У Docker 18.09 працэс стварэння выяў зведаў некаторыя змены дзякуючы прыладзе BuildKit. З дапамогай гэтай штукі павялічваецца хуткасць працэсу, аптымізуецца кіраванне захоўваннем дадзеных і бяспекай. Тут мы не будзем разглядаць усе дэталі гэтай выдатнай прылады, спынімся толькі нам тым, як ён закранае пытанні выкарыстання дыскавай прасторы.

Выкажам здагадку, што ў нас ёсць зусім простае прыкладанне Node.Js:

  • файл index.js запускае просты HTTP сервер, які адказвае радком на кожны атрыманы запыт:
  • файл package.json вызначае залежнасці, з якіх выкарыстоўваецца толькі expressjs для запуску 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 для зборкі выявы выглядае так:

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

Давайце збяром выяву звычайным спосабам, без выкарыстання BuildKit:

$ docker build -t app:1.0 .

Калі мы праверым выкарыстанне дыскавай прасторы, то ўбачым, што месца займаюць толькі базавую выяву (node:13-alpine) і канчатковы вобраз (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

Давайце збяром другую версію нашага прыкладання, ужо з выкарыстаннем BuildKit. Для гэтага нам толькі неабходна ўсталяваць зменную DOCKER_BUILDKIT у значэнне 1:

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

Калі мы зараз праверым выкарыстанне дыска, то ўбачым, што зараз там удзельнічае кэш зборкі (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

Для яго ачысткі скарыстаемся наступнай камандай:

$ 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

Ачысціць усё!

Такім чынам, мы разгледзелі ачыстку дыскавай прасторы, занятай кантэйнерамі, выявамі і тамамі. У гэтым нам дапамагае субкаманда prune. Але яе можна выкарыстоўваць і на сістэмным узроўні docker, і яна ачысціць усё, што толькі зможа:

$ 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]

Калі вы па якіх-небудзь чынніках эканоміце дыскавую прастору на машыне з Docker, то перыядычны запуск гэтай каманды варта ўвесці ў звычку.

Крыніца: habr.com

Дадаць каментар