10年自托管 discourse 管理员提问:为何不在重建时进行启动器清理?

大家好。我叫 Lee,从 2013 年开始就断断续续地自行托管 Discourse。我记得刚开始时不得不折腾 rbenv。我记得不得不编译 nginx 和 Phusion Passenger 来运行东西。我记得大约十年前和 @sam 争论过,认为转向 Docker 是屈服于“在我家目录和我的点文件噩梦中就能运行”的开发者弱点(我当时大错特错!)。我记得第一次听到“自行车棚”这个说法。引用他的话,我记得一切

在离开几年后,我又有机会重新开始自行托管 Discourse,以取代休斯顿地区天气网站上的原生 WordPress 评论。该网站通常每天有约 10,000 次页面浏览量,但在飓风期间,可能会达到约 200 万次页面浏览量,约有 100 万独立访客。多年来,我们一直在努力解决 WordPress 的原生评论问题,但从上周三开始,我们已成功上线自行托管的 Discourse。(而且还是在 Graviton3 上!说真的,它就是能用,而且很棒。)

我要说的是重点:现在是 2025 年,作为一名自行托管者,我仍然需要手动管理我的 Docker 镜像空间。在生产环境运行不到一周后,我将通过代码片段讲述一个关于 /dev/root 的故事:

[11:49:56] 0 ✓ (1.8ms)
root@discourse:/var/discourse # df -h
Filesystem       Size  Used Avail Use% Mounted on
/dev/root         30G   21G  9.6G  69% /
tmpfs            7.7G     0  7.7G   0% /dev/shm
tmpfs            3.1G  1.1M  3.1G   1% /run
tmpfs            5.0M     0  5.0M   0% /run/lock
efivarfs         128K  3.6K  125K   3% /sys/firmware/efi/efivars
/dev/nvme1n1p16  891M  109M  720M  14% /boot
/dev/nvme1n1p15   98M  6.4M   92M   7% /boot/efi
/dev/nvme0n1      32G  346M   30G   2% /var/discourse
tmpfs            1.6G   12K  1.6G   1% /run/user/1001
overlay           30G   21G  9.6G  69% /var/lib/docker/overlay2/5a649418bbfc064f488e895572eec1ace487a3eaa324fe1d8e3b395e6c5e3645/merged

[11:49:59] 0 ✓ (4.8ms)
root@discourse:/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:
untagged: discourse/base@sha256:3696bdf18652b5455bd33795ec3b8e0f201c17a04f0e0126fc0317ed821373cd
....

[a whoooooooooooooooole lot of lines redacted]

....
Total reclaimed space: 12.43GB

[11:50:34] 0 ✓ (27.8s)
root@discourse:/var/discourse # df -h
Filesystem       Size  Used Avail Use% Mounted on
/dev/root         30G  6.9G   24G  23% /
tmpfs            7.7G     0  7.7G   0% /dev/shm
tmpfs            3.1G  1.1M  3.1G   1% /run
tmpfs            5.0M     0  5.0M   0% /run/lock
efivarfs         128K  3.6K  125K   3% /sys/firmware/efi/efivars
/dev/nvme1n1p16  891M  109M  720M  14% /boot
/dev/nvme1n1p15   98M  6.4M   92M   7% /boot/efi
/dev/nvme0n1      32G  346M   30G   2% /var/discourse
tmpfs            1.6G   12K  1.6G   1% /run/user/1001
overlay           30G  6.9G   24G  23% /var/lib/docker/overlay2/5a649418bbfc064f488e895572eec1ace487a3eaa324fe1d8e3b395e6c5e3645/merged

[11:55:28] 0 ✓ (3.3ms)
root@discourse:/var/discourse #

我爱你们。我爱 Discourse。我与这个产品紧密相连,并打算在可预见的未来一直使用它。

但是,呃……为什么。为什么现在是 2025 年,我还在自己动手管理 launcher cleanup?为什么镜像管理不是 launcher 的固有功能?

再说一遍,我爱你们。我选择 Discourse 作为 SCW 的评论系统,是因为我信任你们构建的东西,并且我喜欢使用它。但是,呃……我 AMI 的启动卷有一半被无用的垃圾占用了,这些垃圾本可以——至少如果我理解技术方面的话——被自动管理。

我不是在抱怨——只是在离开管理员职位几年后再次回来检查。我喜欢 AI 垃圾邮件检测和 AI 审核,尤其是在一个天气论坛上,关于气候变化的政治敏感帖子(无论是支持还是反对)是常有的事。感谢你们所做的一切 <3

7 个赞

很高兴看到你回来了,李!

本周我的自托管网站也发生了同样的事情。备份失败了,我因为在外无法使用笔记本电脑,所以就放任了一周左右。一回来我就运行了清理,恢复了大量磁盘空间,备份也能够再次运行了。

4 个赞

你好,很高兴你又回来了!

其中一部分原因是它“足够好”——我们不在内部托管中使用它,因为我们经常轮换容器+镜像,所以我们的节奏与自托管网站的外观大不相同。

