background
8
X
Q
>
r
p
A
U
w
/
/
$
7
7
H
B
Z
d
8
m
f
:
m
H
P
}
l
C
e
b
v
$

favicon
favicon
回归终端
 

日常维护

Reverier-Xu at 2026-01-28 11:20:46 3.8+ R2SPL

本章记录回归终端上线后的日常维护方式,覆盖集群内部署、ret2boot 部署、裸机 / systemd 部署和 Docker Compose 部署。涉及 Kubernetes 的命令主要用于平台运行在集群内、或平台需要排查动态题目环境的场景;裸机和 Docker Compose 部署需要把平台服务日志、进程管理和数据目录命令按实际路径替换。

涉及 Kubernetes / Helm 的命令默认 Helm release 名为 ret2shell,平台 namespace 为 ret2shell-platform,题目 namespace 为 ret2shell-challenge。如果你的部署使用了外部 PostgreSQL、Valkey、NATS、registry 或 VictoriaLogs,对应组件的日志、升级和备份应在外部系统中完成。

维护时应把部署配置、数据库备份、平台数据目录备份和操作记录放在一起管理。部署配置可能是 values.production.yaml、ret2boot 配置、.envdocker-compose.yml/etc/ret2shell/config.toml。不要直接修改 Kubernetes 中由 Helm 生成的对象,也不要在数据目录中手动删除、移动、改名或改权限,除非你已经确认这些目录的用途并做好了可恢复备份。

例行巡检

日常运维可以关注以下状态:

# 仅在集群内部部署方案和 ret2boot 方案中看这些
helm status ret2shell -n ret2shell-platform
helm history ret2shell -n ret2shell-platform
kubectl -n ret2shell-platform get pods,svc,ingress,pvc -o wide
kubectl -n ret2shell-platform get statefulset,deploy -o wide
kubectl -n ret2shell-platform get events --sort-by=.lastTimestamp
 
# 使用裸机部署时
## 查看各个组件的情况也可以使用上述两个命令,将服务名称替换成各个组件的名称
systemctl status ret2shell.service
## 串流日志
journalctl -xeu ret2shell.service -f
 
# 使用 Docker Compose 部署时,在部署文件目录内
docker compose ps
docker compose logs -f ret2shell
 
# 如果你开启了集群功能,无论使用哪种部署方式,最好都要例行巡检一下题目容器的状况
kubectl -n ret2shell-challenge get pods,svc,networkpolicy -o wide
kubectl -n ret2shell-challenge get events --sort-by=.lastTimestamp
kubectl get nodes -o wide
kubectl top nodes
kubectl top pods -A

如果 kubectl top 不可用,说明集群没有安装 Metrics Server,或 Metrics Server 当前异常。它不影响平台基础功能。

ret2shell-platform 中应重点关注:

资源正常状态常见异常
statefulset/ret2shell-platform1/1 就绪配置错误、数据库不可达、缓存不可达、探针失败、镜像拉取失败。
statefulset/ret2shell-postgresql内置数据库启用时 1/1 就绪PVC 未绑定、磁盘满、数据库启动失败、主版本升级不兼容。
statefulset/ret2shell-valkey单实例或主从实例就绪密码不一致、AOF 损坏、内存不足、PVC 问题。
statefulset/ret2shell-natsNATS JetStream 实例就绪JetStream 存储不可写、token 不一致、集群路由异常。
deployment/ret2shell-registry内置 registry 启用时 Pod 就绪镜像层存储满、外部访问地址配置错误、节点无法拉取题目镜像。
statefulset/ret2shell-victoria-logs内置 VictoriaLogs 启用时 1/1 就绪日志盘满、平台无法写入集中日志、查询超时。
pvc/*全部 BoundStorageClass 不存在、Local PV 节点不匹配、磁盘空间不足。

ret2shell-challenge 中应重点关注题目 Pod 是否大量处于 PendingImagePullBackOffCrashLoopBackOffOOMKilled 或长期 Terminating。这些状态通常分别对应资源不足、镜像拉取失败、题目进程崩溃、内存限制过低或节点/网络插件异常。

平台日志

平台日志有三种来源:

  1. Web 管理后台的 /admin/logs 页面。它查询 VictoriaLogs,适合按时间、等级、账号、来源 IP、trace id 和 LogSQL 条件检索。
  2. Kubernetes stdout。它来自容器标准输出,适合服务无法进入后台或 VictoriaLogs 不可用时排障。
  3. 平台本地日志文件。Helm 部署中默认位于平台 Pod 内的 /var/lib/ret2shell/log,可以从 /admin/logs 下载,也可以进入 Pod 只读检查。

后台日志页面常用字段:

字段用途
LEVEL过滤 DEBUGINFOWARNERROR。比赛期间一般先看 WARNERROR
SIZE限制返回条数。问题发生时间明确时可以先用 100,再放宽。
Trace ID追踪一次请求或后台任务。前端请求、后台 worker 和部分事件会携带同一个 trace。
Account按用户账号过滤请求日志。选手反馈问题时优先填写这个字段。
IP按来源 IP 过滤。需要确认反向代理正确传递真实 IP,否则这里可能只看到网关地址。
Log Query SQL直接输入 VictoriaLogs LogSQL。填写后其他结构化过滤项会让位给自定义查询。

Kubernetes 侧查看平台日志:

kubectl -n ret2shell-platform logs statefulset/ret2shell-platform -c platform --tail=200
kubectl -n ret2shell-platform logs statefulset/ret2shell-platform -c platform -f
kubectl -n ret2shell-platform logs -l app.kubernetes.io/component=platform --since=1h

查看平台本地日志文件列表和容量:

kubectl -n ret2shell-platform exec statefulset/ret2shell-platform -c platform -- \
  sh -lc 'ls -lh /var/lib/ret2shell/log && du -sh /var/lib/ret2shell/log'

平台本地日志按天写入,文件名形如 ret2shell.2026-01-29.log。开启日志压缩后,旧日志会归档为 ret2shell.YYYY-MM.log.tar.gzret2shell.YYYY.log.tar.gz。不要手动删除正在写入的当天日志;需要控制保留量时,修改 platform.config.logging.filesKept 或接入外部日志保留策略。

组件日志

各组件都带有 app.kubernetes.io/component 标签。排障时先用标签找 Pod,再按组件查看日志。

kubectl -n ret2shell-platform get pods --show-labels
kubectl -n ret2shell-platform get pods -l app.kubernetes.io/component=postgresql -o wide

常用日志命令:

kubectl -n ret2shell-platform logs -l app.kubernetes.io/component=platform --tail=200
kubectl -n ret2shell-platform logs -l app.kubernetes.io/component=postgresql --tail=200
kubectl -n ret2shell-platform logs -l app.kubernetes.io/component=valkey --tail=200
kubectl -n ret2shell-platform logs -l app.kubernetes.io/component=nats --tail=200
kubectl -n ret2shell-platform logs -l app.kubernetes.io/component=registry --tail=200
kubectl -n ret2shell-platform logs -l app.kubernetes.io/component=victoria-logs --tail=200

组件启用 metrics sidecar 时,需要指定容器名:

kubectl -n ret2shell-platform logs <pod-name> -c metrics --tail=200

题目容器日志位于 ret2shell-challenge

kubectl -n ret2shell-challenge get pods -o wide
kubectl -n ret2shell-challenge logs <pod-name> --tail=200
kubectl -n ret2shell-challenge logs <pod-name> -c <container-name> --tail=200
kubectl -n ret2shell-challenge logs <pod-name> -c <container-name> --previous --tail=200

--previous 用于查看上一次崩溃容器的日志,对 CrashLoopBackOffOOMKilled 很有用。如果题目镜像没有 shell,kubectl exec 可能不可用,此时应优先依赖 describe、事件和容器日志。

基础集群组件通常在 kube-system。K3s 部署中常见组件包括 CoreDNS、local-path-provisioner、metrics-server、Traefik 和 kube-proxy 相关组件:

kubectl -n kube-system get pods,svc,deploy,daemonset,configmap -o wide
kubectl -n kube-system get events --sort-by=.lastTimestamp
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=100
kubectl -n kube-system logs -l app=local-path-provisioner --tail=100

如果平台入口使用独立的 Ingress Controller,例如 ingress-nginx namespace,需要到对应 namespace 查看 Ingress Controller 的 Pod、Service 和日志。

数据目录

Helm 部署中,平台服务把 platform.persistence 挂载到 /var/lib/ret2shell。这个目录保存平台文件态数据,应和 PostgreSQL 一起备份。

目录用途审计建议
/var/lib/ret2shell/bucket比赛、题目、附件、checker、环境配置、题目仓库和 Git 记录。只做容量、文件数量和备份完整性检查。不要手动改题目文件,题目发布状态和数据库记录需要保持一致。
/var/lib/ret2shell/media用户上传图片、平台媒体文件和缩略图。关注容量增长和异常大文件。不要绕过平台接口删除媒体,否则数据库中的引用可能悬空。
/var/lib/ret2shell/log平台本地结构化日志和归档日志。可只读查看、下载和备份。删除策略应通过配置或日志系统完成。
/var/lib/ret2shell/captures题目环境交互捕获数据。开启 enableCapture 后可能增长较快。关注容量和保留周期。当前后台捕获页面未完成时,不要直接把目录当作稳定 API 使用。

只读审计命令:

kubectl -n ret2shell-platform exec statefulset/ret2shell-platform -c platform -- \
  sh -lc 'find /var/lib/ret2shell -maxdepth 2 -type d -print'
 
kubectl -n ret2shell-platform exec statefulset/ret2shell-platform -c platform -- \
  sh -lc 'du -sh /var/lib/ret2shell/* 2>/dev/null'
 
kubectl -n ret2shell-platform exec statefulset/ret2shell-platform -c platform -- \
  sh -lc 'find /var/lib/ret2shell/bucket -mindepth 1 -maxdepth 1 -type d | wc -l'

使用本地静态 PV 时,宿主机上还会有一组 PV 目录。默认模板使用 /srv/ret2shell/backend/storage 作为根目录:

宿主机目录对应组件保存内容
platform-pv1platform.persistence平台 /var/lib/ret2shell 数据。
database-pv1postgresql.persistencePostgreSQL 数据文件。
cache-pv1valkey.persistenceValkey AOF 和运行数据。
queue-pv1nats.persistenceNATS JetStream 存储。
registry-pv1registry.persistence题目镜像层和 manifest。
logs-pv1victoriaLogs.persistenceVictoriaLogs 索引和日志数据。

这些目录由对应容器维护。不要在宿主机上手动 rmmvchown、编辑数据库文件或清理镜像层。需要迁移或清理时,应先停写、备份,再使用对应组件支持的工具完成。

宿主机侧只读审计可以使用:

sudo du -sh /srv/ret2shell/backend/storage/*
sudo find /srv/ret2shell/backend/storage -maxdepth 2 -type d -print

如果磁盘即将耗尽,优先判断增长来源:题目镜像看 registry-pv1,平台附件和题目仓库看 platform-pv1/bucket,媒体看 platform-pv1/media,平台日志看 platform-pv1/log,集中日志看 logs-pv1。不要用删除目录的方式“腾空间”,否则后续恢复成本通常更高。

配置变更

回归终端有两类配置来源:

来源位置生效方式
部署配置values.production.yaml,由 Helm 渲染成 Secret、ConfigMap、StatefulSet、Service、Ingress、PVC 等资源。修改 values 后执行 helm upgrade。生成的 config.tomlblocked.txt 会触发平台 Pod 滚动重建。
运行时配置Web 管理后台,例如 /admin/edit/admin/email/admin/traffic/admin/lifecycle写入数据库并清理平台配置缓存,通常不需要重启平台。

部署配置适合管理数据库连接、缓存连接、NATS、registry、VictoriaLogs、外部域名、入口、PVC、镜像版本、资源限制、节点选择器、RBAC、日志目录等基础设施项。运行时配置适合管理平台展示信息、邮件设置、全局 traffic 脚本、全局 lifecycle 脚本和默认题目节点选择器。

查看当前 Helm values 和渲染后的平台配置:

helm get values ret2shell -n ret2shell-platform > values.installed.yaml
 
kubectl -n ret2shell-platform get secret ret2shell-config \
  -o jsonpath='{.data.config\.toml}' | base64 -d
 
kubectl -n ret2shell-platform get configmap ret2shell-blocked -o yaml

修改生产配置的常规流程:

cd ~/ret2shell-deploy
 
helm template ret2shell "./ret2shell-${R2S_VERSION}.tgz" \
  -n ret2shell-platform \
  -f values.production.yaml \
  > rendered.yaml
 
helm upgrade --install ret2shell "./ret2shell-${R2S_VERSION}.tgz" \
  -n ret2shell-platform \
  -f values.production.yaml \
  --dry-run
 
helm upgrade --install ret2shell "./ret2shell-${R2S_VERSION}.tgz" \
  -n ret2shell-platform \
  -f values.production.yaml \
  --wait \
  --timeout 15m

发布后检查:

helm status ret2shell -n ret2shell-platform
kubectl -n ret2shell-platform rollout status statefulset/ret2shell-platform --timeout=5m
kubectl -n ret2shell-platform get pods,pvc,svc,ingress -o wide
helm test ret2shell -n ret2shell-platform --logs

如果设置了 platform.config.existingSecretplatform.blocked.existingConfigMap,Helm 只知道对象名称,不会自动感知对象内容变化。修改外部 Secret 或 ConfigMap 后,需要显式重启平台 Pod:

kubectl -n ret2shell-platform rollout restart statefulset/ret2shell-platform
kubectl -n ret2shell-platform rollout status statefulset/ret2shell-platform --timeout=5m

敏感词文件对应 /etc/ret2shell/blocked.txt,Helm values 中是 platform.blocked.content。建议把敏感词列表作为配置文件管理,随 values 一起审阅和发布,不要直接进入 Pod 修改挂载文件。

组件升级

升级流程必须先按安装方式区分。不要把 ret2boot、Helm、systemd 和 Docker Compose 的命令混用。

安装方式升级入口适用范围
手动集群内部署Helm Chart 和 values.production.yaml平台服务、内置 PostgreSQL、Valkey、NATS、registry、VictoriaLogs 和 PVC。
通过 ret2boot 部署ret2boot update由 ret2boot 记录和管理的 Kubernetes、Helm、网关、平台和内置基础组件资源。
纯裸机部署systemd、二进制、配置文件和系统包平台服务、前端静态文件、本机数据库、本机缓存、本机队列、本机 registry。
Docker Compose 部署.envdocker-compose.yml 和镜像Compose 管理的平台服务和基础组件,外置 Kubernetes 只运行题目容器。

无论使用哪一种方式,升级前都应完成三件事:

  1. 保存当前部署配置和版本记录。
  2. 备份 PostgreSQL 与平台数据目录。
  3. 确认回滚路径。数据库迁移、数据库主版本升级、组件存储格式变化和 PVC 数据变化通常不能靠“回滚程序版本”恢复。

平台数据目录备份应按你的存储系统完成。使用本地静态 PV 时,可以在停写窗口对宿主机 PV 目录做备份;使用云盘、Longhorn、Rook Ceph、NFS CSI 等存储时,应使用对应快照或备份能力。

一般来说不推荐使用本地静态 PV 之外的 PV 来存储回归终端的数据,回归终端使用 Git 进行比赛文件管理,对于网络文件系统来说,Git 操作通常压力会很大。

手动集群内部署

手动集群内部署使用 Helm 管理平台和内置基础组件。升级时只改 Chart、values 和镜像版本,不要直接编辑 Helm 生成的 StatefulSet、Secret、ConfigMap 或 PVC。

升级前保存 Helm 状态和数据库备份:

cd ~/ret2shell-deploy
 
helm get values ret2shell -n ret2shell-platform > "values.installed.$(date +%F).yaml"
helm history ret2shell -n ret2shell-platform > "helm-history.$(date +%F).txt"
 
DB_POD="$(kubectl -n ret2shell-platform get pod -l app.kubernetes.io/component=postgresql -o jsonpath='{.items[0].metadata.name}')"
kubectl -n ret2shell-platform exec "$DB_POD" -- \
  sh -lc 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' \
  > "ret2shell-postgresql.$(date +%F).dump"

各组件的升级入口:

组件Helm values 字段说明
平台服务platform.image.tagplatform.image.digest,以及 Chart 版本。平台 StatefulSet 是单副本,升级会有短暂不可用。运行中的题目 Pod 不会因为平台 Pod 重建而自动删除,但经平台代理的 WebSocket 流量会中断。
PostgreSQLpostgresql.image.tag小版本升级前也要备份。主版本升级不要只改镜像 tag,应按 PostgreSQL 主版本升级流程处理,必要时新建实例后 pg_dump / pg_restore
Valkeyvalkey.image.tag单实例会重启一次;复制模式按 StatefulSet 顺序滚动。确认密码和持久化配置不变。
NATSnats.image.tagJetStream 数据在 PVC 中。多副本时注意集群路由和磁盘空间。
Registryregistry.image.tag默认策略是 Recreate。镜像层在 registry PVC 中,升级前关注磁盘容量和存储兼容性。
VictoriaLogsvictoriaLogs.image.tag日志查询短暂不可用不影响平台写本地日志。升级前确认存储格式兼容性和可用空间。

升级平台 Chart:

R2S_VERSION="<new-version>"
 
curl -fLO "https://github.com/ret2shell/ret2shell/releases/download/${R2S_VERSION}/ret2shell-${R2S_VERSION}.tgz"
curl -fLO "https://github.com/ret2shell/ret2shell/releases/download/${R2S_VERSION}/ret2shell-${R2S_VERSION}.tgz.sha256"
 
EXPECTED_SHA256="$(awk '{print $1}' "ret2shell-${R2S_VERSION}.tgz.sha256")"
ACTUAL_SHA256="$(sha256sum "ret2shell-${R2S_VERSION}.tgz" | awk '{print $1}')"
test "$EXPECTED_SHA256" = "$ACTUAL_SHA256"
 
helm show values "./ret2shell-${R2S_VERSION}.tgz" > "values.upstream.${R2S_VERSION}.yaml"

把新默认 values 与当前 values.production.yaml 对比后,更新生产 values,再渲染和试运行:

helm template ret2shell "./ret2shell-${R2S_VERSION}.tgz" \
  -n ret2shell-platform \
  -f values.production.yaml \
  > rendered.yaml
 
helm upgrade --install ret2shell "./ret2shell-${R2S_VERSION}.tgz" \
  -n ret2shell-platform \
  -f values.production.yaml \
  --dry-run

确认渲染结果和 dry-run 输出后发布:

helm upgrade --install ret2shell "./ret2shell-${R2S_VERSION}.tgz" \
  -n ret2shell-platform \
  -f values.production.yaml \
  --wait \
  --timeout 15m
 
helm status ret2shell -n ret2shell-platform
kubectl -n ret2shell-platform rollout status statefulset/ret2shell-platform --timeout=5m
kubectl -n ret2shell-platform get pods,pvc,svc,ingress -o wide
kubectl -n ret2shell-platform get events --sort-by=.lastTimestamp
helm test ret2shell -n ret2shell-platform --logs

回滚 Helm release:

helm history ret2shell -n ret2shell-platform
helm rollback ret2shell <revision> -n ret2shell-platform --wait --timeout 15m

回滚只能回滚 Kubernetes 资源和 values。已经执行过的数据库迁移、外部组件升级、PVC 数据格式变化不会自动回退。

通过 ret2boot 部署

ret2boot 部署的环境应优先使用 ret2boot 升级。这个流程不是无人值守自动升级,需要管理员在控制平面节点上执行命令并观察结果。没有保留 ret2boot 安装状态、或后来改成手工 Helm 管理的环境,应按“手动集群内部署”处理。

ret2boot 的升级命令会读取已保存的安装状态,通常包括 /etc/ret2shell/ret2boot.toml/etc/ret2shell/ret2boot-platform-values.yaml。升级过程中,它会检查集群引导资源,确保 Helm CLI 可用,下载最新的 Ret2Shell Helm Chart,校验 sha256,生成 ret2boot 管理的 values、平台运行配置、敏感词文件和存储资源清单,然后执行 Helm 升级并重启已有的平台工作负载。命令只支持在 ret2boot 管理的控制平面安装上使用。

ret2boot 启动时可能会提示有新的 ret2boot 版本并下载到缓存,但当前进程仍会使用已经启动的版本继续执行。需要先升级 ret2boot 自身时,应先替换 /usr/local/bin/ret2boot,再执行平台升级:

ret2boot --version
 
R2B_VERSION="$(curl -fsSL https://api.github.com/repos/ret2shell/ret2boot/releases/latest | sed -n 's/.*"tag_name": "\(.*\)".*/\1/p' | head -n1)"
R2B_TARGET="x86_64-unknown-linux-musl"
 
