ssa1004/gpu-job-orchestrator
GitHub: ssa1004/gpu-job-orchestrator
这是一个面向GPU训练与推理场景的企业级任务编排系统,提供从任务提交、K8s调度、状态回调到计费通知的完整闭环,并附带全套现代DevOps与基础设施代码。
Stars: 0 | Forks: 0
# GPU 任务编排器 (GPU Job Orchestrator)
这是一个用于管理 GPU 训练/推理等长时间运行的异步任务的后端 API。它会将用户的
任务请求记录到数据库中,作为 Kubernetes Job 发起执行请求,然后在工作器 (Worker)
通过回调通知任务完成时更新状态。
本项目在后端 API 的基础上,还直接包含了亲自编写的基础设施(Terraform, Ansible)、
GitOps (ArgoCD) 和可观测性(Prometheus, Grafana, Loki, Tempo)的代码。这是因为
GPU 任务的特殊性,仅靠后端无法完成实际的运营操作。
## 技术栈
- **Backend**: Java 17, Spring Boot 3.3, JPA + Flyway, OAuth2 (JWT), Resilience4j
- **Worker**: Go 1.22 (job 处理 + 回调 + Prometheus metric)
- **Infra (Cloud)**: AWS EKS, Terraform 1.5+, Helm
- **Infra (On-prem)**: Ansible, k3s, NVIDIA driver, Harbor
- **GitOps / CI**: ArgoCD, Argo Rollouts, GitHub Actions, Cosign (镜像签名), Syft (SBOM — 列出包含哪些库的组件清单), Trivy (漏洞扫描器)
- **Autoscaling**: KEDA (基于事件的自动扩缩容 — 以 Kafka 队列积压等为触发条件调整 Pod 数量), Cluster Autoscaler (priority expander — 指定优先使用哪个节点池的优先级)
- **Observability**: Prometheus (kube-prometheus-stack), Grafana, Loki (日志存储), Tempo (Trace 存储), Mimir (Prometheus 长期存储),
OpenTelemetry, DCGM exporter (NVIDIA GPU 指标)
- **Security**: Kyverno cluster policies (Pod 创建时强制执行策略 — 拒绝未签名镜像等), External Secrets Operator (将 AWS Secrets Manager 的密钥值同步为 K8s Secret),
Falco runtime detection (检测正在运行的容器的可疑行为), Cosign attestation (将元数据证明附加到镜像)
- **Resilience**: Velero 备份, Chaos Mesh 定期实验 (故意注入故障以验证系统恢复能力)
- **Load Test**: K6 (CI 每天夜间自动执行负载测试)
- **Storage / Messaging**: PostgreSQL 16, Redis, Kafka, S3 / MinIO
## 目录结构
```
orchestrator-api/ Spring Boot API (도메인, 어댑터, k8s 매니페스트, ADR 25건)
worker/ Go GPU 워커 시뮬레이터 (실제 동작)
tests/load/ K6 부하 테스트 (4 시나리오)
helm/gpu-job-orchestrator/ Helm chart (dev / prod values 분리, leader election 토글)
infrastructure/
├── terraform/ VPC, EKS, GPU 노드그룹, 모니터링 stack
├── ansible/ 온프레미스 노드 부트스트랩
├── ci-cd/ GitHub Actions + Cosign + SBOM + ArgoCD GitOps
├── keda/ ScaledJob (Kafka lag → GPU 워커 자동 확장) + priority class
├── observability/ PrometheusRule + Grafana 대시보드 JSON
├── security/
│ ├── kyverno/ Cluster policy 7건 (서명 강제, privileged 차단 등)
│ ├── external-secrets/ AWS Secrets Manager 연동
│ └── falco/ Runtime detection rules
├── dr/velero/ 백업 스케줄 + restore 절차
└── chaos/ Chaos Mesh 실험 5건
docs/
├── platform-design.md 운영 환경이 API 설계에 영향을 주는 지점
├── slo.md SLI / SLO 정의 + error budget 운영 정책
├── runbooks/ 장애 대응 runbook 5건
└── dr/
├── dr-runbook.md Disaster Recovery 절차 + RTO/RPO
└── chaos-results.md Chaos 실험 결과 누적
```
## 系统流程
```
sequenceDiagram
autonumber
participant C as Client
participant API as orchestrator-api
participant DB as PostgreSQL
participant K8s as Kubernetes API
participant W as Worker Pod
participant K as Kafka
C->>API: POST /api/v1/jobs
API->>API: 쿼터 검사
API->>DB: INSERT job + outbox (one tx)
API->>K8s: create batch/v1 Job
API-->>C: 202 Accepted (jobId)
K8s->>W: schedule
W->>API: POST /internal/jobs/{id}/status (RUNNING)
API->>DB: UPDATE job (optimistic lock)
W->>API: POST /internal/jobs/{id}/status (SUCCEEDED)
API->>DB: UPDATE job + outbox event
Note over API,K: 별도 OutboxRelay 가 polling
API->>K: publish JobCompleted
C->>API: GET /api/v1/jobs/{id}/result-url
API-->>C: presigned URL
```
## 后端核心
核心是具有 `QUEUED → DISPATCHING → RUNNING → SUCCEEDED / FAILED / CANCELLED` 状态机的 Job
聚合(领域单元,将一起更改的对象进行分组)。用户配额
(并发运行任务数,GPU 总计)通过单一聚合查询(一次 SUM/COUNT 查询)进行检查,
从而无需将所有 Job 加载到内存中。即使回调和取消同时到达,也会通过 `@Version` 乐观
锁(假设冲突很少发生,先尝试提交,如果发生冲突则只保留一方的更改)保护,以确保
只有一方被提交。
在 DB 事务中,会同时将事件 INSERT 到 Outbox 表(先将事件写入数据库的发件箱)中,
然后由单独的 `OutboxRelay` 通过轮询将其发布到 Kafka。只有成功发布的行
才会填充 `published_at`,因此即使 Kafka 暂时宕机,也会在下次轮询时自动重试。
Kubernetes 调用 (`KubernetesJobDispatcher`) 和结果 URL 签发 (`PresignedUrlProvider`)
被分离为接口,使得在开发环境中可以使用 Mock 实现运行,在生产环境中则可以替换为
实际的实现。
测试由 44 个单元/切片测试和 1 个 Postgres Testcontainers 集成测试组成。
有关详细信息,请参阅 [`orchestrator-api/README.md`](orchestrator-api/README.md),设计决策依据请参阅
[25 份 ADR](orchestrator-api/docs/adr/),表和索引设计请参阅
[database-design.md](orchestrator-api/docs/database-design.md)。
## DevOps 核心
`infrastructure/terraform/` 中包含 cloud / hybrid / onprem 三种环境的模块。其中
`monitoring/` 模块可以通过 Helm 一次性部署 kube-prometheus-stack, Loki, Tempo, Mimir,
DCGM exporter。GPU 节点的 spot 选项和 NVIDIA driver 兼容的 AMI 也已变量化。
`infrastructure/ansible/` 用于引导不适合使用 EKS 等托管 Kubernetes 的环境(例如自有数据
中心的 GPU 节点)。它会自动安装 Docker, NVIDIA driver, k3s, Harbor 和监控
agent。
`infrastructure/ci-cd/` 中的 GitHub Actions 会分别运行单元测试、切片测试和 Testcontainers IT,
并在构建镜像后使用 Trivy 将具有 HIGH / CRITICAL 漏洞的构建标记为失败。应用了 Cosign keyless
签名,在推送标签时,会自动更新单独的 GitOps 存储库中的 kustomize image tag,以便
ArgoCD 进行同步。生产部署通过 Argo Rollouts 的 canary 策略进行。
`infrastructure/observability/` 中的警报和仪表板以 JSON / YAML 格式进行管理。因为在 Grafana UI
中通过点击创建的仪表板无法进行变更追踪和 PR 审查,因此我们坚持将其作为代码管理。
9 条 Prometheus 警报(5xx 比例,响应时间 p95 — 100个请求中第95个最慢的请求
标准,Outbox 发布延迟,K8s API 调用失败,Job 失败率等)都直接链接到 [runbook](docs/runbooks/)
(故障响应手册)。这是一种在发生故障时,可以从警报直接跳转到响应程序的配置。
`docs/slo.md` 中定义了可用性 99.9%,p95 300ms,Job 成功率 99% 的 SLO (Service Level Objective —
服务必须维护的目标数值),并总结了在 error budget (未达到目标的允许余地) 消耗达到 90% /
100% 时的运营策略。`docs/runbooks/` 中包含 5 份故障响应文档(5xx
激增,Outbox 发布延迟,回调丢失,K8s API 宕机,GPU OOM)。
`orchestrator-api/k8s/security/` 包含在 default-deny 环境(首先阻止所有
流量,仅允许通过的流量)中运行的 NetworkPolicy (Pod 间流量防火墙规则) 和
PodDisruptionBudget (部署和升级期间可以同时终止的 Pod 数量限制)。
ingress 仅允许 ingress-nginx、worker namespace 和 Prometheus,egress 仅允许 DNS, K8s API,
DB, Redis, Kafka, OTel collector。
## Helm chart
`helm/gpu-job-orchestrator/` 是将固定在单一环境中的 `orchestrator-api/k8s/` 清单按环境
分离的 chart。dev 使用 `values.yaml` 的默认值 (replica 1, leader=shedlock,
ingress / HPA / PDB / NetworkPolicy 全部关闭),prod 在其基础上覆盖 `values-prod.yaml`,
变为 replica 3, HPA 3 ~ 12, ingress TLS (cert-manager), PDB minAvailable=2, 启用 NetworkPolicy,
leader=lease (K8s coordination/Lease)。由于同一个 chart 同时支持这两种模式,因此
按环境划分的分支不会硬编码在模板中,使用 `helm diff` 进行变更追踪也非常清晰。
ServiceAccount 附带两种 RBAC Role。在 `gwp-jobs` namespace 中 batch/v1
Job 的创建/查看/delete 权限 (KubernetesJobDispatcher 启动 worker Pod 时所需),
以及自己 namespace 的 `coordination.k8s.io/Lease` 权限 (lease 模式的 leader election)。
Role 的 namespace 是分离的,从而缩小了爆炸半径,使得 orchestrator 无法操作其他 namespace 的 Pod。
```
# dev (本地 K8s — kind / k3s)
helm install orchestrator-api helm/gpu-job-orchestrator/ -n gwp --create-namespace
# prod (预装 cert-manager / NetworkPolicy CNI 的集群)
helm upgrade --install orchestrator-api helm/gpu-job-orchestrator/ \
-n gwp -f helm/gpu-job-orchestrator/values-prod.yaml \
--set image.tag=$IMAGE_TAG \
--set callback.existingSecret=orchestrator-callback-external
# 验证 — CI 中针对每个 PR 执行 lint + template 以阻断 schema 回归
helm lint helm/gpu-job-orchestrator/
helm template t helm/gpu-job-orchestrator/ -f helm/gpu-job-orchestrator/values-prod.yaml \
| kubectl apply --dry-run=client -f -
```
ingress 仅公开 4 种外部用户路径 (`/api/v1/jobs`, `/api/v1/dag`, `/api/v1/admin`,
`/api/v1/callbacks`),而 worker → orchestrator 的回调 (`/internal/*`) 在 prod 环境中会
通过 nginx 的 `server-snippet` 注解在 ingress 层被阻止。集群内部的回调会
直接调用 Service 的 ClusterIP,因此没有理由向外部公开。
现有的 `orchestrator-api/k8s/` 的静态清单作为 ADR / 学习资料保持原样,
实际部署路径统一到 chart 中。ArgoCD application 同步时会引用 chart 的 git ref 和
values-prod.yaml (`infrastructure/ci-cd/argocd/`)。
## 实际的 Worker 及 Autoscaling
`worker/` 中的 Go worker 会实际运行。当 orchestrator-api 将其作为 K8s Job 启动时,
worker 会发送 RUNNING 回调 → GPU 任务模拟 (sleep + CPU burn) → SUCCEEDED 回调,然后
终止。包含 Prometheus 指标、回调重试 (指数退避 — 失败越多重试间隔越长) 和 graceful shutdown (完成任务后干净地终止)。
`infrastructure/keda/` 中的 KEDA `ScaledJob` 会监控 Kafka `gwp.job.queue` 主题的 lag (尚未
处理的消息量),并在 0 ↔ N 之间自动扩缩 worker Pod (空闲时 GPU 成本为 0,
突发时通过 5秒轮询快速 scale-up)。Cluster Autoscaler 的
priority expander 会优先使用 spot (Spot 实例 — 比原价便宜但随时可能被收回的节点)
GPU 节点以降低成本。
`tests/load/` 中的 4 个 K6 场景 (submit-burst, sustained, spike, callback-flood)
会通过 nightly CI (每天夜间自动构建) 验证 SLO regression (性能目标倒退)。
如果 p95 > 300ms 或 5xx > 1%,则判定为失败。
## 供应链安全
CI 在每次构建时都会执行以下操作 (供应链安全 = 在代码从构建到投入运营的所有
阶段阻止篡改和恶意依赖项):
1. **Trivy** — 镜像漏洞扫描 (如果发现 HIGH/CRITICAL 级别漏洞,则构建失败)
2. **Syft** — SBOM (Software Bill of Materials,包含哪些库和版本的组件清单) 生成,CycloneDX 格式
3. **Cosign** — 镜像 + SBOM 的 keyless OIDC attestation (使用 Cosign 签名,但不使用密钥文件,
而是使用 GitHub OIDC token 证明身份,签名记录保留在公开的 transparency log 中)
4. **Trivy SBOM scan** — 仅对 SBOM 本身进行重新检查
K8s 端的 [`Kyverno cluster policies`](infrastructure/security/kyverno/) (admission webhook —
在 Pod 创建之前检查策略并可以拒绝它的钩子) 有 6 条,它们在 admission 阶段:
- 仅允许通过 Cosign 签名的镜像 (`gwp/*` namespace)
- 阻止 privileged Pod (拥有主机权限的危险 Pod)
- 强制要求 runAsNonRoot (以非 root 用户运行) + resource limits
- 禁止 `:latest` 标签 (因为无法追踪正在运行的是哪个版本)
- 阻止 hostNetwork/PID/IPC (直接连接主机的网络、进程、内存空间的选项)
凭据由 [`External Secrets Operator`](infrastructure/security/external-secrets/) 以 5 分钟的间隔从
AWS Secrets Manager 同步。不将 K8s `Secret` YAML 提交到 git 中。
运行时安全由 [`Falco`](infrastructure/security/falco/) 自定义规则实现 — 当 worker Pod 发生 shell
spawn (执行 Shell 进程) / 访问敏感文件 / 可疑 syscall (系统调用) 时会立即触发警报。
## 备份 / 灾难恢复
[`Velero`](infrastructure/dr/velero/) (K8s 集群备份与恢复工具) 通过两种计划进行备份:
- 每小时 Postgres PVC (数据库使用的磁盘卷,保留 24 小时)
- 每天凌晨整个 namespace (保留 30 天,跨区域 S3 复制 — 复制到其他区域的 S3)
[`docs/dr/dr-runbook.md`](docs/dr/dr-runbook.md) 中包含了按场景划分的恢复程序和 RTO 30 分钟 (从
发生故障到恢复完成的目标时间) / RPO 5 分钟 (可接受的数据丢失最大时间范围) 的
SLO。积累季度 DR drill (实际恢复训练) 结果。
## 混沌工程
混沌工程 = 故意注入故障以验证系统是否真正恢复的实验。
[`infrastructure/chaos/`](infrastructure/chaos/) 中的 Chaos Mesh 5 个实验定期运行:
- Pod kill — 强制终止 Pod,检查 PDB (PodDisruptionBudget — 可同时终止的 Pod 限制) 效果,每周一次
- Postgres network delay — 注入 DB 响应延迟,检查 HikariCP (DB 连接池) 行为
- Kafka partition 隔离 — 断开与 Kafka 的网络,检查 Outbox 自动恢复
- Worker CPU stress — 将 worker CPU 负载提升至 90%,检查回调重试行为
- GPU 节 drain — 强制排空 GPU 节点,检查 Job 自动重新提交
被打破的假设案例以及由此产生的代码修改历史记录在
[`docs/dr/chaos-results.md`](docs/dr/chaos-results.md) 中。
## 代码审查指南
如果按以下顺序查看后端流程,会更容易理解。
1. [`Job`](orchestrator-api/src/main/java/com/example/gwp/orchestrator/domain/Job.java):
这是一种仅通过方法而不是 setter 暴露状态更改以保护不变性的结构。
2. [`JobSubmissionService`](orchestrator-api/src/main/java/com/example/gwp/orchestrator/application/JobSubmissionService.java):
可以检查配额检查 → 保存到 DB → 调用 Kubernetes → 记录到 Outbox 的顺序。
3. [`JobLifecycleService`](orchestrator-api/src/main/java/com/example/gwp/orchestrator/application/JobLifecycleService.java):
包含回调/取消处理逻辑和对已结束 Job 的重复回调忽略 (幂等性) 处理。
4. [`OutboxRelay`](orchestrator-api/src/main/java/com/example/gwp/orchestrator/outbox/OutboxRelay.java):
可以检查 Kafka 发布和 published 标记的流程。
在 DevOps 方面,以下五个文件是核心。
1. [`monitoring/main.tf`](infrastructure/terraform/modules/monitoring/main.tf): 将整个可观测性栈
配置为单个模块的部分。
2. [`orchestrator-slo.yaml`](infrastructure/observability/prometheus-rules/orchestrator-slo.yaml):
可以检查 SLO 警报是如何连接到 runbook URL 的。
3. [`orchestrator-overview.json`](infrastructure/observability/grafana-dashboards/orchestrator-overview.json):
将仪表板作为代码管理的方法 (通过 Terraform `grafana_dashboard` 或 sidecar 导入)。
4. [`network-policy.yaml`](orchestrator-api/k8s/security/network-policy.yaml): default-deny
环境中运行的 ingress / egress 规则。
5. [`orchestrator-api-release.yml`](infrastructure/ci-cd/github-actions/orchestrator-api-release.yml):
从 PR 到生产部署的 CI/CD 整个流程。
## 快速开始
可以使用 H2 和 Mock K8s 模式在没有外部依赖项的情况下运行。
```
cd orchestrator-api
./gradlew bootRun
```
```
curl -s -X POST http://localhost:8080/api/v1/jobs \
-H 'Content-Type: application/json' \
-d '{"inputUri":"s3://demo/in.bin","image":"gpu-worker:1.0","gpuCount":1,"priority":"NORMAL"}' \
| tee /tmp/job.json | jq
JOB_ID=$(jq -r .id /tmp/job.json)
curl -s "http://localhost:8080/api/v1/jobs/$JOB_ID" | jq
curl -s "http://localhost:8080/api/v1/jobs/$JOB_ID/result-url" | jq
```
API 文档:
## Portfolio Set 集成
本存储库可以独立运行,但它也是由 8 个存储库像一套系统一样相互咬合而成的
portfolio set 的一个分支。完整的结构可以在个人资料 README — — 中找到。
| 存储库 | 一句话说明 | 与本存储库的关系 |
| --- | --- | --- |
| [auth-service](https://github.com/ssa1004/auth-service) | OAuth2 / OIDC IdP — JWT 签发 / JWK 轮换 / 2FA / introspect / revoke | 本存储库使用 JWK Set 验证传入请求的 JWT |
| [notification-hub](https://github.com/ssa1004/notification-hub) | 多渠道通知 (Email / SMS / push / Slack) | 消费本存储库发布的 `gwp.job.jobcompleted` / `jobpreempted` Kafka 事件 → 向用户进行 fan-out |
| [billing-platform](https://github.com/ssa1004/billing-platform) | 使用量聚合 / 账单 / 支付网关 | 消费 `gwp.job.jobcompleted` 并以 `gpuMillis × ratePerGpuHour` 记入账本 (单价记录由本存储库的 `JobCostRecord` 同时保存) |
| [security-log-search](https://github.com/ssa1004/security-log-search) | SIEM — 审计日志 / 安全事件搜索 | 在本存储库之外对本存储库的 K8s 审计日志进行 ECS 映射后摄取 |
| [search-service](https://github.com/ssa1004/search-service) | 通用域搜索 (商品 / 文档) | 与本存储库没有直接依赖 (portfolio set 的另一个分支) |
| [resell-orderbook](https://github.com/ssa1004/resell-orderbook) | 二手订单匹配引擎 | 与本存储库没有直接依赖 (portfolio set 的另一个分支) |
| [mini-shop-observability](https://github.com/ssa1004/mini-shop-observability) | OTel / Prometheus / Loki 操场 | observability 栈共用 — 本存储库的 Grafana 仪表板具有相同的模式 |
| **gpu-job-orchestrator** | 本存储库 — GPU job 队列 / 调度器 | — |
本存储库的集成点有三个方向:
1. **传入认证** — 使用 auth-service 的 JWK Set (`/oauth2/jwks`) 验证用户 / DAG 注册 / 取消
请求的 JWT。claim 中的 `sub` 被写入为 `Job.owner`。
2. **传出通知** — 在 Job 结束 (`SUCCEEDED` / `FAILED`) 或被抢占时 Outbox →
Kafka 发布 → notification-hub 消费。
3. **传出账单** — billing-platform 将 `JobCompleted` 事件中包含的 `finishedAt` 和本存储库的成本账本
(`/api/v1/cost/jobs/{id}` — 单价记录) 结合起来用于计费。
### 跨存储库序列 — 从用户 JWT 到通知/计费
```
sequenceDiagram
autonumber
participant U as User
participant Auth as auth-service
(IdP) participant API as orchestrator-api participant K8s as Kubernetes API
(prod) / mock (dev) participant W as Worker participant DB as Postgres participant K as Kafka participant N as notification-hub participant B as billing-platform U->>Auth: POST /oauth2/token (client_credentials) Auth-->>U: access_token (RS256 JWT) U->>API: POST /api/v1/jobs + Bearer JWT API->>API: JWK Set 으로 서명 검증 + 쿼터 검사 API->>DB: INSERT job + outbox(JobSubmitted) (one tx) API->>K8s: create batch/v1 Job (또는 mock 분기) API-->>U: 202 Accepted (jobId) K8s->>W: schedule W->>API: POST /internal/jobs/{id}/status (RUNNING) W->>API: POST /internal/jobs/{id}/status (SUCCEEDED + resultUri) API->>DB: UPDATE job + INSERT outbox(JobCompleted) + INSERT job_cost_records Note over API,K: OutboxRelay polling — published_at NULL 인 row 만 발행 API->>K: publish gwp.job.jobcompleted par 알림 fan-out K-->>N: consume gwp.job.jobcompleted N->>U: 채널별 알림 (메일 / Slack / push) and 빌링 적재 K-->>B: consume gwp.job.jobcompleted B->>API: GET /api/v1/cost/jobs/{id} (단가 박제 lookup) API-->>B: gpuMillis × ratePerGpuHour 결과 B->>B: ledger row 적재 (월 단위 청구서로 합산) end ``` ### 集成演示 (mock) 无需启动整个 portfolio,只需使用 **mock auth-service + mock notification-hub + mock billing-platform** 即可在单台主机上验证本存储库的集成点: ``` # 一次性启动 orchestrator-api (自身) + Postgres + Kafka + 3 stub docker compose -f infrastructure/docker/docker-compose.integration.yml up -d --build # 颁发 JWT → 提交 job → worker 回调 → 确认 notification + billing stub 双方均已收到 ./scripts/integration-demo.sh ``` 演示在容器内闭环完成,不进行任何外部 API 调用。K8s 调用由本存储库的 `gwp.kubernetes.enabled=false` 分支 (`MockJobDispatcher`) 替代,worker 回调由演示 脚本直接触发。有关详细流程,请参阅 [scripts/integration-demo.sh](scripts/integration-demo.sh) 头部注释。 ## 当前状态 包括 API, 领域, 用户配额, Kubernetes 调用, Outbox, JWT 认证, Redis 查询缓存, 45 个 测试 (44 个单元·切片 + 1 个 Postgres Testcontainers IT), Terraform / Ansible / ArgoCD 配置, 以及 Prometheus + Grafana + runbook。S3 / MinIO presigned URL 目前仍为 Mock 实现, 但接口 (`PresignedUrlProvider`) 已准备就绪。 在运营稳定性方面,已应用 ShedLock + K8s Lease 双重 leader election (ADR-0017), Resilience4j circuit breaker + Retry with jitter (ADR-0025), graceful shutdown (ADR-0024), 3 种探针分离 (ADR-0023), OTel W3C trace context + Baggage Kafka 标头 传播 (ADR-0018, 0021), Prometheus exemplars (ADR-0019), AsyncAPI + consumer-driven contract test (ADR-0020)。有关完整决策列表,请参阅 [ADR 索引](orchestrator-api/docs/adr/)。 ## 未来改进计划 - S3 / MinIO `PresignedUrlProvider` 生产环境实现 (目前为 Mock. presigned URL = 仅在一定时间内有效的下载链接) - 回调 mTLS 切换 (目前为共享密钥. mTLS = 客户端和服务器互相验证证书) - `Idempotency-Key` 标头处理 — 即使相同的请求到达两次也只处理一次的标头 (防止网络重试时重复创建) - Job timeout watcher — 当 RUNNING 超过预期持续时间的 1.5 倍时,强制与 K8s Pod 状态 同步。作为回调丢失的补充措施
(IdP) participant API as orchestrator-api participant K8s as Kubernetes API
(prod) / mock (dev) participant W as Worker participant DB as Postgres participant K as Kafka participant N as notification-hub participant B as billing-platform U->>Auth: POST /oauth2/token (client_credentials) Auth-->>U: access_token (RS256 JWT) U->>API: POST /api/v1/jobs + Bearer JWT API->>API: JWK Set 으로 서명 검증 + 쿼터 검사 API->>DB: INSERT job + outbox(JobSubmitted) (one tx) API->>K8s: create batch/v1 Job (또는 mock 분기) API-->>U: 202 Accepted (jobId) K8s->>W: schedule W->>API: POST /internal/jobs/{id}/status (RUNNING) W->>API: POST /internal/jobs/{id}/status (SUCCEEDED + resultUri) API->>DB: UPDATE job + INSERT outbox(JobCompleted) + INSERT job_cost_records Note over API,K: OutboxRelay polling — published_at NULL 인 row 만 발행 API->>K: publish gwp.job.jobcompleted par 알림 fan-out K-->>N: consume gwp.job.jobcompleted N->>U: 채널별 알림 (메일 / Slack / push) and 빌링 적재 K-->>B: consume gwp.job.jobcompleted B->>API: GET /api/v1/cost/jobs/{id} (단가 박제 lookup) API-->>B: gpuMillis × ratePerGpuHour 결과 B->>B: ledger row 적재 (월 단위 청구서로 합산) end ``` ### 集成演示 (mock) 无需启动整个 portfolio,只需使用 **mock auth-service + mock notification-hub + mock billing-platform** 即可在单台主机上验证本存储库的集成点: ``` # 一次性启动 orchestrator-api (自身) + Postgres + Kafka + 3 stub docker compose -f infrastructure/docker/docker-compose.integration.yml up -d --build # 颁发 JWT → 提交 job → worker 回调 → 确认 notification + billing stub 双方均已收到 ./scripts/integration-demo.sh ``` 演示在容器内闭环完成,不进行任何外部 API 调用。K8s 调用由本存储库的 `gwp.kubernetes.enabled=false` 分支 (`MockJobDispatcher`) 替代,worker 回调由演示 脚本直接触发。有关详细流程,请参阅 [scripts/integration-demo.sh](scripts/integration-demo.sh) 头部注释。 ## 当前状态 包括 API, 领域, 用户配额, Kubernetes 调用, Outbox, JWT 认证, Redis 查询缓存, 45 个 测试 (44 个单元·切片 + 1 个 Postgres Testcontainers IT), Terraform / Ansible / ArgoCD 配置, 以及 Prometheus + Grafana + runbook。S3 / MinIO presigned URL 目前仍为 Mock 实现, 但接口 (`PresignedUrlProvider`) 已准备就绪。 在运营稳定性方面,已应用 ShedLock + K8s Lease 双重 leader election (ADR-0017), Resilience4j circuit breaker + Retry with jitter (ADR-0025), graceful shutdown (ADR-0024), 3 种探针分离 (ADR-0023), OTel W3C trace context + Baggage Kafka 标头 传播 (ADR-0018, 0021), Prometheus exemplars (ADR-0019), AsyncAPI + consumer-driven contract test (ADR-0020)。有关完整决策列表,请参阅 [ADR 索引](orchestrator-api/docs/adr/)。 ## 未来改进计划 - S3 / MinIO `PresignedUrlProvider` 生产环境实现 (目前为 Mock. presigned URL = 仅在一定时间内有效的下载链接) - 回调 mTLS 切换 (目前为共享密钥. mTLS = 客户端和服务器互相验证证书) - `Idempotency-Key` 标头处理 — 即使相同的请求到达两次也只处理一次的标头 (防止网络重试时重复创建) - Job timeout watcher — 当 RUNNING 超过预期持续时间的 1.5 倍时,强制与 K8s Pod 状态 同步。作为回调丢失的补充措施
标签:Ansible, API集成, ArgoCD, Argo Rollouts, AWS EKS, Chaos Mesh混沌工程, CI/CD流水线, CISA项目, Cluster Autoscaler, Cosign镜像签名, DCGM exporter, DevOps全栈, ECS, External Secrets Operator, Falco运行时安全, Flyway, GET参数, GitHub Actions, GitOps, Go语言, GPU任务编排器, Grafana, Harbor镜像仓库, Helm, Java 17, JPA, JS文件枚举, JWT, k3s, KEDA事件驱动自动扩容, Kubernetes作业, Kyverno策略管理, Loki日志系统, Mimir长期存储, NVIDIA驱动, OAuth2, OpenTelemetry, Outbox模式, Prometheus SLO, Resilience4j, Saga模式, Spring Boot, StruQ, Syft SBOM, Tempo链路追踪, Terraform, Trivy漏洞扫描, Velero备份, 可观测性, 后端开发, 子域名变形, 子域名突变, 容器编排, 异步作业管理, 微服务架构, 搜索引擎查询, 日志审计, 机器学习推理, 测试用例, 深度学习训练, 程序破解, 系统提示词, 自动笔记, 自定义请求头, 请求拦截