Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як вирішити проблему "no space left on device" на Docker-хості?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Спочатку діагноз, потім prune.** ```bash # Куди йде простір? docker system df # TYPE TOTAL ACTIVE SIZE RECLAIMABLE # Images 42 8 18.4GB 14.2GB (77%) # Containers 23 4 2.1GB 1.8GB # Volumes 15 3 42.0GB 38.0GB (90%) # Build cache 1840 8.4GB 8.4GB ``` ```bash # Reclaim'ни все, що не active docker system prune -af --volumes # Більш targeted (безпечніше) docker image prune -af docker builder prune -af docker container prune -f docker volume prune -f ``` **Довгостроково:** ротуй логи (`max-size`, `max-file` log-opts), став `/var/lib/docker` на окремий partition, set up periodic prune-cron.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**«No space left on device»** це найтиповіший Docker-біль у production. Images накопичуються, build-cache росте, container-логи без меж, volumes переживають container'и, що їх створили. Фікс це мікс immediate-cleanup і довгострокової гігієни. ## Теорія ### TL;DR - **Діагнозь через `docker system df`** перед prune. Знай, куди йде простір. - **`docker system prune -af --volumes`** reclaim'ить все, що не active. Безпечно у dev, обережно у prod (дропає detached-volume). - **Логи мовчазний killer**: chatty-container може заповнити `/var/lib/docker/containers/<id>/<id>-json.log` до гігабайт. - **Build-cache** може вирости до десятків GB на busy CI-host. Prune regularly. - **Довгостроково:** ставь `/var/lib/docker` на окремий partition; enable log-rotation у `daemon.json`; cron prune. ### Куди йде простір Docker зберігає все під `/var/lib/docker` (або куди показує `data-root`): ``` /var/lib/docker/ ├── overlay2/ # image-layer'и + writable container-layer ├── containers/<id>/ # container-metadata + логи (json-file) ├── volumes/ # named-volume ├── image/ # image-manifest metadata ├── buildkit/ # build-cache (з BuildKit) └── tmp/ # transient ``` На busy-host, breakdown зазвичай: - 30-50%, image-layer - 20-40%, anonymous/orphan-volume - 10-20%, container-logи - 5-20%, build-cache `docker system df` показує це в human-readable формі. ### Категорії waste | Категорія | Що це | Як чистити | |---|---|---| | **Stopped container** | exited container, збережені для `docker logs`/`docker start` | `docker container prune -f` | | **Dangling image** | image без tag (заміщені новішим build) | `docker image prune -f` | | **Unused image** | image, не reference'ний жодним container | `docker image prune -af` (нота `-a`) | | **Anonymous-volume** | volume, auto-created `VOLUME`-директивою Dockerfile, ніколи не cleaned | `docker volume prune -f` (named-volume теж, якщо `-a`) | | **Build-cache** | BuildKit cache-layer від минулих build | `docker builder prune -af` | | **Container-logи** | json-file логи, що виросли без меж | log-rotation-config | | **Networks** | unused custom-networks (малі) | `docker network prune -f` | ## Приклади ### Диагностичний flow ```bash # Крок 1: який розмір /var/lib/docker? sudo du -sh /var/lib/docker # 87G # Крок 2: breakdown за Docker-категорією docker system df # TYPE TOTAL ACTIVE SIZE RECLAIMABLE # Images 67 12 31.4GB 24.1GB (76%) # Containers 34 8 3.2GB 2.7GB # Volumes 28 5 45.0GB 38.0GB (84%) # Build Cache 2104 8.0GB 8.0GB # Крок 3: drill у найгіршого порушника docker system df -v # verbose: per-image, per-container, per-volume ``` Колонка `RECLAIMABLE` твій перший target. ### Швидкий виграш: prune все безпечно ```bash # Stopped-container, dangling-image, unused-network, build-cache docker system prune -f # Reclaimed: 12.5GB ``` Без `--volumes`-флага значить volume залишаються. Безпечний default. ### Агресивно: reclaim'ни все, що не in use ```bash docker system prune -af --volumes # Включає: # - всі image, не використані container'ом (не лише dangling) # - всі volume, не mounted у жодному container ``` **Небезпечно у prod**: stopped-container's volume OK, але volume, що існує, але випадково не currently-mounted (бо єдиний container, що його використовує, зараз перестворюється), видаляється. Бери це у dev/CI, не prod. ### Targeted-команди ```bash # Images docker image prune -f # лише dangling docker image prune -af # всі image, не використані container # Container'и docker container prune -f # stopped-container # Volume'и docker volume prune -f # volume, не mounted у жодному container # Build-cache docker builder prune -f # cache старший за 24h, dangling docker builder prune -af # весь build-cache docker builder prune --filter until=168h # cache старший за 7 днів # Networks docker network prune -f ``` ### Container-логи Логи дефолтно `json-file`-driver без size-limit. Chatty-app заповнює GB. ```bash # Дивись per-container log-file розміри for c in $(docker ps -q); do name=$(docker inspect -f '{{.Name}}' $c | sed 's|/||') size=$(sudo du -sh /var/lib/docker/containers/$c/$c-json.log 2>/dev/null | cut -f1) echo "$size $name" done ``` **Truncate runaway-log без restart:** ```bash sudo truncate -s 0 /var/lib/docker/containers/<id>/<id>-json.log ``` **Permanent-фікс** через ставлення log-limit у `/etc/docker/daemon.json`: ```json { "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } } ``` Потім `sudo systemctl restart docker`. Існуючі container'и тримають старий config, поки не перестворені; нові container'и inherit. Для production, бери log-shipper (Fluentd, Loki, syslog), щоб логи покидали host повністю. ### Перенеси `/var/lib/docker` на більший partition Якщо OS-partition малий (наприклад, DigitalOcean-droplet з 25 GB): ```bash # Зупини daemon sudo systemctl stop docker # Mount новий disk на /mnt/docker sudo rsync -a /var/lib/docker/ /mnt/docker/ sudo mv /var/lib/docker /var/lib/docker.bak sudo ln -s /mnt/docker /var/lib/docker # (або update daemon.json з "data-root": "/mnt/docker") sudo systemctl start docker docker info | grep 'Docker Root Dir' ``` Верифікуй, потім `rm -rf /var/lib/docker.bak`. ### Periodic cleanup через cron ```bash # /etc/cron.daily/docker-prune #!/bin/sh docker container prune -f docker image prune -f docker builder prune -f --filter until=72h # Не включай --volumes; volume-cleanup потребує ручного review ``` Зроби executable: `chmod +x /etc/cron.daily/docker-prune`. ### «No space left» під час build Під час `docker build`, помилка часто з BuildKit's intermediate-layer, не з фінального image: ```bash docker builder prune -af # Звільнює cache. Спробуй build знову. ``` Або з `/tmp` (використовується для temporary-download): ```bash df -h /tmp # Якщо /tmp малий, set TMPDIR=/var/tmp перед docker build. ``` ### Коли prune не допомагає Іноді `docker system df` рапортує багато reclaimable-простору, але `docker system prune` reclaim'ить дуже мало. Причини: 1. **Inode exhausted** (не block). `df -i`, щоб перевірити. 2. **Open file-handle тримають deleted-files**. Restart daemon, щоб release їх. 3. **Volume-content величезний, але сам volume in use**. Volume «active» (використовується running-container), тож prune skip'ає. Інспектуй volume-content через `docker run --rm -v <vol>:/data alpine du -sh /data`. 4. **Snapshot/COW-chain**. З devicemapper, можливо потрібно recreate storage-pool. Мігруй на overlay2. ## Реальне застосування - **CI-host**: prune builder-cache погодинно; prune image щоденно; логи у syslog. - **Production app-сервери**: log-rotation у daemon.json; weekly-prune-cron; alerting на disk-usage > 70%. - **Single-host hobby**: monthly `docker system prune -af`. Done. - **Disk-emergency**: `docker system prune -af --volumes`, якщо можеш підтвердити, що нема detached, але потрібних volume; інакше prune image і builder спочатку. ### Типові помилки **Run `prune --volumes` у prod наосліп** Якщо сервіс перестворюється і його volume коротко detached, prune його видаляє. Завжди підтверджуй volume-використання: ```bash docker volume ls # Вручну інспектуй кожен незнайомий volume перед prune ``` **Забути `-a` на `docker image prune`** Без `-a`, лише **dangling**-image (без tag) видаляються. Tagged, але unused-image лишаються. **Ігнорувати container-логи** Один chatty-сервіс може заповнити 50 GB у `<id>-json.log`, поки ти питаєш, чому disk повний, а `docker system df` не показує нічого незвичайного. **Ставити `/var/lib/docker` на OS-partition без моніторингу** Коли disk заповнюється, daemon може стати unstable; restart fail, бо логи не можуть flush. Окремий partition + alerting запобігає. ### Питання для поглиблення **Q:** Різниця між `docker prune` і `docker rm`? **A:** `docker rm <name>` видаляє конкретний container; `docker container prune` видаляє **всі** stopped-container за один shot. Та ж ідея для image і volume. **Q:** Чи prune вб'є running-сервіси? **A:** Ні. Prune-команди skip'ають resource, що active (running-container, mounted-volume, used-image). Чіпають лише genuinely-unused речі. **Q:** Як побачити, що у volume перед видаленням? **A:** `docker run --rm -v <volname>:/data alpine ls -la /data`. Якщо important-data, backup перед prune. **Q:** (Senior) Як будувати довгострокову retention-policy для build-cache? **A:** BuildKit підтримує cache-backend (`--cache-to=type=registry,ref=...`). Push-cache у dedicated-registry-image; локально prune все старше за N днів; покладайся на remote-cache для shared-CI. Це обмежує локальний disk, зберігаючи cross-build deduplication. **Q:** (Senior) Чому disk заповнюється швидше, ніж `docker system df` каже? **A:** `docker system df` не включає `daemon.json`-level стан, BuildKit's metadata або зовнішні mount. Порівнюй з `du -sh /var/lib/docker/*`. Невідповідності зазвичай значать: orphaned overlay2-каталоги з daemon-crash, дуже великі container log-file, або host-bind-mount у каталог, про який ти забув.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.