curl -fLO "https://github.com/ret2shell/ret2boot/releases/download/${R2B_VERSION}/ret2boot-${R2B_VERSION}-${R2B_TARGET}.tar.gz"
curl -fLO "https://github.com/ret2shell/ret2boot/releases/download/${R2B_VERSION}/ret2boot-${R2B_VERSION}-${R2B_TARGET}.tar.gz.sha256"
 
EXPECTED_SHA256="$(awk '{print $1}' "ret2boot-${R2B_VERSION}-${R2B_TARGET}.tar.gz.sha256")"
ACTUAL_SHA256="$(sha256sum "ret2boot-${R2B_VERSION}-${R2B_TARGET}.tar.gz" | awk '{print $1}')"
test "$EXPECTED_SHA256" = "$ACTUAL_SHA256"
 
tar -xzf "ret2boot-${R2B_VERSION}-${R2B_TARGET}.tar.gz"
sudo install -m 755 "ret2boot-${R2B_VERSION}-${R2B_TARGET}/ret2boot" /usr/local/bin/ret2boot
 
ret2boot --version

升级前先确认 GitHub 访问、GitHub CLI 登录、Helm release 状态和平台 Pod 状态。ret2boot 下载 release 资源时会读取 gh auth token --hostname github.com,如果没有可用 token,下载会失败。使用 ret2boot update 时,应确认 root 环境也能读取 GitHub CLI 登录状态。

