Не хватает места — образ Docker слишком большой?

Привет! Я администрирую небольшой самописный форум на облачном VPS с 25 ГБ дискового пространства под управлением Debian 13. Я пытался обновить его до версии 2026.6.0-latest с помощью команды ./launcher rebuild app, но обновление прервалось из-за нехватки места на диске. Я следовал подсказке и очистил образы Docker, но это не помогло. У меня осталось 3,9 ГБ. Загрузки на моём форуме занимают 138 МБ, а резервные копии — 448 МБ. Мой сервер практически пуст, кроме установки Discourse, я ничего больше на нём не делал.

После анализа с помощью du я обнаружил, что /var/lib/containerd занимает 13 ГБ, а /var/docker — 5,1 ГБ. Это нормально, что они занимают так много места? Можно ли что-то с этим сделать?

Если это нормально, то, видимо, мне придётся доплатить за дополнительное хранилище. Хотелось бы просто убедиться в этом перед тем, как нести дополнительные расходы. Спасибо!

Хм… вы пробовали ./launcher cleanup?

Стоит запустить очистку. Пожалуйста, опубликуйте подробности того, что произошло. Вот пример того, что я делал ранее:

root@ubuntu-2gb-nbg1-1:/var/discourse# df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        19G   12G  6.5G  65% /

root@ubuntu-2gb-nbg1-1:/var/discourse# ./launcher cleanup
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y

Deleted Images:
deleted: sha256:33ce56b3484175342191a344fe1aa9f330431de7bf6f0f0e14f75c5bd851a5b0
deleted: sha256:5e04a0411f813e8f2c1a50d84a7d7bb1b17a855ce041730cf8e3b2fb90144b19
untagged: discourse/base:2.0.20200512-1735
untagged: discourse/base@sha256:7f6c5be23a8e4237cecafaca9d041de5964f8237345b7b183cebdee1f73ed024
deleted: sha256:991acdba0b1f18141192f8682bc5ec1c3365dff0d4fa1c6504e6ce0e3ae6dd76
deleted: sha256:e1c41c8dbd697ae0a61ca612c61f085f69f5bf74c4269cf5c68b4de0fec723fa
deleted: sha256:c2adabaecedbda0af72b153c6499a0555f3a769d52370469d8f6bd6328af9b13
untagged: discourse/base:2.0.20200724-1815
untagged: discourse/base@sha256:1d5eb2f8eae84203b28d3c643648d0dd7d213c2055865cfa5132e30db9e365d5

Total reclaimed space: 2.591GB

# df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        19G  8.7G  9.3G  49% /

Также стоит подробно изучить использование диска и опубликовать здесь эти данные! Например, см.:

Если на системе есть резервные копии, их следует скачать, проверить и удалить все, кроме последней. Если вы находитесь в экстремальной ситуации, удалите и последнюю копию. (В моём случае я сначала убеждаюсь, что скачанная копия также защищена моей личной резервной копией, хранящейся вне сайта. Всегда имейте как минимум две копии.)

Помимо утилиты du, которая отвечает на вопросы на уровне операционной системы, можно задать вопросы на уровне Docker. Пожалуйста, опубликуйте свои подробные результаты!

# docker volume ls -qf dangling=true
# docker images -a

Управлять использованием диска на экземпляре с 25 ГБ сложно — я делал это долгое время, тратя время и используя опыт системного администратора. В конце концов я сменил провайдера, заплатил меньше и получил 40 ГБ, что оказалось намного лучше.

Также см. ранее:
Discourse upgrade fails due to insufficient disk space on 25G droplet

Это очень информативно, спасибо.

Прежде чем я попробую cleanup, есть ли в Discourse способ проверить целостность резервной копии без восстановления?

Результат команды du -hx / | sort -h | tail -49 (я обнаружил, что флаг -h упрощает для меня анализ результатов):

