RAILSHOT.
返回展厅

Railshot

AI deployment & operations platform

将在本机构建的 Web 应用部署到预先准备的云端与本地机房环境,并加以运维。

一个 AI 部署与运维平台:把在本机构建的 Web 应用部署到预先准备的云端或本地机房环境,并持续运行。

2026.09.28 — 2026.10.04 · 已结束

团队项目 · 我负责:CI 规划与实现、CSP 集群与 Ansible 接口、运维、团队代码审查与集成

SoftBank Hackathon 2026 powered by KOREC & Progate参加初赛 · 决赛入选名单预计 2026年10月26日公布(截至 2026年10月7日)

  • 网页已实现 · 黑客松
  • MCP 服务器已实现 · 远程 · 本地

运维集群与客户应用集群相互分离,公开路径与部署控制分开。

在运维 K3s 中,仪表盘、产品 API 和 build controller 放置在 platform 角色节点上,runner Job 放置在 build 角色节点上,由 Argo CD 负责部署。客户应用运行在每个已注册目标各自独立的单节点 K3s + Cilium 集群的指定 namespace 中。

集群结构图 · 依据公开提交 645e28a 的声明与代码绘制
Railshot 运维与客户集群结构图运维 K3s 集群与一个已注册的客户应用集群。在运维集群中,railshot-system namespace 将仪表盘、产品 API、远程 MCP(仅在提供镜像时)和 build controller 放置在 platform 角色节点上;railshot-build namespace 中的 runner Job 在带 taint 的 build 角色节点上领取 GitHub Actions 作业。由 GitHub 托管的 release 作业将已测试 bundle 发布到 GHCR。产品 API 将 workload 提交到 config Git,并 sync argocd namespace 中的 Application,Argo CD 将 Deployment、NodePort Service 和 NetworkPolicy 应用到客户集群中已注册的 namespace。应用请求经提供商的 L7 入口进入节点的 NodePort 与 Service,再到达应用 Pod。部署判定只依据 Argo 状态和公开 URL 检查;Pod 诊断、日志和指标作为独立信号读取。运维人员的安装与注册输入与租户应用 payload 相互分离。Railshot 用户仪表盘 · MCP运维人员初始化安装 · 注册 · SecretGHCRdigest 镜像config Git 仓库workload.json · revision提供商 L7 入口ALB · GCP LB · Amphora应用用户公开 HTTPS观测 VM客户 K3s 之外 · Composerailshot-systemdashboard · nginx远程 MCP · 仅在提供镜像时build controller · CronJob产品 API · cd.js → bridge.pyargocdArgo CD · ApplicationAppProject · cluster Secret凭据续期 CronJob · 每 2 小时railshot-buildrunner Job · hostNetwork · Docker socketrailshot-deploy.ymlloop job · self-hosted runnerrelease job · GitHub-hosted<app namespace>Deployment · Pod · digest 镜像NodePort Service · LocalNetworkPolicy · 列出的 CIDRrailshot-argocd SA · 令牌kube-systemCilium · Helm · VXLANrailshot-observabilitynode-exporterkube-state-metrics运维集群 · K3sAWS · 角色节点platform 角色节点nodeSelectorbuild 角色节点NoSchedule taintGitHubActions · GHCR客户应用集群 · 示例每个已注册目标一个单个 K3s 节点 · serverCilium · 保留 kube-proxy1workflow_dispatch2补充 runner Job3领取作业4已测试 bundle5 按 digest 发布 · release job · GitHub-hosted → GHCR51workload commit · push2revision3 Application sync · 产品 API · cd.js → bridge.py → Argo CD · Application34应用到 namespace5按 digest pull1HTTPS 4432NodePort3 到 Pod · NodePort Service · Local → Deployment · Pod · digest 镜像34 执行策略 · Cilium · Helm · VXLAN → NetworkPolicy · 列出的 CIDR45 仪表盘 · API · Railshot 用户 → dashboard · nginx51 revision · health · 镜像 · 产品 API · cd.js → bridge.py → Argo CD · Application12公开 HTTPS 检查3Pod 诊断 · 不作判定4日志 tail · 每个 Pod 100 行5抓取 · NodePort6Blackbox probe1渲染 platform · Secret2注册 bootstrap3安装 K3s · Cilium4TokenRequest · 6 小时

