Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ logs/

# vibe coding
.claude
.qwen
openspec
AGENTS.md
CLAUDE.md
QWEN.md
21 changes: 21 additions & 0 deletions cookbook/en/advanced_deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ async def deploy_to_k8s():
kube_config=K8sConfig(
k8s_namespace="agentscope-runtime",
kubeconfig_path=None,
service_type="LoadBalancer", # Options: LoadBalancer, ClusterIP, NodePort
),
registry_config=RegistryConfig(
registry_url="your-registry-url",
Expand Down Expand Up @@ -477,6 +478,26 @@ if __name__ == "__main__":
- Resource limits and health checks configured
- Can be scaled with `kubectl scale deployment`

**Service Type Configuration**:
- **`LoadBalancer`** (default): Best for production with external access via cloud provider's load balancer
- **`ClusterIP`**: For internal cluster access only. Use `kubectl port-forward deployment/<deployment-name> 8080:8080 -n agentscope-runtime` to access locally
- **`NodePort`**: Exposes service on each node at a static port (30000-32767). Access via `http://<node-ip>:<node-port>`. Useful for development environments

**Accessing Different Service Types**:
```bash
# LoadBalancer: Access via external IP
curl http://<external-ip>:8080/health

# ClusterIP: Use port-forward
kubectl port-forward deployment/agent-xxx 8080:8080 -n agentscope-runtime
curl http://127.0.0.1:8080/health

# NodePort: Access via node IP and allocated port
kubectl get nodes -o wide # Get node IP
kubectl get svc -n agentscope-runtime # Get NodePort
curl http://<node-ip>:<node-port>/health
```


## Method 4: Serverless Deployment: ModelStudio

Expand Down
21 changes: 20 additions & 1 deletion cookbook/en/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ agentscope deploy k8s SOURCE [OPTIONS]
| `--kube-config-path` | `-c` | path | `None` | Path to kubeconfig file |
| `--replicas` | integer | `1` | Number of pod replicas |
| `--port` | integer | `8080` | Container port |
| `--service-type` | choice | `"LoadBalancer"` | Service type: `LoadBalancer`, `ClusterIP`, `NodePort` |
| `--image-name` | string | `"agent_app"` | Docker image name |
| `--image-tag` | string | `"linux-amd64"` | Docker image tag |
| `--registry-url` | string | `"localhost"` | Remote registry URL |
Expand All @@ -589,7 +590,7 @@ agentscope deploy k8s SOURCE [OPTIONS]
##### Examples

```bash
# Basic deployment
# Basic deployment with LoadBalancer (default)
export USE_LOCAL_RUNTIME=True
agentscope deploy k8s app_agent.py \
--image-name agent_app \
Expand All @@ -598,6 +599,19 @@ agentscope deploy k8s app_agent.py \
--registry-url your-registry.com \
--push

# Deploy with ClusterIP (internal-only access)
agentscope deploy k8s app_agent.py \
--service-type ClusterIP \
--env DASHSCOPE_API_KEY=sk-xxx
# Access via: kubectl port-forward deployment/agent-xxx 8080:8080 -n agentscope-runtime
# Then visit: http://127.0.0.1:8080

# Deploy with NodePort (development/testing)
agentscope deploy k8s app_agent.py \
--service-type NodePort \
--env DASHSCOPE_API_KEY=sk-xxx
# Access via: http://<node-ip>:<node-port>

# Custom namespace and resources
agentscope deploy k8s app_agent.py \
--namespace production \
Expand All @@ -607,6 +621,11 @@ agentscope deploy k8s app_agent.py \
--env DASHSCOPE_API_KEY=sk-xxx
```

**Service Type Selection:**
- **`LoadBalancer`** (default): Best for production deployments requiring external access via cloud provider's load balancer
- **`ClusterIP`**: For internal-only access within the cluster. Requires `kubectl port-forward` for local development
- **`NodePort`**: Exposes service on each node's IP at a static port (30000-32767). Good for development or when LoadBalancer is unavailable

**Note:** `USE_LOCAL_RUNTIME=True` uses local agentscope runtime instead of PyPI version.

### 5. Deployment Management
Expand Down
21 changes: 21 additions & 0 deletions cookbook/zh/advanced_deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ async def deploy_to_k8s():
kube_config=K8sConfig(
k8s_namespace="agentscope-runtime",
kubeconfig_path=None,
service_type="LoadBalancer", # 选项:LoadBalancer、ClusterIP、NodePort
),
registry_config=RegistryConfig(
registry_url="your-registry-url",
Expand Down Expand Up @@ -472,6 +473,26 @@ if __name__ == "__main__":
- 配置资源限制和健康检查
- 可使用 `kubectl scale deployment` 进行扩展

**服务类型配置**:
- **`LoadBalancer`**(默认):适合生产环境,通过云服务商的负载均衡器提供外部访问
- **`ClusterIP`**:仅限集群内部访问。本地访问需使用 `kubectl port-forward deployment/<deployment-name> 8080:8080 -n agentscope-runtime`
- **`NodePort`**:在每个节点上暴露静态端口(30000-32767)。通过 `http://<节点IP>:<节点端口>` 访问。适合开发环境

**访问不同服务类型**:
```bash
# LoadBalancer:通过外部 IP 访问
curl http://<external-ip>:8080/health

# ClusterIP:使用端口转发
kubectl port-forward deployment/agent-xxx 8080:8080 -n agentscope-runtime
curl http://127.0.0.1:8080/health

# NodePort:通过节点 IP 和分配的端口访问
kubectl get nodes -o wide # 获取节点 IP
kubectl get svc -n agentscope-runtime # 获取 NodePort
curl http://<节点IP>:<节点端口>/health
```


## 方法4:Serverless部署:ModelStudio

Expand Down
21 changes: 20 additions & 1 deletion cookbook/zh/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ agentscope deploy k8s SOURCE [OPTIONS]
| `--kube-config-path` | `-c` | path | `None` | kubeconfig 文件路径 |
| `--replicas` | integer | `1` | Pod 副本数量 |
| `--port` | integer | `8080` | 容器端口 |
| `--service-type` | choice | `"LoadBalancer"` | 服务类型:`LoadBalancer`、`ClusterIP`、`NodePort` |
| `--image-name` | string | `"agent_app"` | Docker 镜像名称 |
| `--image-tag` | string | `"linux-amd64"` | Docker 镜像标签 |
| `--registry-url` | string | `"localhost"` | 远程注册表 URL |
Expand All @@ -588,7 +589,7 @@ agentscope deploy k8s SOURCE [OPTIONS]
##### 示例

```bash
# 基本部署
# 使用 LoadBalancer 的基本部署(默认)
export USE_LOCAL_RUNTIME=True
agentscope deploy k8s app_agent.py \
--image-name agent_app \
Expand All @@ -597,6 +598,19 @@ agentscope deploy k8s app_agent.py \
--registry-url your-registry.com \
--push

# 使用 ClusterIP 部署(仅集群内部访问)
agentscope deploy k8s app_agent.py \
--service-type ClusterIP \
--env DASHSCOPE_API_KEY=sk-xxx
# 访问方式:kubectl port-forward deployment/agent-xxx 8080:8080 -n agentscope-runtime
# 然后访问:http://127.0.0.1:8080

# 使用 NodePort 部署(开发/测试环境)
agentscope deploy k8s app_agent.py \
--service-type NodePort \
--env DASHSCOPE_API_KEY=sk-xxx
# 访问方式:http://<节点IP>:<节点端口>

# 自定义命名空间和资源
agentscope deploy k8s app_agent.py \
--namespace production \
Expand All @@ -606,6 +620,11 @@ agentscope deploy k8s app_agent.py \
--env DASHSCOPE_API_KEY=sk-xxx
```

**服务类型选择:**
- **`LoadBalancer`**(默认):适合生产环境部署,需要通过云服务商的负载均衡器对外提供访问
- **`ClusterIP`**:仅限集群内部访问。本地开发需要使用 `kubectl port-forward` 进行端口转发
- **`NodePort`**:在每个节点的 IP 上暴露静态端口(30000-32767)。适合开发环境或无法使用 LoadBalancer 的场景

**注意:** `USE_LOCAL_RUNTIME=True` 使用本地 agentscope runtime 而不是 PyPI 版本。

### 5. 部署管理
Expand Down
24 changes: 24 additions & 0 deletions examples/deployments/k8s_deploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,36 @@ registry_config = RegistryConfig(
k8s_config = K8sConfig(
k8s_namespace="agentscope-runtime",
kubeconfig_path="your-kubeconfig-local-path",
service_type="LoadBalancer", # Options: LoadBalancer, ClusterIP, NodePort
)
```

- **`k8s_namespace`**: Kubernetes namespace where resources will be deployed
- Creates the namespace if it doesn't exist
- **`kubeconfig_path`**: Path to kubeconfig file (None uses default kubectl config at your local require kubectrl running)
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: "kubectrl" should be "kubectl".

Suggested change
- **`kubeconfig_path`**: Path to kubeconfig file (None uses default kubectl config at your local require kubectrl running)
- **`kubeconfig_path`**: Path to kubeconfig file (None uses default kubectl config at your local require kubectl running)

Copilot uses AI. Check for mistakes.
- **`service_type`**: Kubernetes service type for exposing the deployment (default: LoadBalancer)
- **`LoadBalancer`**: Exposes the service externally via a cloud provider's load balancer. Best for production deployments requiring external access.
- **`ClusterIP`**: Creates an internal IP only accessible within the cluster. Use this for internal-only services or when using `kubectl port-forward` for access.
- **`NodePort`**: Exposes the service on each node's IP at a static port (30000-32767). Useful for development or when LoadBalancer is not available.

#### Service Type Examples

**For production with external access:**
```python
k8s_config = K8sConfig(service_type="LoadBalancer")
```

**For internal cluster communication only:**
```python
k8s_config = K8sConfig(service_type="ClusterIP")
# Access via: kubectl port-forward deployment/agent-xxx 8080:8080
```

**For development or local clusters:**
```python
k8s_config = K8sConfig(service_type="NodePort")
# Access via: http://<node-ip>:<node-port>
```

### Runtime Configuration

Expand Down
5 changes: 5 additions & 0 deletions examples/deployments/k8s_deploy/app_deploy_to_k8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@ async def deploy_app_to_k8s():
},
# Image pull policy
"image_pull_policy": "IfNotPresent",
# Service type configuration:
# - LoadBalancer: External access via cloud provider (default)
# - ClusterIP: Internal cluster access only, requires port-forward
# - NodePort: Access via node IP and allocated port
# service_type="ClusterIP", # Uncomment for cluster-internal access
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment shows a commented-out example with the key name service_type but this key should be nested inside runtime_config based on the actual implementation. The comment should be updated to show the correct usage as a key within the runtime_config dictionary, like:

runtime_config = {
    "service_type": "ClusterIP",  # Uncomment for cluster-internal access
}

or demonstrate setting it directly in the deployment call.

Suggested change
# service_type="ClusterIP", # Uncomment for cluster-internal access
# "service_type": "ClusterIP", # Uncomment for cluster-internal access

Copilot uses AI. Check for mistakes.
}

# 5. Deployment configuration
Expand Down
1 change: 1 addition & 0 deletions examples/deployments/k8s_deploy/k8s_deploy_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"namespace": "agentscope-runtime",
"replicas": 1,
"port": 8080,
"service_type": "LoadBalancer",
"image_name": "agent_app",
"image_tag": "linux-amd64-1",
"base_image": "python:3.10-slim-bookworm",
Expand Down
6 changes: 6 additions & 0 deletions examples/deployments/k8s_deploy/k8s_deploy_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ namespace: "agentscope-runtime"
replicas: 1
port: 8080

# Service type configuration
# - LoadBalancer: External access via cloud provider (default)
# - ClusterIP: Internal cluster access only, requires port-forward
# - NodePort: Access via node IP and allocated port
service_type: "LoadBalancer"

# Docker image settings
image_name: "agent_app"
image_tag: "linux-amd64-1"
Expand Down
61 changes: 61 additions & 0 deletions src/agentscope_runtime/cli/commands/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,12 @@ def agentrun(
help="Target platform (e.g., 'linux/amd64', 'linux/arm64')",
default="linux/amd64",
)
@click.option(
"--service-type",
help="Kubernetes service type",
type=click.Choice(["LoadBalancer", "ClusterIP", "NodePort"]),
default="LoadBalancer",
)
def k8s(
source: str,
name: str,
Expand All @@ -854,6 +860,7 @@ def k8s(
deploy_timeout: int,
health_check: bool,
platform: str,
service_type: str,
):
"""
Deploy to Kubernetes/ACK.
Expand Down Expand Up @@ -898,6 +905,7 @@ def k8s(
"deploy_timeout": deploy_timeout,
"health_check": health_check,
"platform": platform,
"service_type": service_type,
}
merged_config = _merge_config(config_dict, cli_params)

Expand All @@ -918,6 +926,7 @@ def k8s(
deploy_timeout = merged_config.get("deploy_timeout", 300)
health_check = merged_config.get("health_check", True)
platform = merged_config.get("platform")
service_type = merged_config.get("service_type", "LoadBalancer")

# Handle requirements (can be comma-separated string, list, or file
# path)
Expand Down Expand Up @@ -963,6 +972,7 @@ def k8s(

if image_pull_policy and "image_pull_policy" not in runtime_config:
runtime_config["image_pull_policy"] = image_pull_policy
runtime_config["service_type"] = service_type

# Validate source
abs_source, source_type = _validate_source(source)
Expand Down Expand Up @@ -1050,6 +1060,57 @@ def k8s(
echo_info(f"Namespace: {namespace}")
echo_info(f"Replicas: {replicas}")

# Add service-type specific instructions
if service_type == "ClusterIP":
echo_info("")
echo_info("=== ClusterIP Service Access Instructions ===")
echo_info(
"This service is only accessible within the cluster or via "
"port-forward.",
)
echo_info(
"To access locally, run the following command in another "
"terminal:",
)
echo_info(
f" kubectl port-forward deployment/{resource_name} {port}:"
f"{port} -n {namespace}",
)
echo_info(f"Then access via: {url}")
echo_info(
f"Cluster-internal DNS: http://{resource_name}."
f"{namespace}.svc.cluster.local:{port}",
)
elif service_type == "NodePort":
echo_info("")
echo_info("=== NodePort Service Access Instructions ===")
echo_info(
"This service is accessible via NodePort.",
)
echo_info(f"Access URL: {url}")
echo_info(
"To get the node IP in cloud environments, run:",
)
echo_info(
" kubectl get nodes -o wide",
)
echo_info(
"Then access via: http://<NODE-IP>:<NODE-PORT>",
)
elif service_type == "LoadBalancer":
echo_info("")
echo_info("=== LoadBalancer Service Access Instructions ===")
echo_info(
"This service is accessible via external LoadBalancer.",
)
echo_info(f"Access URL: {url}")
echo_info(
"If the LoadBalancer IP is pending, run:",
)
echo_info(
f" kubectl get svc {resource_name}-service -n {namespace}",
)

except Exception as e:
echo_error(f"Deployment failed: {e}")
import traceback
Expand Down
Loading