833M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var/www/discourse/vendor/bundle/ruby
833M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var/www/discourse/vendor/bundle/ruby/3.4.0
837M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/283/fs/var
837M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/283/fs/var/www
837M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/283/fs/var/www/discourse
837M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/283/fs/var/www/discourse/vendor
837M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/283/fs/var/www/discourse/vendor/bundle
837M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/283/fs/var/www/discourse/vendor/bundle/ruby
837M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/283/fs/var/www/discourse/vendor/bundle/ruby/3.4.0
839M	/var/discourse/shared
839M	/var/discourse/shared/standalone
840M	/var/discourse
863M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42
863M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs
868M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/283
868M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/283/fs
874M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/284
874M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/284/fs
874M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/43
874M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/43/fs
908M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/263/fs/usr
925M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/22/fs/usr
944M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/263
944M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/263/fs
961M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/22
961M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/22/fs
1.3G	/usr
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251/fs
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251/fs/var
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251/fs/var/www
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251/fs/var/www/discourse
1.5G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs/var
1.5G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs/var/www
1.5G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs/var/www/discourse
1.6G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227
1.6G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs
2.5G	/var/log
2.5G	/var/log/journal
2.5G	/var/log/journal/1d9299c9656046d6bd0e18d4a09c183c
2.7G	/var/lib/containerd/io.containerd.content.v1.content
2.7G	/var/lib/containerd/io.containerd.content.v1.content/blobs
2.7G	/var/lib/containerd/io.containerd.content.v1.content/blobs/sha256
9.8G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs
9.8G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots
13G	/var/lib
13G	/var/lib/containerd
17G	/var
20G	/

Результат команды docker volume ls -qf dangling=true был пустым. На самом деле, docker volume ls тоже пуст.

docker images -a:

IMAGE                              ID             DISK USAGE   CONTENT SIZE   EXTRA
discourse/base:2.0.20260209-1300   50d2dae489a9       4.77GB         1.12GB        
discourse/base:2.0.20260521-0047   27373b823bbe       4.89GB         1.17GB        
local_discourse/app:latest         01527763be8d        6.9GB         1.63GB    U   

Я слишком мало знаю о Docker, чтобы проанализировать этот вывод, но /var/log/ кажется немного большим, если там только логи. Также интересно, что у меня 3 образа, хотя запущен только 1 форум (хотя, возможно, это вполне ожидаемо).

Спасибо за замечание о необходимости большего места на диске. Я, скорее всего, расширю его, но до этого это хороший опыт обучения.

Вы можете немного сэкономить, перенастроив ведение журнала:

Я никогда толком не разбирался в управлении контейнерами Docker. Иногда очистка помогает. Я только что выполнил следующие команды:

# cd /var/discourse/
# df -h /
Файловая система      Размер  Использовано  Свободно  Использовано%  Смонтировано на
/dev/sda1             38G     24G           13G       67%            /
# docker images -a
                                                                                             i Info →   U  В использовании
ИЗОБРАЖЕНИЕ                              ID             РАСХОД ДИСКА   РАЗМЕР КОНТЕНТА   ДОП.
discourse/base:2.0.20260209-1300         18ccefc73392        3.1GB             0B        
local_discourse/app:latest               810ac5579584       4.57GB             0B    U   
<без метки>                              d303cfc49c99       4.37GB             0B        
<без метки>                              a9d03385c205       4.34GB             0B        
# ./launcher cleanup
ВНИМАНИЕ! Это удалит все остановленные контейнеры.
Вы уверены, что хотите продолжить? [y/N] y
Восстановлено места: 0B
ВНИМАНИЕ! Это удалит все образы, не связанные ни с одним контейнером.
Вы уверены, что хотите продолжить? [y/N] y
Удалённые образы:
удалено: sha256:d303cfc49c992b7fa0b0da65e38f3de79312c6e42eb99e5fd7b27bf4e237ab1d
удалено: sha256:829057c668fd2bd0f7b863c2589e5c3c27364285b39d6df31d38eb208e6410df
без метки: discourse/base:2.0.20260209-1300
без метки: discourse/base@sha256:50d2dae489a9c9916c3d50d880f7f1282fcbe179339b60a8947ab135c1f1f9bf
удалено: sha256:a9d03385c205f740e5f02db0c665a83688f7194d5386bd2d01772b8b5cd5dc65
удалено: sha256:70ec1b4b6cab7365b5f56b8187ef7631e6906fe13b5d3a2b1e39d3457d14514c

Восстановлено места: 2.517GB
# docker images -a
                                                                                             i Info →   U  В использовании