构建 → 发布镜像

产品 API 请求一次 GitHub Actions 运行,build 节点上的 runner 领取该作业并执行检查。只有通过同样检查的 bundle 才由 GitHub 托管的 release 作业发布到 GHCR。

  1. 产品 API · cd.js → bridge.pyrailshot-system运行 · 应用: workflow_dispatchloop job · self-hosted runnerrailshot-deploy.yml

    产品 API 以 tenant、app、源提交和目标请求一次 GitHub Actions 运行。API 从不直接调用 runner Job。

  2. build controller · CronJobrailshot-system运行 · 应用: 补充 runner Jobrunner Job · hostNetwork · Docker socketrailshot-build

    build controller CronJob(每分钟一次,运行在 platform 节点上)在 railshot-build namespace 中创建 runner Job。其 Role 只允许对 Job 执行 get、list 和 create,以及对唯一的 runner 注册 Secret 执行 get、update 和 patch;它不能创建 namespace 或其他 Secret。

  3. runner Job · hostNetwork · Docker socketrailshot-build运行 · 应用: 领取作业loop job · self-hosted runnerrailshot-deploy.yml

    build 角色节点上的 runner(精确 hostname,NoSchedule toleration)按 self-hosted 标签领取 loop 作业并运行。客户源码在现有的受限 Docker 构建与检查容器中运行。

  4. runner Job · hostNetwork · Docker socketrailshot-build数据: 已测试 bundlerelease job · GitHub-hostedrailshot-deploy.yml

    loop 作业留下通过同样检查的 bundle,release 作业只接收该 bundle。

  5. release job · GitHub-hostedrailshot-deploy.yml数据: 按 digest 发布GHCR

    由 GitHub 托管的 release 作业(ubuntu-24.04)将已测试 bundle 的镜像不经重新构建发布到 GHCR。镜像发布从不在客户应用集群内进行。

config Git → Argo → 客户 namespace

config Git 承载期望的资源,GHCR 承载镜像字节。Argo CD 只应用到已注册的客户 namespace。

  1. 产品 API · cd.js → bridge.pyrailshot-system数据: workload commit · pushconfig Git 仓库

    cd.js 运行 bridge.py;仅当发布记录与已注册目标一致时,bridge.py 才 commit 并 push workload.json,然后读回远程 revision。Git 承载期望的资源,GHCR 承载镜像字节。

  2. config Git 仓库数据: revisionArgo CD · Applicationargocd

    Application 只读取其受限的 config 仓库、路径和 revision。

  3. 产品 API · cd.js → bridge.pyrailshot-system运行 · 应用: Application syncArgo CD · Applicationargocd

    指定的 Application 以 server-side apply 设置,并请求对一个确切 revision 进行不带 prune 的 sync。产品 API 的 railshot-product ServiceAccount 同时持有运维人员预装的注册 bootstrap 权限(argocd 中 Secret、AppProject 和 Application 的 create;指定名称 Role 的 get、update 和 escalate),以及针对每个已验证目标按确切名称追加的 get 和 patch 授权。Kubernetes 的 create 无法按名称限制,因此名称范围也由产品的输入校验把守。

  4. Argo CD · Applicationargocd运行 · 应用: 应用到 namespace<app namespace>

    Argo CD 使用已注册 cluster Secret 的凭据,应用到客户集群中的指定 namespace。AppProject 只允许 namespace 范围的 kind,不允许集群范围的资源。

  5. Deployment · Pod · digest 镜像<app namespace>数据: 按 digest pullGHCR

    已发布的 digest 镜像通过同一 namespace 中按名称引用的 pull Secret 拉取。Secret 值从不进入产物或 config Git。

公开请求路径

