新手推荐
如果你是首次部署回归终端,建议先看 Docker Compose 部署。Compose 方案可以用于生产环境,配置路径更直接;当你需要让平台服务、基础组件和题目容器都进入 Kubernetes 统一调度时,再使用本页的集群内部部署方案。
本文介绍将回归终端、平台基础组件和题目容器统一部署在 Kubernetes 集群内部的流程。该模式适合单服务器单节点办赛,也适合已经具备稳定 Kubernetes 运维能力的多节点集群。
使用 ret2boot
新建单服务器生产环境可以考虑使用 ret2boot。ret2boot 会通过交互式流程完成系统预检、Kubernetes、Helm、网关和平台部署。本页适合手工维护 Helm values、接入已有 Kubernetes 集群或规划多节点调度的场景。 不过也请注意,在网络环境不佳、与 GitHub 和 Docker 源通信存在较大问题的情况下本工具可能会出现问题。如果你对系统运维并不熟悉,不知道网络错误导致安装进程中断后如何清理,还是推荐使用手动操作部署方案。
集群内部部署会创建两个固定 namespace:
| Namespace | 用途 |
|---|---|
ret2shell-platform | 运行平台服务、PostgreSQL、Valkey、NATS、registry 和 VictoriaLogs。 |
ret2shell-challenge | 运行平台动态创建的 challenge pods 和对应 Service。 |
平台工作负载以单副本 StatefulSet 运行。请保持平台副本数为 1,并通过节点标签、持久卷和备份策略保证该节点稳定。
安装 Helm
Helm 是 Kubernetes 的包管理工具。回归终端使用 Helm Chart 描述平台 StatefulSet、Service、Ingress、RBAC、ConfigMap、Secret、PVC 和各个基础组件。安装和升级时,Helm 会对比当前 release 与新的 Chart / values,并把差异应用到集群中。
Helm 3 官方提供了安装脚本。常规 Linux 环境可以直接执行下面的命令:
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash需要审阅脚本、使用二进制包或使用系统包管理器时,可以参考 Helm 3 Installing Helm。安装完成后检查版本和 Kubernetes 连接:
helm version
kubectl cluster-info
kubectl get nodes -o wide准备磁盘空间
正式部署前应先完成 环境准备中的资源估算。平台自身和基础组件的负载较低,主要资源压力来自 challenge pods。集群内部部署还需要为平台数据、数据库、缓存、队列、镜像仓库和日志组件准备持久化存储。
单场比赛的平台数据量通常可以控制在 20 GiB 以内。仅举办单场比赛时,100 GiB 磁盘通常可以覆盖系统、平台 PVC、镜像缓存、日志和少量备份。这个档位建议分配约 70Gi 给平台 PVC,剩余空间留给系统、k3s、容器运行时和镜像缓存。平台作为长期练习场持续维护时,磁盘建议从 1 TiB 起步。Chart 上游默认 PVC 容量偏向长期维护留量,单场比赛建议在 values.production.yaml 中按下表覆盖。
| 组件 | 单场比赛 100Gi 磁盘档位 | 长期练习场 1 TiB 档位 | 保存内容 | 规划建议 |
|---|---|---|---|---|
platform | 32Gi | 450Gi | bucket 仓库、附件、媒体文件、题目环境捕获文件、平台本地日志。 | 与题目数量、附件大小、选手交互捕获量相关。 |
postgresql | 10Gi | 150Gi | 平台主数据库。 | 与用户、队伍、提交、聊天、审计记录和配置数据相关。 |
valkey | 1Gi | 20Gi | 会话缓存、令牌、速率限制和临时状态。 | 复制模式下每个 Valkey Pod 都会申请同等大小 PVC。 |
nats | 1Gi | 20Gi | JetStream 消息持久化。 | 多副本模式下每个 NATS Pod 都会申请同等大小 PVC。 |
registry | 25Gi | 350Gi | 题目镜像层和 manifest。 | 使用内置 registry 时需要。镜像较多时应优先扩容这一项。 |
victoriaLogs | 1Gi | 10Gi | 平台集中日志。 | 日志留存周期较长时应提高容量,或接入外部日志系统。 |
单场比赛建议 PVC 合计为 70Gi,长期练习场档位合计约 1TiB。启用外部 PostgreSQL、Valkey、NATS、registry 或 VictoriaLogs 时,可以从总量中扣除对应组件。registry 和 VictoriaLogs 支持 disabled 模式;PostgreSQL、Valkey 和 NATS 是平台运行必需组件,应使用内置或外部服务。
K3s 默认提供 local-path StorageClass。单节点部署可以使用它作为起点:
kubectl get storageclass生产环境建议使用 SSD 承载 PVC,并保留额外空间给容器运行时镜像缓存、题目镜像拉取、challenge pods 临时存储和数据库备份。使用多节点集群时,平台和内置基础组件应绑定到稳定节点,题目容器应调度到题目节点。
示例节点标签:
kubectl label node platform-node ret.sh.cn/workload=platform
kubectl label node worker-1 ret.sh.cn/workload=challenge
kubectl label node worker-2 ret.sh.cn/workload=challenge拉取 Helm Chart
推荐从 GitHub Release 拉取已经打包好的 Helm Chart。下面的命令会读取最新 release,下载 Chart 和 checksum,并导出默认 values 作为配置起点:
sudo apt install -y jq
mkdir -p ~/ret2shell-deploy
cd ~/ret2shell-deploy
R2S_VERSION="$(curl -fsSL https://api.github.com/repos/ret2shell/ret2shell/releases/latest | jq -r '.tag_name')"
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.yaml
cp values.upstream.yaml values.production.yamlvalues.upstream.yaml 用来保留上游默认值,values.production.yaml 用来记录当前环境的实际配置。后续升级时继续维护 values.production.yaml,不要直接修改 values.upstream.yaml。
创建本地静态 PV
K3s 默认提供 local-path StorageClass。测试环境可以直接使用 local-path,生产环境的单节点部署建议创建静态 Local PV。静态 Local PV 会把平台、数据库、缓存、队列、registry 和日志分别绑定到宿主机固定目录,并使用 Retain 回收策略保留数据。
使用云厂商块存储、Longhorn、Rook Ceph、NFS CSI 等动态存储时,可以跳过本节,直接在 values.production.yaml 中填写对应 StorageClass。
从当前 release 拉取本地 PV 模板:
cd ~/ret2shell-deploy
curl -fL "https://raw.githubusercontent.com/ret2shell/ret2shell/${R2S_VERSION}/deploy/k8s/storage-local.yaml" \
-o storage-local.yaml模板中的 Local PV 通过 nodeAffinity 绑定到节点。先查看实际节点名,再替换模板中的默认节点名。多节点集群应选择运行平台和内置基础组件的稳定节点:
kubectl get nodes -o wide
NODE_NAME="$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')"
sed -i "s/ret2shell-node-master/${NODE_NAME}/g" storage-local.yaml按前面的磁盘规划调整 storage-local.yaml 中每个 PV 的 spec.capacity.storage。单场比赛 100Gi 磁盘档位可以使用下面的容量,长期练习场可以使用 1 TiB 档位:
| 组件 | PV 名称 | StorageClass | 宿主机目录 | 单场比赛档位 | 长期练习场档位 |
|---|---|---|---|---|---|
| 平台数据 | ret2shell-storage-platform-pv1 | ret2shell-storage-platform | /srv/ret2shell/backend/storage/platform-pv1 | 32Gi | 450Gi |
| PostgreSQL | ret2shell-storage-database-pv1 | ret2shell-storage-database | /srv/ret2shell/backend/storage/database-pv1 | 10Gi | 150Gi |
| Valkey | ret2shell-storage-cache-pv1 | ret2shell-storage-cache | /srv/ret2shell/backend/storage/cache-pv1 | 1Gi | 20Gi |
| NATS | ret2shell-storage-queue-pv1 | ret2shell-storage-queue | /srv/ret2shell/backend/storage/queue-pv1 | 1Gi | 20Gi |
| registry | ret2shell-storage-registry-pv1 | ret2shell-storage-registry | /srv/ret2shell/backend/storage/registry-pv1 | 25Gi | 350Gi |
| VictoriaLogs | ret2shell-storage-logs-pv1 | ret2shell-storage-logs | /srv/ret2shell/backend/storage/logs-pv1 | 1Gi | 10Gi |
PVC 的 size 应小于或等于对应 PV 的容量。为了便于审计和扩容,建议让 Helm values 中的 *.persistence.size 与 PV 容量保持一致。
创建宿主机目录并应用 PV 模板:
sudo mkdir -p /srv/ret2shell/backend/storage/{platform-pv1,database-pv1,cache-pv1,queue-pv1,registry-pv1,logs-pv1}
sudo chmod 1777 /srv/ret2shell/backend/storage/database-pv1
kubectl apply -f storage-local.yaml
kubectl get storageclass
kubectl get pv -o wide部署前应看到 6 个 Available 状态的 PV。Helm 安装后,平台 namespace 中的 PVC 会按 StorageClass 绑定到这些 PV。
配置 values
部署前至少需要修改 values.production.yaml 中的外部访问地址、密钥、密码、存储类和入口方式。下面的示例展示了使用本地静态 PV 和 Ingress 的常见配置:
global:
storageClass: ""
platform:
image:
tag: "<version>"
exposure:
type: ingress
ingress:
className: nginx
hosts:
- host: ctf.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: ret2shell-tls
hosts:
- ctf.example.com
config:
auth:
signingKey: "replace-with-strong-random-key"
server:
externalDomain: ctf.example.com
externalHttps: true
corsOrigins: "https://ctf.example.com"
cluster:
enabled: true
nodeSelector: "challenge"
enableCapture: true
nodeSelector:
ret.sh.cn/workload: platform
persistence:
enabled: true
accessMode: ReadWriteOnce
storageClass: ret2shell-storage-platform
size: 32Gi
postgresql:
mode: internal
auth:
password: "replace-with-random-password"
persistence:
enabled: true
accessMode: ReadWriteOnce
storageClass: ret2shell-storage-database
size: 10Gi
valkey:
mode: internal
auth:
enabled: true
password: "replace-with-random-password"
persistence:
enabled: true
accessMode: ReadWriteOnce
storageClass: ret2shell-storage-cache
size: 1Gi
nats:
mode: internal
auth:
enabled: true
token: "replace-with-random-token"
persistence:
enabled: true
accessMode: ReadWriteOnce
storageClass: ret2shell-storage-queue
size: 1Gi
registry:
mode: internal
externalAccess:
enabled: true
serviceType: NodePort
nodePort: 30310
host: registry.example.com:30310
insecure: true
persistence:
enabled: true
accessMode: ReadWriteOnce
storageClass: ret2shell-storage-registry
size: 25Gi
victoriaLogs:
mode: internal
persistence:
enabled: true
accessMode: ReadWriteOnce
storageClass: ret2shell-storage-logs
size: 1Gi示例中的 <version> 应替换为下载的 release 版本号,例如命令中的 $R2S_VERSION。使用 local-path 或其他动态 StorageClass 时,可以删除各组件的 storageClass 字段,并把 global.storageClass 设置为目标 StorageClass。
选择 NodePort + 外置 Web Server 时,平台入口配置通常改为:
platform:
exposure:
type: nodePort
service:
nodePort: 30307
config:
server:
externalDomain: ctf.example.com
externalHttps: true
corsOrigins: "https://ctf.example.com"外置 Web Server 负责 TLS、WebSocket、静态资源缓存和 /v2 registry 代理时,需要把 externalDomain 设置为用户实际访问的平台域名。
准备入口和 TLS
Ingress 部署需要集群中已经存在 Ingress Controller。使用 Nginx Ingress Controller 时,可以通过 Helm 安装:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
-n ingress-nginx \
--create-namespace \
--wait
kubectl -n ingress-nginx get pods,svc -o wideIngress Controller 通过 NodePort 暴露时,访问端口可以从 Service 中查看:
kubectl -n ingress-nginx get svc ingress-nginx-controller -o wide使用真实域名和 80/443 入口时,可以把 Ingress Controller 调整为 hostNetwork DaemonSet。执行前应确认宿主机 80/443 没有被 Traefik、Nginx、Caddy 或其他服务占用:
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
-n ingress-nginx \
--set controller.kind=DaemonSet \
--set controller.hostNetwork=true \
--set controller.service.type=ClusterIP \
--waitvalues 中配置了 platform.ingress.tls.secretName 时,需要先创建 TLS Secret:
kubectl create namespace ret2shell-platform --dry-run=client -o yaml | kubectl apply -f -
kubectl -n ret2shell-platform create secret tls ret2shell-tls \
--cert=/path/to/fullchain.cer \
--key=/path/to/private.key使用 NodePort + 外置 Web Server 时,外置 Web Server 应转发到平台 NodePort,并保留 WebSocket 和真实客户端地址相关请求头。registry 代理需要把标准 /v2 路径转发到平台的 /api/cluster/registry/v2 路径。
入口配置完成后,应检查宿主机和 Kubernetes Service 的端口暴露状态:
sudo ss -lntp
kubectl get svc -A -o wide公网通常只开放 80/443 或明确选择的业务入口端口。6443、10250、k3s Traefik 高位端口、平台 NodePort 和 registry NodePort 应通过云安全组、防火墙或网关访问控制限制到可信来源。
global
global.storageClass 是所有组件默认使用的 StorageClass。各组件的 *.persistence.storageClass 可以覆盖该值。global.imagePullSecrets 用于私有镜像仓库鉴权。global.labels 和 global.annotations 会附加到 chart 资源上,便于集群侧审计和资源分组。
platform
platform.image 控制平台镜像来源,默认仓库为 ghcr.io/ret2shell/ret2shell。platform.image.tag 应与下载的 Chart 版本保持一致,使用 digest 时以 digest 为准。
platform.exposure.type 支持 ingress 和 nodePort。Ingress 适合使用集群内 Ingress Controller 统一暴露平台。NodePort 适合由宿主机 Nginx、Caddy 或已有网关转发到平台 Service。
platform.config.auth.signingKey 用于签发平台令牌,生产环境必须替换为随机强密钥。platform.config.server.externalDomain 和 externalHttps 决定平台生成的外部地址。corsOrigins 建议设置为实际访问源,例如 https://ctf.example.com。
platform.config.cluster.enabled 控制动态题目容器功能。nodeSelector 会转换为 challenge pods 的 ret.sh.cn/workload=<值> 调度选择器。上面的示例会把题目容器调度到带有 ret.sh.cn/workload=challenge 标签的节点。enableCapture 会保存题目容器交互捕获数据,捕获量较大时应提高 platform.persistence.size。
platform.persistence.size 对应 /var/lib/ret2shell。该目录保存平台 bucket、media、log 和 capture 数据。单场比赛 100Gi 磁盘档位建议从 32Gi 起步,长期练习场建议从 450Gi 起步。平台以单副本 StatefulSet 运行,platform.replicaCount 保持 1。
platform.serviceAccount 和 platform.rbac 控制 Kubernetes API 权限。默认会创建 ServiceAccount 和 ClusterRoleBinding。受限集群可以预先创建账号和权限,然后设置 platform.serviceAccount.create=false、platform.serviceAccount.name=<existing-sa>、platform.rbac.create=false。
postgresql
postgresql.mode 支持 internal 和 external。内置模式会创建单实例 PostgreSQL StatefulSet、Secret、Service 和 PVC。单场比赛 100Gi 磁盘档位建议从 10Gi 起步,长期练习场建议从 150Gi 起步。外部模式需要填写 postgresql.external.host、port、database、username、password 和 sslMode。自维护 PostgreSQL 可以参考 PostgreSQL Debian 安装文档。
PostgreSQL 保存平台主数据。升级前建议先做数据库备份。已有云数据库或自维护 PostgreSQL 时,可以使用外部模式降低集群内磁盘压力。
valkey
valkey.mode 支持 internal 和 external。内置模式默认创建单实例 Valkey StatefulSet,开启鉴权和 AOF 持久化。单场比赛 100Gi 磁盘档位建议从 1Gi 起步,长期练习场建议从 20Gi 起步。外部模式使用 valkey.external.url,格式为 redis://:<password>@host:6379/0。自维护 Valkey 可以参考 Valkey Installation。
valkey.architecture=replication 会创建主从结构。复制模式下,每个 Valkey Pod 都会申请 valkey.persistence.size 指定的 PVC。
nats
nats.mode 支持 internal 和 external。内置模式会创建 NATS StatefulSet,启用 JetStream。单场比赛 100Gi 磁盘档位建议从 1Gi 起步,长期练习场建议从 20Gi 起步。外部模式需要填写 nats.external.host、port、token、user、password 和 tls 中实际使用的字段。自维护 NATS 可以参考 Installing a NATS Server,Kubernetes 环境可以参考 NATS and Kubernetes。
nats.replicaCount 大于 1 时会启用 NATS 集群路由。每个 NATS Pod 都会申请同等大小 PVC。
registry
registry.mode 支持 disabled、internal 和 external。内置 registry 用于题目镜像上传、保存和集群侧拉取。单场比赛 100Gi 磁盘档位建议从 25Gi 起步,长期练习场建议从 350Gi 起步。题目镜像较多、镜像层较大或保留多个版本时,应优先扩容 registry。
registry.externalAccess.host 必须是 Kubernetes 节点可以访问的地址。平台推送镜像时使用 chart 内部 Service,节点拉取镜像时使用 externalAccess.host。使用 Docker Hub、GHCR、Harbor 或云厂商镜像仓库时,可以设置 registry.mode=external 并填写 registry.external.server、external、username 和 password。自建 registry 可以参考 CNCF Distribution 部署文档 或 Harbor Installation and Configuration。使用托管仓库可以参考 Docker Hub Repositories 和 GitHub Container Registry。不使用受控题目镜像仓库时,可以设置 registry.mode=disabled。
registry.replicaCount 大于 1 需要 RWX 共享存储或等价的共享后端。默认 RWO 本地卷只适合单副本 registry。
victoriaLogs
victoriaLogs.mode 支持 disabled、internal 和 external。内置模式会创建单实例 VictoriaLogs StatefulSet。单场比赛 100Gi 磁盘档位建议从 1Gi 起步,长期练习场建议从 10Gi 起步。外部模式使用 victoriaLogs.external.url。自维护 VictoriaLogs 可以参考 VictoriaLogs Quick Start。
VictoriaLogs 用于集中查询平台日志和比赛行为记录。正式比赛建议保留该组件,或接入已有日志系统。
通用工作负载配置
各组件都支持 resources、nodeSelector、tolerations、affinity、podAnnotations、podLabels、priorityClassName、topologySpreadConstraints 和 podDisruptionBudget。多节点部署时建议为平台和内置基础组件设置 nodeSelector,把它们固定在稳定节点上,再通过 platform.config.cluster.nodeSelector 把 challenge pods 调度到题目节点。
各组件的 metrics 或 serviceMonitor 配置用于 Prometheus 生态监控。集群中已经安装 Prometheus Operator 时,可以开启对应的 ServiceMonitor。
安装平台
先创建平台 namespace。Ingress TLS Secret、外部镜像拉取 Secret 和预创建 ServiceAccount 都应放在这个 namespace 中:
kubectl create namespace ret2shell-platform --dry-run=client -o yaml | kubectl apply -f -再渲染 Chart,检查 Kubernetes 资源和 values:
helm template ret2shell "./ret2shell-${R2S_VERSION}.tgz" \
-n ret2shell-platform \
-f values.production.yaml \
> rendered.yaml
less rendered.yaml确认配置后执行安装:
helm upgrade --install ret2shell "./ret2shell-${R2S_VERSION}.tgz" \
-n ret2shell-platform \
--create-namespace \
-f values.production.yaml \
--wait \
--timeout 15m安装完成后检查 release、Pod、PVC 和入口:
helm status ret2shell -n ret2shell-platform
kubectl -n ret2shell-platform get pods,pvc,svc,ingress -o wide
kubectl get pv -o wide
kubectl -n ret2shell-challenge get all使用静态 Local PV 时,所有平台 PVC 都应处于 Bound 状态,并且 VOLUME 列应指向前面创建的 ret2shell-storage-* PV。
Chart 内置了基本连通性测试:
helm test ret2shell -n ret2shell-platform --logs平台 Pod 正常运行后,通过配置的 Ingress 域名或外置 Web Server 地址访问平台。
后续升级
升级前先保存当前 values 和 release 状态:
cd ~/ret2shell-deploy
helm get values ret2shell -n ret2shell-platform > "values.installed.$(date +%F).yaml"
helm history ret2shell -n ret2shell-platform拉取新的 Chart:
R2S_VERSION="$(curl -fsSL https://api.github.com/repos/ret2shell/ret2shell/releases/latest | jq -r '.tag_name')"
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 后执行升级:
helm upgrade --install ret2shell "./ret2shell-${R2S_VERSION}.tgz" \
-n ret2shell-platform \
-f values.production.yaml \
--wait \
--timeout 15m升级后检查状态:
kubectl -n ret2shell-platform rollout status statefulset/ret2shell-platform --timeout=5m
kubectl -n ret2shell-platform get pods,pvc -o wide
helm test ret2shell -n ret2shell-platform --logs回滚到上一版本时,先查看 revision,再执行 rollback:
helm history ret2shell -n ret2shell-platform
helm rollback ret2shell <revision> -n ret2shell-platform --wait --timeout 15mPVC 可以扩容,前提是对应 StorageClass 支持 allowVolumeExpansion。PVC 无法直接缩容。调整 *.persistence.size 后执行 Helm upgrade,再检查 PVC 容量和 Pod 状态。
日常检查与排障
查看平台组件:
kubectl -n ret2shell-platform get pods -o wide
kubectl -n ret2shell-platform get statefulset,deploy,svc,pvc -o wide
kubectl -n ret2shell-platform get events --sort-by=.lastTimestamp查看平台日志:
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-challenge get pods -o wide
kubectl -n ret2shell-challenge get svc -o wide
kubectl -n ret2shell-challenge get pods -l ret.sh.cn/challenge=<challenge_id> -o wide
kubectl -n ret2shell-challenge get pods -l ret.sh.cn/user=<user_id> -o wide
kubectl -n ret2shell-challenge get pods -l ret.sh.cn/team=<team_id> -o wide
kubectl -n ret2shell-challenge get pods -l 'ret.sh.cn/challenge=<challenge_id>,ret.sh.cn/user=<user_id>' -o wide调试单个题目容器:
kubectl -n ret2shell-challenge describe pod <pod-name>
kubectl -n ret2shell-challenge logs <pod-name> -c <container-name> --tail=200
kubectl -n ret2shell-challenge exec -it <pod-name> -c <container-name> -- sh检查调度和资源:
kubectl top nodes
kubectl top pods -A
kubectl describe node <node-name>
kubectl -n ret2shell-challenge describe pod <pod-name>调试 PostgreSQL:
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 -it "$DB_POD" -- sh -lc 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U "$POSTGRES_USER" -d "$POSTGRES_DB"'
kubectl -n ret2shell-platform logs "$DB_POD" --tail=200调试 Valkey:
CACHE_POD="$(kubectl -n ret2shell-platform get pod -l app.kubernetes.io/component=valkey -o jsonpath='{.items[0].metadata.name}')"
CACHE_PASS="$(kubectl -n ret2shell-platform get secret ret2shell-valkey -o jsonpath='{.data.password}' | base64 -d)"
kubectl -n ret2shell-platform exec -it "$CACHE_POD" -- valkey-cli -a "$CACHE_PASS" ping
kubectl -n ret2shell-platform logs "$CACHE_POD" --tail=200调试 NATS:
NATS_TOKEN="$(kubectl -n ret2shell-platform get secret ret2shell-nats -o jsonpath='{.data.token}' | base64 -d)"
kubectl -n ret2shell-platform run nats-debug \
--rm -it \
--image=natsio/nats-box \
--restart=Never \
--env=NATS_TOKEN="$NATS_TOKEN" \
-- sh -lc 'nats --server nats://ret2shell-nats:4222 --auth "$NATS_TOKEN" stream ls'调试 registry:
kubectl -n ret2shell-platform port-forward svc/ret2shell-registry 5000:5000
curl -fsSL http://127.0.0.1:5000/v2/
curl -fsSL http://127.0.0.1:5000/v2/_catalog调试 VictoriaLogs:
kubectl -n ret2shell-platform port-forward svc/ret2shell-victoria-logs 9428:9428
curl -fsSL http://127.0.0.1:9428/metrics >/tmp/victoria-logs.metrics
curl -G 'http://127.0.0.1:9428/select/logsql/query' --data-urlencode 'query=* | limit 20'诊断入口问题:
kubectl -n ret2shell-platform get ingress -o wide
kubectl -n ret2shell-platform describe ingress ret2shell-platform
kubectl -n ret2shell-platform get svc ret2shell-platform -o wide
kubectl -n ret2shell-platform get svc ret2shell-platform-nodeport -o wide --ignore-not-found
kubectl -n ingress-nginx get pods,svc -o wide诊断 PVC 问题:
kubectl -n ret2shell-platform get pvc -o wide
kubectl -n ret2shell-platform describe pvc <pvc-name>
kubectl get storageclass -o wide
kubectl get pv -o wide
kubectl describe pv <pv-name>使用本地静态 PV 时,还应在节点上检查宿主机目录是否存在并且可以写入:
sudo ls -al /srv/ret2shell/backend/storage
sudo du -sh /srv/ret2shell/backend/storage/*排障时通常先看 ret2shell-platform namespace 的平台日志和事件,再看 ret2shell-challenge namespace 中对应题目 Pod 的状态、日志、Service 和节点调度结果。题目容器的标签可以直接定位到用户、队伍、题目和 traffic token。
上线前检查
正式开放前建议完成以下检查:
| 项目 | 检查方式 |
|---|---|
| TLS 与域名 | 浏览器访问平台域名,确认证书链、HTTPS 跳转和 WebSocket 正常。 |
| PV / PVC | kubectl get pv 与 kubectl -n ret2shell-platform get pvc 均显示已绑定,节点重启后数据仍在宿主机目录中。 |
| 平台文件 | 上传图片、题目附件和题目镜像,确认上传、下载和展示正常。 |
| 动态容器 | 启动一题带在线环境的题目,确认 Pod、Service、访问地址和回收流程正常。 |
| registry | 使用内置 registry 时,确认 /v2 代理、镜像上传和节点拉取均正常。 |
| 邮件 | 启用 SMTP 后发送测试邮件,确认验证邮件和找回密码邮件内容正确。 |
| 端口暴露 | 公网只开放业务入口所需端口,Kubernetes API、kubelet、Traefik 高位端口、平台 NodePort 和 registry NodePort 应受安全组或防火墙限制。 |
后续维护
集群内部部署完成后,应继续阅读 日常维护手册,建立数据库备份、日志保留、镜像清理、平台升级、题目容器巡检和比赛期间应急处理流程。