ИЗОБРАЖЕНИЕ                        ID             РАСХОД ДИСКА   РАЗМЕР КОНТЕНТА   ДОП.
local_discourse/app:latest         810ac5579584       4.57GB             0B    U   
<без метки>                        18ccefc73392        3.1GB             0B        
# df -h /
Файловая система      Размер  Использовано  Свободно  Использовано%  Смонтировано на
/dev/sda1             38G     21G           15G       59%            /

Вывод команды ./launcher cleanup:

WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
untagged: discourse/base:2.0.20260209-1300
deleted: sha256:50d2dae489a9c9916c3d50d880f7f1282fcbe179339b60a8947ab135c1f1f9bf
deleted: sha256:1bb6f08ca8363e7e002eaf8bafc76b7742d8baa429f816cde77d3d38d234c98a
deleted: sha256:07596c600885cf3f0647c4b41959c5631328ee37af14913b9f2b1b1771ad4f45
untagged: discourse/base:2.0.20260521-0047
deleted: sha256:27373b823bbeca526dd006cefe1c58e7eeca1e5670ab6e619fcd2138f7d50420
deleted: sha256:ab90467600edc09bae8ac2f43420b7c771f87d357aa15646cd40025ec0774fda
deleted: sha256:053438a5cf1727f724f96a4d7af0b135929f633afd8ee05edcddeaf99232b636

Total reclaimed space: 1.17GB

Однако это странно: мой форум Discourse только что показал увеличение свободного места с 3,9 ГБ до 8,5 ГБ. Если я снова запущу du -hx / | sort -h | tail -49, вы сможете сравнить это с моими предыдущими результатами, и /var/lib уменьшился на 8 ГБ:

628M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs/var/www/discourse/vendor/bundle/ruby
628M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs/var/www/discourse/vendor/bundle/ruby/3.4.0
629M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs/var/www/discourse/vendor
733M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var/www/discourse/vendor/bundle/ruby/3.4.0/gems
792M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/43/fs/var/www/discourse/node_modules/.pnpm
793M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/43/fs/var/www/discourse/node_modules
794M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/43/fs/var
794M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/43/fs/var/www
794M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/43/fs/var/www/discourse
833M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var
833M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var/www
833M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var/www/discourse
833M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var/www/discourse/vendor
833M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var/www/discourse/vendor/bundle
833M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var/www/discourse/vendor/bundle/ruby
833M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs/var/www/discourse/vendor/bundle/ruby/3.4.0
839M	/var/discourse/shared
839M	/var/discourse/shared/standalone
841M	/var/discourse
863M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42
863M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/42/fs
874M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/43
874M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/43/fs
925M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/22/fs/usr
961M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/22
961M	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/22/fs
1.3G	/usr
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251/fs
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251/fs/var
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251/fs/var/www
1.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/251/fs/var/www/discourse
1.5G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs/var
1.5G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs/var/www
1.5G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs/var/www/discourse
1.6G	/var/lib/containerd/io.containerd.content.v1.content
1.6G	/var/lib/containerd/io.containerd.content.v1.content/blobs
1.6G	/var/lib/containerd/io.containerd.content.v1.content/blobs/sha256
1.6G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227
1.6G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/227/fs
2.5G	/var/log
2.5G	/var/log/journal
2.5G	/var/log/journal/1d9299c9656046d6bd0e18d4a09c183c
6.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs
6.4G	/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots
7.9G	/var/lib/containerd
8.0G	/var/lib
12G	/var
15G	/

И вывод docker images -a заметно отличается:

IMAGE                        ID             DISK USAGE   CONTENT SIZE   EXTRA
local_discourse/app:latest   01527763be8d        6.9GB         1.63GB    U   

Кажется, что ./launcher cleanup занижает объём освобождённого пространства?

Теперь у меня должно быть достаточно места для обновления. Похоже, что запуск cleanup после обновления — это хорошая привычка.

Спасибо за помощь!

Вы только что очистили два базовых образа, оставив локально собранный образ.

Являются ли базовые образы просто остатками процесса первоначальной установки? Или они также загружаются при выполнении команды rebuild app?

Да. Если отсутствует последний образ, он будет загружен, и вы создадите свой локальный образ на его основе.

Я не могу придумать причины, по которой вам может потребоваться хранить более одного базового образа…