应用请求经提供商 L7 入口 → 节点 NodePort → Service → 应用 Pod。Cilium 的策略执行是一项独立控制,而不是承载请求的一跳。进入运维仪表盘走的是另一条路径。

  1. 应用用户数据: HTTPS 443提供商 L7 入口

    应用用户通过已注册的 hostname 访问提供商的 L7 入口。入口由各提供商各自实现。

  2. 提供商 L7 入口数据: NodePortNodePort Service · Local<app namespace>

    入口转发到节点的私有地址和 NodePort。该 NodePort 是注册目标时分配的。

  3. NodePort Service · Local<app namespace>数据: 到 PodDeployment · Pod · digest 镜像<app namespace>

    Service 将请求发往同一节点上的应用 Pod(Deployment)。由于 externalTrafficPolicy 为 Local,源地址原样到达 NetworkPolicy 的已注册 CIDR 检查。

  4. Cilium · Helm · VXLANkube-system运行 · 应用: 执行策略NetworkPolicy · 列出的 CIDR<app namespace>

    Cilium 执行 NetworkPolicy:入站仅允许从已注册 CIDR 到应用端口;默认无出站,经批准的数据库地址除外。云防火墙和主机规则仍不可少。

  5. Railshot 用户数据: 仪表盘 · APIdashboard · nginxrailshot-system

    用户经运维入口进入 nginx 仪表盘,nginx 在前端承接产品 API。仅在给定经批准的节点端口时,dashboard Service 才是 NodePort;API 保持为 ClusterIP。

验证 · 观测

部署判定只依据 Argo 状态和公开 URL 检查。Pod 诊断、当前日志和运行指标是独立信号,从不改变判定。

  1. 产品 API · cd.js → bridge.pyrailshot-system观测: revision · health · 镜像Argo CD · Applicationargocd

    deployed 要求 Application 的 sync revision、Synced 与 Healthy、operation Succeeded,并且 Argo Application 状态中记录的镜像引用等于经审查的 Deployment 的 digest 镜像。这不是直接检查 Pod imageID 的关卡,仅凭 Argo 的绿色状态也无法确立这种一致。

  2. 产品 API · cd.js → bridge.pyrailshot-system观测: 公开 HTTPS 检查提供商 L7 入口

    不跟随重定向检查已注册的公开 URL。只有同时具备 Argo 判定和这项检查,才记录为 succeeded。

  3. 产品 API · cd.js → bridge.pyrailshot-system观测: Pod 诊断 · 不作判定Deployment · Pod · digest 镜像<app namespace>

    完成 Argo 判定和公开检查后,用已注册凭据另行读取 Deployment、ReplicaSet 和 Pod,并将 imageID 与就绪状态作为 ready、progressing 或 unavailable 诊断附加上去。诊断失败或不一致,都不会改变 deployed 或 succeeded 判定。

  4. 产品 API · cd.js → bridge.pyrailshot-system观测: 日志 tail · 每个 Pod 100 行Deployment · Pod · digest 镜像<app namespace>

    仅针对当前已部署的 operation,使用可信 config 和已注册凭据。对当前每个 Pod(最多三个),运行中的镜像 digest 必须等于预期 digest;随后在字节上限内为每个 Pod 读取最多 100 行已脱敏的日志。较早的尝试返回 superseded;未配置时返回 not_configured。这不是日志聚合。

  5. 观测 VM观测: 抓取 · NodePortrailshot-observability

    观测 VM 上的 Prometheus 通过两个受防火墙限制的 NodePort 抓取 node-exporter 和 kube-state-metrics。缺失或过期的值为未知,而不是零。

  6. 观测 VM观测: Blackbox probe提供商 L7 入口

    probe_success=1 表示在该探测位置收到 2xx。它既不证明所有用户都能访问,也不证明已部署的版本,也绝不会把已发布提升为已部署。

运维人员安装 · 注册

