Files
qiming/qiming-rcoder/specs/k8s-runtime-support/data-model.md
2026-06-01 13:54:52 +08:00

8.6 KiB
Raw Permalink Blame History

Data Model: Kubernetes Runtime Support

Date: 2026-04-16
Feature: K8s Runtime Support

1. Interface Changes

1.1 ContainerRuntime Trait (container-runtime-api)

Location: crates/container-runtime-api/src/runtime_trait.rs

Existing Methods:

pub trait ContainerRuntime: Send + Sync {
    async fn create_container(&self, project_id, user_id, host_workspace_path, service_type, resource_limits) -> Result<ContainerBasicInfo>;
    async fn get_container_info(&self, project_id) -> Result<Option<ContainerBasicInfo>>;
    async fn find_container(&self, project_id, service_type) -> Result<Option<RuntimeContainerInfo>>;
    async fn stop_container(&self, project_id) -> Result<()>;
    async fn is_container_running(&self, project_id) -> Result<bool>;
    async fn list_containers(&self) -> Result<Vec<RuntimeContainerInfo>>;
    async fn cleanup_all(&self) -> Result<()>;
    async fn health_check(&self) -> Result<()>;
}

New Methods:

// 新增: 按标签列出容器
async fn list_containers_by_label(&self, label_selector: &str) -> Result<Vec<RuntimeContainerInfo>>;

// 新增: 获取 Pod 的 DNS 名称
fn get_service_dns_name(&self, project_id: &str, user_id: Option<&str>) -> String;

2. KubernetesRuntime Implementation

Location: crates/docker_manager/src/runtime/kubernetes_runtime.rs

2.1 Config Changes

#[derive(Debug, Clone)]
pub struct KubernetesRuntimeConfig {
    pub namespace: String,
    pub pod_ttl_seconds: Option<u64>,
    pub image_pull_secret: Option<String>,
    pub service_account_name: String,
    // 新增: DNS 域名后缀
    pub cluster_domain: String,  // 默认: "cluster.local"
}

2.2 Service DNS Name Generation

impl KubernetesRuntime {
    /// Generate stable service DNS name for a pod
    /// 
    /// Format: {prefix}-{id}.{namespace}.svc.{cluster_domain}
    /// Examples:
    ///   - RCoder: rcoder-agent-{project_id}.default.svc.cluster.local
    ///   - Computer: computer-agent-runner-{user_id}.default.svc.cluster.local
    pub fn get_service_dns_name(&self, project_id: &str, user_id: Option<&str>) -> String {
        let prefix = match user_id {
            Some(uid) => format!("computer-agent-runner-{}", uid),
            None => format!("rcoder-agent-{}", project_id),
        };
        format!(
            "{}.{}.svc.{}",
            prefix, self.namespace, self.config.cluster_domain
        )
    }
}

2.3 ContainerBasicInfo with Service URL

// KubernetesRuntime 返回的 ContainerBasicInfo.service_url 使用 DNS
ContainerBasicInfo {
    // ...
    container_ip: pod_ip,              // 仍保留 Pod IP用于内部参考
    service_url: format!(              // 使用稳定的 DNS
        "http://{}:{}",
        self.get_service_dns_name(project_id, user_id),
        shared_types::GRPC_DEFAULT_PORT
    ),
    // ...
}

2.4 user_id Support in create_container

async fn create_container(
    &self,
    project_id: Option<&str>,
    user_id: Option<&str>,  // ← 现在处理 user_id
    host_workspace_path: &str,
    service_type: ServiceType,
    resource_limits: Option<ServiceResourceLimits>,
) -> ContainerRuntimeResult<ContainerBasicInfo> {
    // 确定容器标识符
    let identifier = user_id.or(project_id).ok_or_else(|| {
        ContainerRuntimeError::ConfigurationError(
            "Either project_id or user_id must be provided".to_string()
        )
    })?;

    // 生成 Pod 名称时考虑 user_id
    let pod_name = match user_id {
        Some(uid) => format!("computer-agent-runner-{}", uid),
        None => format!("rcoder-agent-{}", project_id.unwrap()),
    };

    // ... 后续逻辑
}