sudo gh auth status --hostname github.com
sudo gh auth token --hostname github.com >/dev/null
helm status ret2shell -n ret2shell-platform
kubectl -n ret2shell-platform get pods,pvc -o wide
 
sudo cp /etc/ret2shell/ret2boot.toml "ret2boot.$(date +%F).toml"
sudo cp /etc/ret2shell/ret2boot-platform-values.yaml "ret2boot-platform-values.$(date +%F).yaml"

确认数据库备份和平台数据目录备份已经完成后,执行升级:

ret2boot update

执行完成后,ret2boot 会输出本次同步报告。常见变化包括 Helm release 不存在、Helm Chart 变化、平台工作负载规格变化、Helm values 变化、平台配置漂移已修正、敏感词配置漂移已修正、存储类状态变化等。如果没有需要应用的变化,报告会说明当前状态已经同步。

升级后检查:

helm status ret2shell -n ret2shell-platform
kubectl -n ret2shell-platform rollout status statefulset/ret2shell-platform --timeout=5m
kubectl -n ret2shell-platform get pods,pvc,svc,ingress -o wide
kubectl -n ret2shell-challenge get pods,svc -o wide
helm test ret2shell -n ret2shell-platform --logs

ret2boot 会维护这些生产路径:/etc/ret2shell/ret2boot.toml/etc/ret2shell/ret2boot-platform-values.yaml/srv/ret2shell/backend/config/config.toml/srv/ret2shell/backend/config/blocked.txt/srv/ret2shell/backend/deployments/0-init.yaml/srv/ret2shell/backend/deployments/1-volumes.yaml/srv/ret2shell/backend/deployments/7-platform.yaml/var/cache/ret2shell/ret2boot。不要手动改这些文件来绕过 ret2boot;如需变更平台配置,应先调整 ret2boot 使用的安装配置,再通过 ret2boot 或 Helm 流程应用。