集群安装、注册 bootstrap 与目标输入、Secret 以及凭据续期设置都是运维人员的输入,从不属于租户应用 payload。

  1. 运维人员初始化运行 · 应用: 渲染 platform · Secretrailshot-system

    运维人员用 render-platform.py 渲染 platform 声明,并提供私有的运维配置和 Secret。远程 MCP 仅在提供镜像时纳入,个人 gateway(WireGuard)仅在使用 --personal 时纳入。

  2. 运维人员初始化运行 · 应用: 注册 bootstrapAppProject · cluster Secretargocd

    运维人员在 argocd 中安装注册 bootstrap Role 和一个空的 registrations Role,并准备目标输入。随后,产品 API 运行的注册 helper(environment.py、applications.py)以限定范围的凭据写入 railshot-<target> Secret(clusterResources false,列出允许的 namespace),并将经验证的确切名称追加到 registrations Role。按应用注册时,app-<id> namespace 与同名 AppProject 绑定。

  3. 运维人员初始化运行 · 应用: 安装 K3s · CiliumCilium · Helm · VXLANkube-system

    install-k3s.sh 安装单节点 K3s server(关闭 flannel、network policy、traefik 和 servicelb;保留 kube-proxy),Cilium 以 Helm release 形式安装(kubeProxyReplacement false,VXLAN,关闭 Hubble)。

  4. 凭据续期 CronJob · 每 2 小时argocd运行 · 应用: TokenRequest · 6 小时railshot-argocd SA · 令牌<app namespace>

    railshot-credentials CronJob 每两小时为客户 SA 请求一个新的六小时令牌。客户侧 Role 只允许为其自身 SA 执行 token create。六小时是单个令牌的 TTL,而不是运维访问结束的时间。

所有连接以相同粗细显示。选择一个流程,即只突出显示其路径,并标出步骤编号。

  • 实线 · 请求、bundle、镜像与声明的流向
  • 虚线 · 运行请求、应用、安装、凭据
  • 长点划线 · 读取状态、日志、探针、指标;独立于判定
  • 粗黑线 · 所选流程;数字表示顺序
  • 方框 · 一个 namespace,标题栏为其名称(不是节点)
  • 内层小框 · 该 namespace 中的组件
  • 虚线框 · 集群之外
  • railshot-system · 产品
  • argocd · 部署权限
  • railshot-build · 主机 Docker 权限
  • GitHub · 客户集群

docs/architecture 中 10月2日的布局决定(两个角色节点)和公开 README 中的图都属于历史;本结构图依据 645e28a 的声明与代码。箭头表示原因与方向,并不证明每条提供商路径当前都在运行。

namespace 与节点
namespace 是命名范围:既不是硬件,本身也不是安全边界。platform 与 build 角色是通过 nodeSelector 和 taint 实现的调度布局;本图不规定运维集群的节点数。Argo CD 的节点布局也需另行检查。
build 节点权限
runner Job 以 hostNetwork、主机 Docker 套接字、NET_ADMIN 和 root 运行。namespace、taint 或 RBAC 都不能移除主机 Docker 权限,因此这既不是 VM 管理员级别的隔离,也不是任意代码的沙箱。
客户 namespace
每个已注册目标使用非默认的 namespace 和 AppProject(例如 tenant-demo,或按应用的 app-<id>)。只创建一个服务的 Deployment(关闭 ServiceAccount 令牌自动挂载)、NodePort Service 和 NetworkPolicy,以及可选的 PVC 或迁移 Job;Secret 只按名称引用(pull Secret 和经批准的 DATABASE_URL),从不创建。
AWS 入口
Route 53 Alias → 共享 ALB HTTPS 443 → 客户节点私有地址和 NodePort。多个应用复用一个节点,每个应用各有自己的 namespace、Application 和 NodePort。
GCP 入口
全局 EXTERNAL_MANAGED HTTPS LB → 可用区 GCE_VM_IP_PORT NEG → 现有 VM 的私有 NodePort。证书由 Certificate Manager 通过 DNS 授权签发。该模块既不拥有 VM 也不拥有 VPC,单台 VM 仍是单点故障。
OpenStack 入口
Amphora TLS 监听器 443,带 Host 与路径 L7 策略 → HTTP NodePort。默认地址是私有 VIP;Octavia、K3s、数据库和 DNS 不在模块范围内。公网可达性和现场 Amphora 就绪需另行验收,且尚未用该模块验证过现场应用。
跨提供商
三个入口是各自独立的实现,提供商之间没有自动故障转移或复制。客户应用集群是已注册目标的一个示例,并不表示同一部署同时运行在所有云上。
运维人员选项
个人 gateway(WireGuard)仅在运维人员启用 --personal 时加入 platform;它不是客户云的必经路径。在受支持的 direct 模式下,观测 VM 可以与运维控制 VM 共用。