2.5 list_containers_by_label Implementation

async fn list_containers_by_label(
    &self,
    label_selector: &str,
) -> ContainerRuntimeResult<Vec<RuntimeContainerInfo>> {
    let lp = ListParams::default().labels(label_selector);
    let pods = self.pods().list(&lp).await?;
    
    let mut result = Vec::new();
    for p in pods.items {
        let pod: Pod = p;
        // ... 转换逻辑
        result.push(RuntimeContainerInfo { ... });
    }
    Ok(result)
}

3. Global Module Changes

Location: crates/docker_manager/src/lib.rs

3.1 New Initialization API

pub mod global {
    // 修改: 添加 runtime_type 参数
    pub async fn init_global_runtime(
        runtime_type: RuntimeType,
        config: DockerManagerConfig,
    ) -> DockerResult<()> {
        match runtime_type {
            RuntimeType::Kubernetes => {
                RuntimeManager::init(config).await?;
            }
            RuntimeType::Docker => {
                init_docker_manager_direct(config).await?;
            }
        }
    }

    // 新增: 获取运行时类型
    pub fn get_runtime_type() -> RuntimeType {
        RuntimeType::from_env()
    }
}

3.2 Backward Compatibility

// 保持向后兼容的初始化方法
pub async fn init_global_docker_manager_with_config(
    config: DockerManagerConfig,
) -> DockerResult<()> {
    // 自动检测运行时类型
    init_global_runtime(RuntimeType::from_env(), config).await
}

4. Error Types

Location: crates/container-runtime-api/src/runtime_trait.rs

#[derive(Error, Debug)]
pub enum ContainerRuntimeError {
    #[error("Connection error: {0}")]
    ConnectionError(String),

    #[error("Container creation failed: {0}")]
    ContainerCreationError(String),

    // ... existing errors ...

    // 新增 K8s 相关错误
    #[error("Kubernetes error: {0}")]
    K8sError(String),

    #[error("Pod not found: {0}")]
    PodNotFound(String),

    #[error("Service DNS resolution failed: {0}")]
    DnsResolutionError(String),
}

5. Entity Relationships

┌─────────────────────────────────────────────────────────────┐
│                      RuntimeManager                          │
│  - select_runtime() -> Arc<dyn ContainerRuntime>            │
└─────────────────────────┬───────────────────────────────────┘
                          │
          ┌───────────────┴───────────────┐
          │                               │
          ▼                               ▼
┌─────────────────┐           ┌─────────────────────┐
│  DockerRuntime  │           │ KubernetesRuntime   │
│  (wrapper)      │           │                     │
├─────────────────┤           ├─────────────────────┤
│ - inner:        │           │ - client: Client    │
│   DockerManager │           │ - namespace: String  │
├─────────────────┤           │ - config: K8sConfig │
│ Implements:     │           ├─────────────────────┤
│ ContainerRuntime           │ Implements:         │
└─────────────────┘           │ ContainerRuntime    │
                              │ + Service DNS      │
                              └─────────────────────┘

6. State Transitions

Container State (K8s)

                    ┌──────────┐
                    │ Pending  │
                    └─────┬────┘
                          │ (Pod scheduled)
                          ▼
                    ┌──────────┐
        ┌──────────│ Running  │──────────┐
        │          └────┬─────┘          │
        │               │ (container     │
        │               │ exits)        │
        ▼               ▼                ▼
   ┌─────────┐    ┌──────────┐    ┌──────────┐
   │ Succeeded│    │ Failed   │    │ Unknown  │
   └─────────┘    └──────────┘    └──────────┘

RCoder Container Status Mapping

K8s Phase RCoder Status
Pending Creating
Running Running
Succeeded Stopped
Failed Failed
Unknown Unknown