使用自定义镜像扩展 Sandbox 服务

更新时间:
复制为 MD 格式

AgentRun Sandbox 的 AIO(All-In-One)镜像内置了 Code Interpreter 和 BrowserTool 两类能力。如果您需要在同一沙箱实例中运行自己的服务(例如自定义 API、数据处理进程),可以通过扩展 AIO 基础镜像的方式实现,无需修改 AIO 原有代码。

本文以一个简单的 Python Echo Server 为例,介绍如何将自定义服务集成到 AIO 沙箱中。同样的方式适用于 CodeInterpreter、Browser 等其他基础镜像。

工作原理

AIO 镜像内置了两个核心组件:

  • Process Compose:进程编排工具,负责管理沙箱内所有自启动进程。

  • OpenResty(Nginx):反向代理服务,负责将外部请求路由到内部各服务。

由于 AgentRun 的运行环境限制,沙箱实例对外只暴露一个端口(5000)。所有外部请求都通过 OpenResty 按路径分发到内部的不同服务。

AIO 镜像的启动脚本(entrypoint.sh)在容器启动时会自动扫描以下目录,加载用户扩展的服务配置:

配置类型

扫描目录

作用

进程配置

/etc/sandbox/config/process-compose.*.yaml

自动启动并管理自定义进程

Nginx Upstream

/etc/sandbox/config/nginx/http.d/

注册后端服务地址

Nginx 路由

/etc/sandbox/config/nginx/conf.d/

将 URL 路径映射到对应服务

因此,扩展 AIO 镜像只需要做一件事:向正确目录放置配置文件。

前提条件

开始前,请确认以下条件已满足:

  • 已完成 AgentRun SLR 服务角色授权(首次使用时在控制台根据提示完成)。

  • 已在控制台创建 AIO 沙箱模板。

  • 本地已安装 Docker,能够构建和运行容器镜像。

  • 熟悉 Docker、Nginx 基本概念。

操作步骤

以下示例将一个 Python Echo Server 集成到 AIO 沙箱中,通过/echo路径对外提供服务。

您可以下载完整的示例代码包:echoserver.zip

文件结构

新建echoserver/目录,按以下结构组织文件:

echoserver/
├── echo_server.py
└── config/
 ├── process-compose.echoserver.yaml
 ├── nginx-echoserver-upstream.conf
 └── nginx-echoserver-routes.conf

步骤一:编写服务代码

创建 echo_server.py,实现一个简单的 HTTP 服务,GET 请求返回ok

#!/usr/bin/env python3
import os
from http.server import HTTPServer, BaseHTTPRequestHandler

DEFAULT_PORT = 9000

class EchoHandler(BaseHTTPRequestHandler):
 def do_GET(self):
 self.send_response(200)
 self.send_header('Content-Type', 'text/plain; charset=utf-8')
 self.end_headers()
 self.wfile.write(b'ok\n')

def main():
 port = int(os.environ.get('ECHO_SERVER_PORT', DEFAULT_PORT))
 host = os.environ.get('ECHO_SERVER_HOST', '0.0.0.0')
 server = HTTPServer((host, port), EchoHandler)
 print(f"[echoserver] Starting echo server on {host}:{port}")
 try:
 server.serve_forever()
 except KeyboardInterrupt:
 server.shutdown()

if __name__ == '__main__':
 main()

步骤二:配置Process Compose

创建process-compose.echoserver.yaml,定义服务的启动方式、健康检查和日志:

version: "0.5"

log_level: info

environment:
 - PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

processes:
 echoserver:
 command: "python3 /usr/local/bin/echo_server.py"
 availability:
 restart: "always"
 backoff_seconds: 2
 max_restarts: 5
 readiness_probe:
 http_get:
 host: localhost
 port: ${ECHO_SERVER_PORT:-9000}
 path: /
 initial_delay_seconds: 1
 period_seconds: 5
 timeout_seconds: 2
 success_threshold: 1
 failure_threshold: 3
 environment:
 - ECHO_SERVER_HOST=0.0.0.0
 - ECHO_SERVER_PORT=9000
 - PYTHONUNBUFFERED=1
 - PYTHONDONTWRITEBYTECODE=1
 log_configuration:
 disable_json: true
 no_metadata: false
 add_timestamp: true
 timestamp_format: "2006-01-02 15:04:05.000"
 fields_to_append:
 - level=INFO

步骤三:配置Nginx

Upstream 配置:创建nginx-echoserver-upstream.conf,定义后端服务地址:

upstream echoserver {
 server localhost:9000;
 keepalive 16;
}

路由配置:创建nginx-echoserver-routes.conf,将/echo路径代理到 echo server:

location /echo {
 proxy_pass http://echoserver;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto $scheme;
 proxy_connect_timeout 60s;
 proxy_send_timeout 60s;
 proxy_read_timeout 60s;
 proxy_http_version 1.1;
 proxy_set_header Upgrade $http_upgrade;
 proxy_set_header Connection $connection_upgrade;
}

步骤四:编写Dockerfile

创建Dockerfile,以 AIO 基础镜像为基础,将服务代码和配置文件复制到对应目录:

FROM serverless-registry.cn-hangzhou.cr.aliyuncs.com/functionai/sandbox-all-in-one:v0.9.29

USER root

# 复制服务代码
COPY echo_server.py /usr/local/bin/echo_server.py
RUN chmod +x /usr/local/bin/echo_server.py

# Process Compose 配置(entrypoint.sh 自动扫描 /etc/sandbox/config/ 目录)
COPY config/process-compose.echoserver.yaml /etc/sandbox/config/process-compose.echoserver.yaml