ret2boot sync 适合用于修正配置漂移、重新渲染网关配置和同步 ret2boot 记录的 Chart,不等同于升级到最新平台版本。需要拉取最新 Ret2Shell release 时,应使用 ret2boot update

如果升级在 Helm 阶段失败,可以使用前面手动集群内部署流程中的 helm historyhelm rollback 查看并回滚 release。如果失败发生在 Helm 升级前,先检查错误输出、GitHub 访问、gh auth 状态、Chart 缓存目录和 /etc/ret2shell/ret2boot.toml

纯裸机部署

纯裸机部署由 systemd 管理平台服务和本机基础组件。升级时不要使用 Helm 或 ret2boot;应按系统服务边界分别处理平台二进制、前端静态文件、配置文件和基础组件。

升级前备份数据库、配置和平台数据:

sudo install -d -m 0750 -o ret2shell -g ret2shell /var/lib/ret2shell/backups
 
sudo -iu postgres pg_dump -Fc ret2shell > "/var/lib/ret2shell/backups/ret2shell.$(date +%F).dump"
sudo tar -C / -czf "/var/lib/ret2shell/backups/ret2shell-config.$(date +%F).tar.gz" etc/ret2shell
sudo tar -C /var/lib -czf "/var/lib/ret2shell/backups/ret2shell-data.$(date +%F).tar.gz" \
  ret2shell/bucket \
  ret2shell/media \
  ret2shell/captures

