Skip to main content

Що таке dangling image і як їх видалити?

Dangling images накопичуються природно у будь-якому Docker-сетапі, що часто білдить image. Це не corruption і не баг, це побічний ефект того, як працюють tag. Чистити їх це звичайна disk-гігієна.

Теорія

TL;DR

  • Dangling image це image без tag і без іншого image, що посилається на нього як на батька. Доступний лише по digest.
  • З'являються найчастіше після того, як docker build перевикористовує tag, попередній image з тим tag стає dangling.
  • У docker images видно як рядки, де REPOSITORY і TAG обидва <none>.
  • Безпечно видаляти: ніщо не посилається; нічого не зламається, якщо вони зникнуть.
  • docker image prune видаляє ВСІ dangling. docker image prune -a агресивніший, ще видаляє unused-but-tagged image.

Швидкий приклад

bash
# Зібрати той самий tag двічі → перший image стає dangling $ docker build -t myapp:1.0 . $ # ... редагуємо Dockerfile ... $ docker build -t myapp:1.0 . $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE myapp 1.0 4f06b3e2c0c1 2 minutes ago 180MB <none> <none> 8a3f2d1c9b8e 10 minutes ago 180MB ← DANGLING nginx 1.27 a3b4c5d6e7f8 3 weeks ago 54MB # Перелічити лише dangling $ docker images -f dangling=true REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 8a3f2d1c9b8e 10 minutes ago 180MB # Почистити $ docker image prune -f Deleted Images: deleted: sha256:8a3f2d1c9b8e... Total reclaimed space: 180MB

Другий білд замінив tag-pointer myapp:1.0; старий image все ще на диску, але без tag. prune його видаляє.

Dangling vs unused

Це різниця, на якій люди зашпинюються.

DanglingUnused
Має tag?Ні (<none>:<none>)Так
На нього посилається container?НіНі
Видаляє docker image pruneТакНі
Видаляє docker image prune -aТакТак

Dangling = untagged + ніщо не посилається. Unused = tagged, але жоден поточний container його не використовує.

Tagged image, що ти стягнув три місяці тому і ніколи не запускав container з нього, це unused, але не dangling. Звичайний prune його не зачепить; prune -a зачепить.

Як з'являються dangling image

Найпоширеніші шляхи:

  1. Перевикористання tag при білді. docker build -t myapp:1.0 двічі. Image першого білду втрачає tag.
  2. Re-pull з тим же tag. docker pull nginx:latest після того, як upstream запушив новий latest. Старий image стає untagged.
  3. Multi-stage білди. Кожен проміжний стейдж дає untagged image. З дефолтними налаштуваннями BuildKit вони кешуються невидимо; з legacy builder вони показуються як dangling.
  4. Failed білди. docker build, що падає посередині, лишає проміжні untagged image.

BuildKit (дефолт з Docker 23) набагато краще не лишає такого. Legacy builder продукував більше dangling image на білд.

Команди cleanup, у порядку агресії

bash
# Лише dangling (безпечно, зазвичай те, що треба) docker image prune docker image prune -f # пропустити підтвердження # Dangling І будь-який tagged image без container docker image prune -a # Все: зупинені container, dangling image, невикористані мережі, build-cache docker system prune # Те саме плюс volume (ДЕСТРУКТИВНО, стирає named volume теж) docker system prune -a --volumes # Filtered docker image prune -a --filter 'until=24h' # лише image старші за 24г

Звичка щоденних ops: docker system prune -f щотижня на dev-машинах. Звільняє гігабайти. Прод-обережність: ніколи system prune -a --volumes сліпо, флаг --volumes ще видаляє named volume, що можуть бути твоїми базами.

Типові помилки

Плутати prune з prune -a

bash
# Видаляє лише untagged dangling image $ docker image prune # Видаляє ВСІ image, що жоден container не використовує (включно з tagged) $ docker image prune -a

Якщо у тебе nginx:1.27, node:22, postgres:16 стягнуті, але жоден container їх зараз не крутить, звичайний prune їх лишає; prune -a видаляє. Сюрприз, коли вперше re-pull'аєш 200MB image, бо prune -a його змів.