这里的另一个解释是,在启动器和 Docker 之间,没有哪个系统愿意承担数据删除计划的全部责任——删除用户数据的计划应完全由用户控制。

我在自托管网站上遇到了一些问题,清理*也会清理我需要构建的新 Discourse 基础,从而导致了一个糟糕的鸡生蛋还是蛋生鸡的问题。如果由于自动运行而没有注意到这一点,可能会有点麻烦。

一个简单的建议可能是,自行承担风险,通过 cronjob 运行 docker system prunelauncher clean。可以吗?

6 个赞

因为有时它会删除你唯一可用的容器。
你可以在运行重建之前,趁所有可用的容器还在运行时,每次都运行它。

1 个赞

好主意——有时最简单的答案就是最好的。谢谢您,我将照办!

当通过 cron 执行 ./launcer cleanup 时,我/我们该如何回答“yes”?我的意思是,对我来说,容器不是什么大问题,但孤立的镜像是个问题。

1 个赞

没有理由通过 cron 来执行此操作,只有在您使用 launcher 构建新镜像时才需要构建新镜像。您只需要在构建镜像之前或之后执行此操作。

如果您想避免 launcher 的提示,可以使用上面建议的 docker 命令。这是一个(但请阅读手册以了解其作用,确保它是您想要的):

/usr/bin/docker image prune -a -f
1 个赞

我得去看看。谢谢。

我不知道还有什么别的,但今天,又一次,重建失败了,因为我只剩下不到 5 GB 的可用空间。当然,cleanup 解决了问题,这只是有点烦人。不过,我还是希望不要再遇到这种情况。

这充分说明了我对 Docker 的理解有多么肤浅 :joy: 如果我理解得没错,那些因为没有被任何容器使用而被删除的镜像,根本就不是我一直以为的那种图片 :face_with_peeking_eye: :rofl:

2 个赞

直接的答案是你可以运行 echo y | launcher cleanup 来提前发送“y”。

间接的答案是实际的 launcher cleanup(在之后)等同于以下两个命令:

docker container prune --force --filter until=24h
docker image prune --all --force --filter until=24h

我认为你指的是删除旧的 postgres 数据目录的提示:

rm -rf /var/discourse/shared/standalone/postgres_data_old*

你可以取消对 launcher 的依赖,直接使用这些命令。

2 个赞

实际上,我指的是我在运行 ./launcher cleanup 时遇到的问题。首先,它会移除所有已停止的容器。然后,它会提供删除所有未被至少一个容器使用的镜像的选项——而这部分是我节省空间的原因,上次节省了近 40 GB。

这就是为什么我一直很困惑,因为我不明白为什么会有这么多孤立的镜像(jpg、png 等)。但我们这里讨论的是完全不同的镜像,对吧?

是的,我每周至少重建两次。或者说最近,当我追踪一个行为不端的插件时,我进行了至少十几次重建。

它每次都会生成新镜像吗?我不知道。

每次重建都是一个新映像,如果不清理,它们就会累积。

Launcher 目前只在磁盘空间不足时运行其他命令时才提示清理。

1 个赞

如果您使用脚本运行它,这可能会很麻烦;脚本将一直挂起等待响应(我想这就是为什么要把 yes 管道传输给它)。如果磁盘剩余空间少于 10GB,我就会进行清理。

1 个赞

这或许是一个可能对我有用的变通方法。在此提出,以防对他人也有帮助。

我正在考虑在 /etc/docker/daemon.json 中添加一个 data-root 设置,看看这是否能强制 Docker 将其镜像(在这种情况下是 Discourse 的镜像,因为该服务器上没有托管其他东西)放置在一个不太关键的位置,从而不会耗尽我的启动卷。

在 meta 上搜索关于此的过往帖子,我找到了几个 结果,但它们并没有真正告诉我太多信息。在我导致我的生产 Discourse 实例崩溃成一堆冒烟的废墟之前,我想问一下这是否可行 :slight_smile:

{“content”:“[quote="Lee_Ars, post:13, topic:378204"]\n我正在考虑在 /etc/docker/daemon.json 中添加一个 data-root 设置,看看这是否能强制 docker 将其镜像(在这种情况下是 Discourse 的镜像,因为盒子上没有托管其他东西)放在一个不太关键的位置,这样就不会炸毁我的启动卷。\n\n[/quote]\n\n我采用了另一种方法,将一个单独的文件系统挂载到了 /var/lib/docker\n\n在我的例子中,出于非常特定于站点的原因,我为 /var/discourse/shared/var/discourse/shared/data/var/discourse/shared/app/uploads/default/original/var/lib/docker 中的每一个都选择了单独的文件系统——但如果你只想让 /var/discourse 成为一个单独的文件系统,你也许可以创建目录 /var/discourse/share/docker 并将其绑定挂载到 /var/lib/docker(显然,在系统静止并根据需要移动文件的情况下进行此操作)。”,“target_locale”:“zh_CN”}

4 个赞

这比捣鼓 Docker 的内部更好!谢谢!!

1 个赞

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.