平台服务升级流程:

sudo systemctl stop ret2shell
 
sudo install -m 0755 r2s-server /usr/local/bin/r2s-server
sudo rsync -a --delete web/dist/ /usr/local/share/ret2shell/web/
 
sudo systemctl daemon-reload
sudo systemctl start ret2shell
sudo systemctl status ret2shell
journalctl -u ret2shell -f

启动后检查健康状态:

curl -fsS http://127.0.0.1:8080/api/ping

如果新版本需要新增配置字段,先更新 /etc/ret2shell/config.toml/etc/ret2shell/sensitive_word_list.txt,再启动平台。r2s-server 启动时会执行数据库迁移;迁移完成后再开放流量。

裸机部署中的 PostgreSQL、Valkey、NATS、registry、VictoriaLogs 和 Nginx 应按各自软件的升级文档处理。小版本升级通常由系统包管理器完成,主版本升级前必须阅读对应组件的迁移说明,并准备独立回滚方案。平台二进制可以换回旧版本,但已经完成的数据库迁移不会自动回退。

需要回滚平台程序时,停止 ret2shell,恢复旧的 /usr/local/bin/r2s-server/usr/local/share/ret2shell/web 和配置备份,再启动服务。只有确认数据库结构仍兼容旧版本时,才执行程序回滚。