# Nginx 配置(entrypoint.sh 自动扫描并加载)
RUN mkdir -p /etc/sandbox/config/nginx/http.d /etc/sandbox/config/nginx/conf.d
COPY config/nginx-echoserver-upstream.conf /etc/sandbox/config/nginx/http.d/echoserver-upstream.conf
COPY config/nginx-echoserver-routes.conf /etc/sandbox/config/nginx/conf.d/echoserver-routes.conf

ENV ECHO_SERVER_HOST=0.0.0.0 \
 ECHO_SERVER_PORT=9000

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["process-compose", "up", "--tui=false", "--no-server"]

步骤五:构建并运行

cd echoserver

# 构建镜像
docker build -f Dockerfile -t echoserver-extension:latest .

# 本地运行(将容器的 5000 端口映射到本地 5000)
docker run --rm \
 -p 5000:5000 \
 --name echoserver-test \
 echoserver-extension:latest

步骤六:验证

# 通过 Nginx 代理访问 echo server
curl http://localhost:5000/echo
# 预期返回: ok

在 AgentRun 上部署后,访问地址格式如下:

https://{账号ID}.agentrun-data.cn-hangzhou.aliyuncs.com/sandboxes/{沙箱ID}/echo

配置参考

Process Compose 配置

process-compose.*.yaml支持以下核心配置项:

配置项

说明

command

服务启动命令

availability.restart

重启策略,"always"表示异常退出时自动重启

readiness_probe.http_get

HTTP 健康检查,服务提供/health等端点时推荐使用

readiness_probe.exec

进程健康检查,服务未提供 HTTP 端点时使用

environment

服务运行所需的环境变量

log_configuration

日志格式配置

Nginx Upstream 配置

定义后端服务地址,放置在/etc/sandbox/config/nginx/http.d/目录:

upstream your_service {
 server localhost:9001; # 自定义服务内部端口
 keepalive 16;
}

Nginx 路由配置

定义 URL 路径到 upstream 的映射,放置在/etc/sandbox/config/nginx/conf.d/目录。

基本路由:

location /your-service {
 proxy_pass http://your_service;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto $scheme;
}

使用 rewrite 转换路径:

如果需要在转发前改写 URL 路径,可以使用rewrite指令。例如,将外部路径/api/v1/echo转换为后端期望的/echo

location /api/v1/echo {
 rewrite ^/api/v1/echo(.*)$ /echo$1 break;
 proxy_pass http://echoserver;
 proxy_set_header Host $host;
}

rewrite指令说明:

  • ^/api/v1/echo(.*)$:匹配路径,(.*)捕获尾部内容。

  • /echo$1:改写后的路径,$1为捕获内容。

  • break:停止后续 rewrite 规则处理,直接将改写后的路径传给proxy_pass

更多 rewrite 示例:

# 移除路径前缀:/api/echo/xxx → /echo/xxx
location /api/echo {
 rewrite ^/api/echo(.*)$ /echo$1 break;
 proxy_pass http://echoserver;
}
# 添加路径前缀:/echo → /v1/echo
location /echo {
 rewrite ^/echo(.*)$ /v1/echo$1 break;
 proxy_pass http://echoserver;
}

文件命名规范

建议遵循以下命名约定,保持团队一致性:

配置类型

命名格式

示例

Process Compose

process-compose.<服务名>.yaml

process-compose.echoserver.yaml

Nginx Upstream

nginx-<服务名>-upstream.conf

nginx-echoserver-upstream.conf

Nginx 路由

nginx-<服务名>-routes.conf

nginx-echoserver-routes.conf

注意事项

  • 端口冲突:自定义服务的内部端口不能与 AIO 内置服务冲突,建议使用 9000 及以上端口。AIO 内置服务端口:

    • Nginx 内置网关:5000

    • Code Interpreter:5001

    • BrowserTool:3000

  • 健康检查:如果服务提供 HTTP 健康检查端点(如/health),建议在process-compose.*.yaml中使用readiness_probe.http_get;否则使用readiness_probe.exec检查进程是否存活。

  • 服务命名唯一性process-compose.*.yamlprocesses下的服务名(key)在同一沙箱内必须唯一。

  • 路由路径唯一性location路径不能与 AIO 内置路由冲突。AIO 内置路由:

    • Code Interpreter 占用://contexts/execute

    • BrowserTool 占用:/ws/automation/recordings

故障排查

服务未启动

# 查看 process-compose 日志
docker logs echoserver-test | grep echoserver

# 确认进程是否运行
docker exec echoserver-test pgrep -f echo_server.py

# 确认 Process Compose 配置已加载
docker exec echoserver-test ls -la /etc/sandbox/config/process-compose.*.yaml

Nginx 配置错误

# 验证 Nginx 配置语法
docker exec echoserver-test /usr/local/openresty/nginx/sbin/nginx -t

# 查看 Nginx 错误日志
docker exec echoserver-test tail -f /var/log/nginx/error.log

# 确认 upstream 配置已加载
docker exec echoserver-test cat /etc/sandbox/config/nginx/http.d/echoserver-upstream.conf

# 确认路由配置已加载
docker exec echoserver-test cat /etc/sandbox/config/nginx/conf.d/echoserver-routes.conf

路由不工作

# 确认 Nginx conf.d 目录内容
docker exec echoserver-test ls -la /etc/sandbox/config/nginx/conf.d/

# 直接访问内部服务(绕过 Nginx),确认服务本身是否正常
docker exec echoserver-test curl http://localhost:9000/

# 查看 Nginx 访问日志,确认请求是否到达
docker exec echoserver-test tail -f /var/log/nginx/access.log