Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке dangling image і як їх видалити?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Dangling image** це untagged image без tag, що на нього вказує, зазвичай попередній білд, що втратив tag, коли новіший білд зайняв те саме ім'я. Займають диск і не служать нічому. ```bash docker images -f dangling=true # перелічити їх docker image prune # видалити лише dangling docker image prune -a # видалити dangling І невикористані tagged image docker system prune -a --volumes # ядерний cleanup усього невикористаного ``` **Головне:** dangling = без tag, без дітей. Відрізняється від «unused» (tagged, але жоден container не посилається). `docker image prune` чистить dangling безпечно. `-a` ще видаляє unused-but-tagged image, агресивніше.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**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 Це різниця, на якій люди зашпинюються. | | Dangling | Unused | |---|---|---| | Має 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` існував, і досі працює.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.