Docker Compose 部署

Docker Compose 部署由 .envdocker-compose.yml 决定镜像版本。升级时不要使用 Helm 或 ret2boot;应先备份 Compose 配置、数据库和 volume,再拉取新镜像并重建相关服务。

升级前备份:

cd /opt/ret2shell
mkdir -p backups
 
docker compose exec -T database pg_dump -U ret2shell ret2shell > "backups/ret2shell.$(date +%F).sql"
tar -czf "backups/ret2shell-config.$(date +%F).tar.gz" .env docker-compose.yml config

只升级平台服务时,修改 .env 中的 R2S_VERSION,然后执行:

docker compose pull platform
docker compose up -d platform gateway
docker compose ps
docker compose logs -f platform

检查平台健康状态:

curl -fsS http://127.0.0.1/api/ping

如果同时升级 Compose 中的 PostgreSQL、Valkey、NATS、registry 或 VictoriaLogs 镜像,先确认对应 volume 数据格式兼容,再执行:

docker compose pull
docker compose up -d
docker compose ps

Compose 回滚通常是把 .env 中的 R2S_VERSION 改回旧版本,再执行 docker compose pull platform && docker compose up -d platform gateway。如果升级已经执行数据库迁移,或基础组件已经写入新格式数据,必须先确认旧版本仍兼容,必要时从升级前备份恢复数据库和 volume。

滚动升级时可以先降低业务压力:暂停比赛开放、通知用户短暂维护、避免在提交高峰或大量选手启动环境时升级。平台单副本意味着它不是无感升级;需要多组件升级时,建议先升级可独立验证的可选组件,再升级平台服务,最后执行健康检查和业务检查。

Namespace 排查

排查服务器问题时,先分别查看 ret2shell-platformret2shell-challengekube-system。不要只看 Pod 状态,事件、PVC、Service、Ingress 和节点状态通常能更快指向根因。

平台 namespace:

kubectl -n ret2shell-platform get all -o wide
kubectl -n ret2shell-platform get ingress,pvc,configmap,secret,serviceaccount,role,rolebinding -o wide
kubectl -n ret2shell-platform describe pod <pod-name>
kubectl -n ret2shell-platform describe pvc <pvc-name>
kubectl -n ret2shell-platform get events --sort-by=.lastTimestamp

题目 namespace:

kubectl -n ret2shell-challenge get pods,svc,networkpolicy -o wide --show-labels
kubectl -n ret2shell-challenge describe pod <pod-name>
kubectl -n ret2shell-challenge describe svc <service-name>
kubectl -n ret2shell-challenge get events --sort-by=.lastTimestamp

系统 namespace:

kubectl -n kube-system get pods,svc,deploy,daemonset,configmap -o wide
kubectl -n kube-system describe pod <pod-name>
kubectl -n kube-system get events --sort-by=.lastTimestamp

节点层面:

kubectl get nodes -o wide
kubectl describe node <node-name>
kubectl top node <node-name>
kubectl get pods -A -o wide --field-selector spec.nodeName=<node-name>

常见判断:

现象优先检查
平台 502 / 无法访问平台 Pod、Ingress / NodePort、网关日志、/api/ping、数据库和缓存连接。
登录态异常ret2shell-platform 日志、Valkey 日志、auth.signingKey 是否变更、浏览器时间和域名 HTTPS 配置。
提交后长时间无结果NATS、平台 worker 日志、PostgreSQL、题目 checker 日志、提交相关 trace。
在线环境无法启动ret2shell-challenge 事件、Pod 状态、镜像拉取、节点资源、默认 node selector、registry 外部地址。
在线环境能启动但无法连接Service、traffic 脚本、网关映射、NodePort / Ingress、安全组、题目容器实际监听端口。
大量 Pod Pending节点 CPU/内存/临时存储不足、node selector 没有匹配节点、PVC 或网络插件异常。
大量 ImagePullBackOffregistry 地址、节点到 registry 网络、image pull secret、镜像 tag 是否存在。

选手环境问题排查

选手反馈线上环境问题时,先记录四类信息:

  1. 选手账号、用户 ID、队伍 ID。
  2. 比赛 ID、题目 ID、题目名称。
  3. 问题发生时间、前端报错、访问地址或 traffic token。
  4. 是否所有人都有问题,还是单个用户 / 单个队伍有问题。