Запуск system prune --volumes на проді

bash
# ДЕСТРУКТИВНО: ще видаляє named volume (бази!) $ docker system prune -af --volumes

--volumes видаляє будь-який volume, не змонтований running-container. Якщо твоя DB коротко down на час deploy, її volume не приєднаний і його зносить. Ніколи не використовуй --volumes на проді без явної верифікації.

Думати dangling = corrupt

bash
$ docker images REPOSITORY TAG IMAGE ID SIZE <none> <none> 8a3f2d1c9b8e 180MB

Dangling image не corrupt; це повністю валідні OCI image, які просто втратили tag. Можеш docker run <image-id> проти них без проблем. Видаляють, не зламані.

Pruning на CI runner з активними білдами

docker image prune -a посеред білду може race з build-cache і сповільнити наступні білди. Плануй cleanup між білдами, не під час.

Реальне застосування

  • Dev-машини: щотижневий docker system prune -f--volumes лише коли впевнений, що нічого важливого не unmounted).
  • CI runners: cleanup-хук в кінці кожного job: docker container prune -f && docker image prune -f.
  • Прод-хости: запланований docker image prune -af --filter 'until=168h' (тиждень) через cron, тримає свіжі image, видаляє старі.
  • Disk-pressure response: docker system df спочатку, щоб побачити, куди іде місце, потім таргетований prune.

Питання для поглиблення

Q: Яка різниця між docker image prune і docker rmi?


A: prune bulk + filtered; rmi <id> таргетований на конкретний image (або список). Бери prune, коли тобі байдуже, які саме image зникнуть; бери rmi, коли хочеш видалити конкретний.

Q: Як побачити використання диску Docker?


A: docker system df показує totals (image, container, volume, build-cache) і reclaimable простір. docker system df -v verbose з per-image і per-volume розмірами.

Q: Чи можна тримати dangling image для кешу?


A: Загалом ні, вони не використовуються як build-cache (BuildKit-cache живе деінде). Єдиний раз, коли б ти їх тримав, це якщо використовуєш legacy builder і конкретний intermediate перевикористовується. З сучасним BuildKit просто prune.

Q: Чому prune не видаляє мій image, хоч жоден container не running?


A: Бо у image є tag. Звичайний prune зачіпає лише dangling (untagged) image. Додай -a, щоб ще видалити unused-tagged.

Q: (Senior) Як налаштувати автоматичний Docker cleanup на прод-сервері?


A: Щоденний systemd-timer або cron-job, що крутить docker container prune -f --filter 'until=24h' && docker image prune -af --filter 'until=168h' && docker builder prune -f --filter 'until=72h'. Уникай --volumes. Моніторь диск через docker system df до і після для верифікації, що cleanup робить очікуване. Для великих кластерів це живе у host config-management (Ansible/Chef), не per-container.

Приклади

Cleanup loop для CI runner

bash
# .github/workflows/cleanup.yml або Jenkins postBuild #!/bin/sh set -e docker container prune -f --filter 'until=1h' docker image prune -f docker builder prune -f --filter 'until=24h' # Volume лишаємо, вони тримають inter-job кеші, якщо є.

Дрібний cleanup після кожного job; за тиждень тримає /var/lib/docker runner'а від вибуху.

Inspect перед prune

bash
$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 47 12 8.421GB 6.3GB (74%) Containers 18 4 412MB 287MB (69%) Local Volumes 9 5 3.2GB 180MB (5%) Build Cache 128 0 2.1GB 2.1GB (100%) $ docker image prune -af Total reclaimed space: 6.3GB $ docker builder prune -f Total reclaimed space: 2.1GB

Цифри кажуть, куди іде місце. Image-prune звільнив 6.3GB; build-cache ще 2.1GB. Volume не зачеплено (180MB тільки, і вони мабуть тримають реальні дані).

Bulk-видалення з фільтром

bash
$ docker images -f dangling=true -q | xargs -r docker rmi # Або простіше: $ docker image prune -f

Дві форми еквівалентні. prune сучасний one-liner; xargs-форма з часів до того, як prune існував, і досі працює.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Коментарі

Ще немає коментарів