Files
2026-06-01 13:54:52 +08:00

236 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Implementation Plan: Kubernetes Runtime Support
**Branch**: `dev-k8s` | **Date**: 2026-04-16 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/k8s-runtime-support/spec.md`
## Execution Flow (/plan command scope)
```
1. Load feature spec from Input path
2. Fill Technical Context
3. Constitution Check (empty constitution - skip)
4. Execute Phase 0 → research.md
5. Execute Phase 1 → contracts, data-model.md, quickstart.md
6. Re-evaluate Constitution Check
7. Plan Phase 2 → tasks.md (via /tasks command)
8. STOP - Ready for /tasks command
```
## Summary
修复 RCoder 的 Kubernetes 运行时支持,使系统能够在 K8s 环境中动态创建和管理容器Pod而不依赖 Docker Socket。
主要改动:
1. 重构 `global` 模块使用 `RuntimeManager` 选择运行时 **P0 - 关键路径)**
2. K8s Runtime 支持 `user_id` 参数 **P0 - ComputerAgent 支持)**
3. 修复 `stop_container` 方法正确处理不同 ServiceType **P0**
4. 更新 Makefile K8s 命令避免重复操作 **P1**
## Technical Context
**Language/Version**: Rust 1.75+ (2024 Edition)
**Primary Dependencies**: kube-rs 0.98, bollard, tonic, tower
**Storage**: N/A (状态在 K8s API 中)
**Testing**: cargo test, integration tests
**Target Platform**: Linux (Docker + Kubernetes)
**Performance Goals**: Pod 启动 < 120s, gRPC 延迟 < 100ms
**Constraints**:
- 必须兼容现有 Docker 模式
- K8s Service Account 需要预配置
- 需要 RBAC 权限创建/删除 Pod
## Problem Analysis (Updated 2026-04-20)
### P0 Issues (Critical - Blocking K8s)
| Issue | Location | Description |
|-------|----------|-------------|
| `RuntimeManager::init()` never called | `main.rs:181-186` | K8s mode calls `init_global_docker_manager_with_config()` which does NOT initialize `RuntimeManager::RUNTIME_INSTANCE` |
| `stop_container` ignores service_type | `kubernetes_runtime.rs:437` | Always uses `ServiceType::RCoder`, cannot stop ComputerAgentRunner pods |
| K8s path not properly initialized | `lib.rs:201-223` | `init_global_docker_manager_with_config()` has K8s code but never reaches it properly |
### Root Cause
```rust
// main.rs calls this:
docker_manager::global::init_global_docker_manager_with_config(config).await
// But this function does NOT call RuntimeManager::init() for K8s mode!
// It only sets GLOBAL_DOCKER_MANAGER (for Docker mode)
```
### Required Changes
1. **main.rs**: Initialize using `RuntimeManager::init()` for K8s, or modify `init_global_docker_manager_with_config()` to properly call `RuntimeManager::init()` when K8s mode detected
2. **kubernetes_runtime.rs**: Fix `stop_container` to handle different service types
## Constitution Check
*Note: Constitution file is empty template - no gates to check*
## Project Structure
### Documentation (this feature)
```
specs/k8s-runtime-support/
├── plan.md # This file
├── spec.md # Feature specification
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output (interfaces)
└── tasks.md # Phase 2 output (/tasks command)
```
### Source Code (repository root)
```
crates/
├── docker_manager/
│ ├── src/
│ │ ├── lib.rs # MODIFY: global module
│ │ └── runtime/
│ │ ├── mod.rs # MODIFY: export changes
│ │ ├── manager.rs # KEEP: RuntimeManager
│ │ ├── kubernetes_runtime.rs # MODIFY: fix issues
│ │ └── docker_runtime.rs # KEEP: unchanged
├── container-runtime-api/
│ └── src/
│ └── runtime_trait.rs # KEEP: trait definition
└── rcoder/
└── src/
└── main.rs # MODIFY: runtime init
```
**Structure Decision**: 修改现有 `docker_manager` crate重构 `global` 模块使其根据 `CONTAINER_RUNTIME` 环境变量选择 `RuntimeManager` 或直接使用 `DockerManager`
### K8s Local Development Environment
新增 `k8s/` 目录,用于本地 K8s 测试环境(类比现有 `docker/` 目录):
```
k8s/
├── README.md # K8s 环境使用说明
├── kind-config.yaml # Kind (Kubernetes IN Docker) 配置
├── start-kind.sh # 启动本地 K8s 集群脚本
├── stop-kind.sh # 停止本地 K8s 集群脚本
├── manifests/
│ ├── namespace.yaml # Namespace 定义
│ ├── serviceaccount.yaml # ServiceAccount + RBAC
│ ├── rcoder-deployment.yaml # RCoder 主服务 Deployment
│ └── rcoder-service.yaml # RCoder 主服务 Service
└── test-chat.sh # 测试脚本
```
**功能**
- 使用 [Kind](https://kind.sigs.k8s.io/) 在本地运行 K8s
- 一键启动本地 K8s 集群
- 部署 RCoder 到本地 K8s
- 测试 `/chat``/computer/chat` 接口
## Phase 0: Outline & Research
### Research Tasks
1. **K8s Pod IP 通信**: Pod 之间直接用 IP 通信,同 Docker 方式
2. **kube-rs 最佳实践**: 社区推荐的 K8s Runtime 实现模式
3. **K8s 健康检查**: HTTP Health Check 方式(与 Docker 一致)
4. **K8s 存储**: workspace 存储问题(标记为后续优化项)
### Output
**research.md**:
- Decision: 使用 Pod IP 直接通信(与 Docker 方式一致)
- Rationale: Pod IP 在同一集群内可直接通信,无需额外 ServicePod 重启后 cleanup_task 会重建并更新 IP
- Alternatives considered: Service DNS需要额外创建 Service增加复杂度当前不需要
## Phase 1: Design & Contracts
### Actual Code Changes Required
#### 1. Fix `lib.rs` - global module initialization
**Current (broken)**:
```rust
pub async fn init_global_docker_manager_with_config(config: DockerManagerConfig) -> DockerResult<()> {
let runtime_type = RuntimeType::from_env();
crate::runtime::RuntimeManager::init(config.clone()).await // <- Already calls RuntimeManager::init()!
if runtime_type == RuntimeType::Docker {
let manager = Arc::new(DockerManager::new(config).await?);
GLOBAL_DOCKER_MANAGER.set(manager)...;
}
// Problem: Sets RUNTIME_INSTANCE in RuntimeManager::init() but returns DockerResult
}
```
**Fix**: Ensure proper error handling and that K8s path doesn't try to set GLOBAL_DOCKER_MANAGER
#### 2. Fix `main.rs` - runtime initialization
**Current**: Calls `init_global_docker_manager_with_config()` which should work, but error handling may be wrong
**Fix**: Verify RuntimeManager is properly initialized before using `RuntimeManager::get()`
#### 3. Fix `kubernetes_runtime.rs` - stop_container
**Current**:
```rust
async fn stop_container(&self, project_id: &str) -> ContainerRuntimeResult<()> {
let pod_name = self.pod_name(project_id, &ServiceType::RCoder); // Always RCoder!
// ...
}
```
**Fix**: Need to track service_type per container or change the interface
#### 4. Fix Makefile k8s commands
**Current**:
```makefile
dev-up-k8s:
kubectl apply -f manifests/rcoder-deployment.yaml
kubectl set image deployment/rcoder rcoder=$(IMAGE) # Redundant after apply
dev-restart-k8s: dev-build-k8s
kubectl apply -f manifests/rcoder-deployment.yaml
kubectl set image deployment/rcoder rcoder=$(IMAGE)
kubectl rollout restart deploy/rcoder # rollout restart uses current deployment image, not new one!
```
**Fix**: Use `kubectl delete pods` or fix the image update flow
## Phase 2: Task Planning Approach
*This section describes what the /tasks command will do - DO NOT execute during /plan*
**Task Generation Strategy**:
- P0 优先级:先解决阻止 K8s 运行的 critical 问题
- P1 优先级:修复已知的 bug 和不完整实现
- P2 优先级:改进和优化
**Task Order (Dependency-Based)**:
1. **[P0] Fix global module initialization** - 确保 K8s 模式下 RuntimeManager 正确初始化
2. **[P0] Fix rcoder main.rs** - 调用正确的初始化函数
3. **[P0] Fix stop_container in KubernetesRuntime** - 正确处理不同 service_type
4. **[P1] Fix Makefile k8s commands** - 消除重复操作,简化逻辑
5. **[P1] Test K8s mode end-to-end** - 验证修复有效
6. **[P2] Improve K8s health check** - 如有时间,优化健康检查
**Estimated Output**: 8-10 focused tasks
## Complexity Tracking
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| 重构 global 模块 | 需要统一运行时选择逻辑 | 直接在 rcoder 中判断,但会导致代码重复 |
## Progress Tracking
**Phase Status**:
- [x] Phase 0: Research complete - research.md created
- [x] Phase 1: Design complete - data-model.md created
- [x] Phase 2: Task planning approach defined (above)
- [ ] Phase 3: Tasks generated (/tasks command)
- [ ] Phase 4: Implementation complete
- [ ] Phase 5: Validation passed
**Gate Status**:
- [x] Initial Constitution Check: N/A (empty constitution)
- [x] Post-Design Constitution Check: N/A
- [x] All NEEDS CLARIFICATION resolved
- [ ] Complexity deviations documented
---
*Based on Constitution v2.1.1 - See `/memory/constitution.md`*