用户 ID 可以从后台用户管理页查看。题目 ID 和比赛 ID 通常能从后台题目页面、URL、日志字段或提交记录中确认。找到 ID 后,按标签定位 Pod:

# 按用户定位
kubectl -n ret2shell-challenge get pods \
  -l ret.sh.cn/user=<user_id> \
  -o wide --show-labels
 
# 按题目定位
kubectl -n ret2shell-challenge get pods \
  -l ret.sh.cn/challenge=<challenge_id> \
  -o wide --show-labels
 
# 按题目 + 用户定位个人实例
kubectl -n ret2shell-challenge get pods \
  -l ret.sh.cn/challenge=<challenge_id>,ret.sh.cn/user=<user_id> \
  -o wide --show-labels
 
# 按题目 + 队伍定位团队实例
kubectl -n ret2shell-challenge get pods \
  -l ret.sh.cn/challenge=<challenge_id>,ret.sh.cn/team=<team_id> \
  -o wide --show-labels
 
# 如果拿到了 traffic token
kubectl -n ret2shell-challenge get pod,svc \
  -l ret.sh.cn/traffic=<traffic_token> \
  -o wide --show-labels

Pod 名称形如 ret2shell-<challenge_id>-<user_id>-<timestamp>。Pod 和同名 Service 都带有 ret.sh.cn/* 标签;注解中保存了可读名称、端口和续期次数。

查看实例详情:

POD="<pod-name>"
 
kubectl -n ret2shell-challenge describe pod "$POD"
kubectl -n ret2shell-challenge get pod "$POD" -o jsonpath='{.metadata.labels}{"\n"}{.metadata.annotations}{"\n"}'
kubectl -n ret2shell-challenge get svc "$POD" -o yaml
kubectl -n ret2shell-challenge logs "$POD" --tail=200
kubectl -n ret2shell-challenge logs "$POD" --previous --tail=200

多容器题目需要指定容器:

kubectl -n ret2shell-challenge get pod "$POD" -o jsonpath='{.spec.containers[*].name}{"\n"}'
kubectl -n ret2shell-challenge logs "$POD" -c <container-name> --tail=200

需要进入容器时:

kubectl -n ret2shell-challenge exec -it "$POD" -c <container-name> -- sh

如果镜像里没有 sh,应使用题目镜像提供的调试方式,或者重新构建带调试工具的临时镜像在测试环境复现。不要在生产题目 Pod 中安装软件或修改文件来“临时修好”,这些修改不会持久化,也会让后续判断变得不可靠。

按现象继续判断:

现象排查方式常见处理
找不到 Pod选手可能未启动实例、实例已过期、平台启动实例失败。/admin/logs 中该账号和题目 ID 的日志,再让选手重新启动。
Pendingdescribe podEvents补节点资源、修正 ret.sh.cn/workload 节点标签、调整题目资源限制。
ImagePullBackOffdescribe pod 中的拉取错误。修正镜像 tag、registry 地址、节点访问权限或 image pull secret。
CrashLoopBackOfflogs --previous修题目启动命令、环境变量、端口、内存限制或依赖文件。
Running 但连不上查 Service、端口、traffic 脚本、网关和安全组。确认题目进程监听 env.toml 配置端口,确认 traffic 返回地址可从公网访问。
只有外网访问失败ret.sh.cn/internet 标签和网络策略。如果题目配置为不联网,外网访问失败可能是预期行为;否则检查 NetworkPolicy 和节点出站策略。
只有某个节点上的实例失败kubectl describe node 和该节点上的系统 Pod。临时把节点从题目调度范围移出,迁移或重启实例,再修节点网络、镜像缓存或磁盘问题。

平台日志中按账号或 trace 检索:

/admin/logs?account=<account>
/admin/logs?trace=<trace_id>

也可以在 Kubernetes stdout 中按时间窗口查看:

kubectl -n ret2shell-platform logs statefulset/ret2shell-platform -c platform --since=30m

处理选手实例时,优先使用平台页面或 API 停止、重启、续期实例。直接删除 Pod 只适合应急处理;如果手动删除,应同时确认同名 Service 是否已经清理,并在操作记录中写清楚原因、时间、Pod 名称和影响范围。

维护记录

每次生产维护建议记录以下内容:

项目记录内容
时间窗口开始时间、结束时间、是否影响比赛。
变更内容Chart 版本、镜像 tag、values diff、运行时配置变更。
备份数据库备份文件、平台数据备份或存储快照编号。
验证helm statusrollout statushelm test、平台页面、在线环境启动测试。
回滚方案Helm revision、数据库恢复点、外部组件恢复方式。