致歉
比赛开始后约一小时内,比赛平台因不明原因(目前来看应为平台程序负载过高)导致平台响应速度极慢。如果有参赛的师傅读到这篇文章,再次向您表达歉意。
前传
尽管我常常自称运维,但是我确实没有实打实的运维过 CTF 比赛,更没有运维过 k8s 集群。这几年协会不少比赛的运维也都是由凌武学长负责。
先前 HGAME Final 2025 虽已有相关经验,但是 Final 毕竟是,线下赛,校内赛,当时也没出锅,况且出锅了就大不了走到前面给大家鞠躬。
今年 D^3CTF 的准备时间相较往年有所减少(两个月 -› 一个月)。运维任务我一开始以为不会在 Vidar-Team 手中,结果最后还是落到我们手里。
餐前
首先,毋庸置疑使用了 ret2shell 作为 CTF 平台。首先他是 D^3 成员写的平台,其次就算 ret2shell 有一些小瑕疵,但是其仍比大多数平台更加好用。
ret2shell 需要跑在 k8s 系平台上,考虑 HGAME 时校内网络稀烂,我们决定全量上云。
由于路径依赖,我仍然选择腾讯云。就在我已经在腾讯云一台机器上装好 k3s 时,队长告诉我我们已经成功要到了 Google Cloud Platform 的赞助。那云平台也就自然需要使用 GCP 了。
我一登录 GCP 就好像刘姥姥进了大观园。虽然国内的云平台的应用名也都挺花里胡哨,但是一般还是可以看最后几个字确定的。但是 GCP 上来一个 “Compute Engine” 给我干晕了,这在引擎什么呢?
不过这倒是我的英文水平不济的问题。我们现在可以创建虚拟机了,让我们试试水。等等,为什么没有带宽选项?查了一下,原来是自动配置的,谷歌还是太有带宽了。
随后我开始在 GCP 上乱翻,发现了一个叫 GKE 的东西,竟然谷歌有全自动托管的 k8s 集群,为什么不用呢?
我一开始尝试使用 autopilot 集群,结果发现这个模式下我甚至不能 createRole,于是转而使用传统集群。
有了 k8s 集群,我很快部署了平台,现在的问题是,如何保证平台能够在赛时的压力下正常运行。
再结合往年宣传和学长经验后,我得到了如下的基本信息:
- 平台经过了 miniL 和 HGAME 的考验,应该不用担心。
- 靶机数量峰值应当在 500 左右。
- cpu:memory 应该在 1:2 左右。(单位 核:GiB)
有了这些假设,我认为平台可以在 8 个专门用来跑靶机,1 个专门用来跑平台的机器上存活下来。
k8s 内部的 NodePort 是互通的,由于用于跑靶机的 vm 有可能会动态扩缩。为了保证靶机 IP 的稳定性,我决定将靶机出口 IP 放到用于跑平台的机器上。
我开了两个节点组,一个动态扩缩的节点组,用于靶机,一个单个节点的节点组,用于平台。
正餐
平台几乎平稳的跑到了比赛日的到来,除了 ret2shell 在赛前一天抽风开始乱发邮件(事后查明是对消息队列的使用不当),别的没有什么问题。
然后比赛一开始,爆炸了。海量的 timed out。我当然要开始火线救援,但是 kubectl top 一看,欸,数据库什么的都没有到限额占用,但是平台占用很高。
看了数据库和平台的 log,只有大量的请求过慢。这就很奇怪了。
我先尝试给平台增加了限额,但是情况还是没有改变。我意识到是平台本身需要更多的资源,但是我们没有足够的 CPU 配额用于新的机器了。为此我紧急关闭了一台用于靶机的机器,并增加新的用于平台的机器。同时,我请学长帮我在 GCP 上申请扩大配额(GCP 申请扩大配额需要写小作文)。
在给平台本身更多资源后,问题基本解决。大约 15min 后,CPU 配额也下来了,我重整完用于平台的机器后,注意到靶机资源略显紧张。
观察图表发现 CPU:内存 根本不是 1:2,其实 1:8 才差不多。同一时间也注意到动态扩容不能及时生效。我采用滚动更新的方式创建了新的节点组,并逐步淘汰了老的节点组。
另一方面,我们担心大量的靶机请求会拖累平台机器,建立 2 个专门用来中转的机器。
自此,集群的状态是 8+2+2,靶机+中转+平台。平台进入稳定状态。我注意到平台稳定在 400-450 台靶机很长时间,直到开赛后 3h 才开始回落,最终稳定在 120 台左右。
甜点
第二天的时候,伴随比赛的发展,平台的反作弊系统开始生效。为此发生了很多一言难尽的事情,这并非本文的要点。
平台平稳到达比赛结束,为了节省费用,我改成了 1+1+2 的状态,比赛正式结束。
但是在 writeup 收集时,我们很后面才注意到,Google Groups 不能接受超过 8MiB 的附件。我们建议选手上传到网盘作为解决方案。
现在来看,可能还是需要一个正经可控的邮箱平台,或者提供一个上传 writeup 的平台。
总结
其实本来是想在文末卖惨的,因为运维 D^3 本就赶鸭子上架,尽管已经努力,还是免不了唉喷。但话又说回来,既然接下了锅就要负责到底,自己水平不够考虑不够导致这样那样的问题也是不争的事实。只能希望被我们这些小毛小病影响到的师傅不要介怀于此。
现在回过头来看,有几点需要指出:
- 压测基于估算,估算基于假设。但事实往往和假设有出入,一旦有较大出入就会出事故。
比如我事前对平台,参赛人数的假设就完全错误,最终导致了平台过载。运维能做的只有不断改善假设,并在结构上提供更好的抗压条件。
理论上,ret2shell 可以有多个实例,后续应当考虑多实例负载均衡来缓解问题。 - WriteUP 收集也许还是应当摒弃传统的邮件方式,改由平台或者独立的网站承担。
现在想要一个可控的邮件系统非常困难,然而如果只是通过网页收取用户上传 PDF,问题会简单许多。 - 虽然我曾开玩笑说:「一切问题都是 ret2shell 有反作弊机制导致的」。但没有道理对违规行为屈服,后续比赛的反作弊压力肯定也会很大,只能希望后续的运营和运维能够妥善抗压了。
- CTFTime 上的排名是上传后不可修改的…这在本文写后才发现。
Ref
- https://baimeow.cn/posts/projects/hgame25-op 从 HGAME2025 运维,聊聊学校战队 CTF 独立办赛