概述
本教程将指导您如何使用 OpenHands、Kubernetes、Ingress 和账户管理系统(接入微软 Azure Active Directory)搭建一个多租户版的 OpenHands 系统。通过本教程,您将实现:
- 多用户支持:每个用户登录后访问自己的 OpenHands 实例。
- 身份验证:通过 Azure AD 实现用户身份验证。
- 动态实例分配:根据用户动态分配 OpenHands 实例。
- 数据隔离:确保每个用户的实例和数据互不干扰。
系统架构
系统架构如下:
- 用户通过浏览器访问系统。
- 系统引导用户通过 Azure AD 登录。
- 登录成功后,系统根据用户 ID 查询或分配 OpenHands 实例。
- 用户被路由到对应的 OpenHands 实例。
[用户] --> [账户管理系统] --> [Azure AD 登录]
       --> [用户实例映射表] --> [Ingress/反向代理] --> [OpenHands 实例]
准备工作
- Docker 镜像:确保 OpenHands 的 Docker 镜像已构建并可用(例如 docker.all-hands.dev/all-hands-ai/openhands:0.27)。
- Kubernetes 集群:确保 Kubernetes 集群已配置好(可以使用 Minikube、Kind 或云服务如 GKE、EKS 等)。
- kubectl 工具:确保本地安装了 kubectl并已连接到 Kubernetes 集群。
- Azure AD 应用:在 Azure AD 中注册一个应用,用于用户身份验证。
步骤 1: 部署 OpenHands 到 Kubernetes
创建 Kubernetes 配置文件
以下是一个示例的 Kubernetes 配置文件,包含 Deployment 和 Service:
openhands-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: openhands-deployment
  labels:
    app: openhands
spec:
  replicas: 3  # 启动 3 个实例,可以根据需要调整
  selector:
    matchLabels:
      app: openhands
  template:
    metadata:
      labels:
        app: openhands
    spec:
      containers:
      - name: openhands
        image: docker.all-hands.dev/all-hands-ai/openhands:0.27
        ports:
        - containerPort: 3000
        env:
        - name: SANDBOX_RUNTIME_CONTAINER_IMAGE
          value: "docker.all-hands.dev/all-hands-ai/runtime:0.27-nikolaik"
        - name: LOG_ALL_EVENTS
          value: "true"
        volumeMounts:
        - name: openhands-state
          mountPath: /.openhands-state
      volumes:
      - name: openhands-state
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: openhands-service
spec:
  selector:
    app: openhands
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
  type: LoadBalancer
部署到 Kubernetes
将上述配置文件保存为 openhands-deployment.yaml,然后运行以下命令:
kubectl apply -f openhands-deployment.yaml
验证部署
- 检查 Pod 是否运行正常:kubectl get pods
- 检查 Service 是否分配了外部 IP(如果使用 LoadBalancer 类型):
 您可以通过分配的外部 IP 访问 OpenHands 实例。kubectl get service openhands-service
步骤 2: 配置 Ingress 实现路由
使用 Kubernetes 的 Ingress 控制器,通过不同的子路径或子域名分配实例。例如:
- 用户 A 访问 http://example.com/user-a
- 用户 B 访问 http://example.com/user-b
示例 Ingress 配置
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: openhands-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /user-a
        pathType: Prefix
        backend:
          service:
            name: openhands-user-a
            port:
              number: 80
      - path: /user-b
        pathType: Prefix
        backend:
          service:
            name: openhands-user-b
            port:
              number: 80
将上述配置保存为 openhands-ingress.yaml,然后运行:
kubectl apply -f openhands-ingress.yaml
步骤 3: 接入 Azure AD 实现身份验证
注册 Azure AD 应用
- 登录 Azure Portal。
- 在 Azure AD 中注册一个新的应用: - 设置重定向 URI,例如 https://example.com/auth/callback。
- 获取应用的 Client ID和Client Secret。
 
- 设置重定向 URI,例如 
- 配置 API 权限,确保应用有 openid和profile权限。
配置身份验证中间件
在账户管理系统中,使用支持 OAuth 2.0 或 OIDC 的库(如 Python 的 authlib)来处理用户登录。
示例代码(Python Flask 应用)
from flask import Flask, redirect, url_for, session
from authlib.integrations.flask_client import OAuth
app = Flask(__name__)
app.secret_key = 'random_secret_key'
oauth = OAuth(app)
azure = oauth.register(
    name='azure',
    client_id='YOUR_CLIENT_ID',
    client_secret='YOUR_CLIENT_SECRET',
    server_metadata_url='https://login.microsoftonline.com/YOUR_TENANT_ID/v2.0/.well-known/openid-configuration',
    client_kwargs={
        'scope': 'openid profile email',
    }
)
@app.route('/')
def home():
    return 'Welcome to OpenHands! <a href="/login">Login with Azure AD</a>'
@app.route('/login')
def login():
    redirect_uri = url_for('auth_callback', _external=True)
    return azure.authorize_redirect(redirect_uri)
@app.route('/auth/callback')
def auth_callback():
    token = azure.authorize_access_token()
    user_info = token.get('userinfo')
    session['user'] = user_info
    return f'Hello, {user_info["name"]}!'
if __name__ == '__main__':
    app.run()
步骤 4: 用户与 OpenHands 实例的映射
数据库存储映射关系
使用数据库(如 PostgreSQL 或 MongoDB)存储用户与实例的映射。例如:
| 用户 ID (Azure AD) | OpenHands 实例 URL | 
|---|---|
| user1@domain.com | http://openhands-1.com | 
| user2@domain.com | http://openhands-2.com | 
| user3@domain.com | http://openhands-3.com | 
动态路由
使用 Ingress 或反向代理(如 Nginx)根据用户的身份动态路由到对应的实例。
示例 Nginx 配置
server {
    listen 80;
    server_name example.com;
    location / {
        proxy_pass http://openhands-instance-$user_id;
    }
}
注意事项
- 单用户限制:OpenHands 默认是单用户模式。如果需要支持多用户共享一个实例,可能需要对 OpenHands 的代码进行修改。
- 安全性: - 确保所有通信使用 HTTPS。
- 配置 Azure AD 的权限范围,避免过多权限暴露。
 
- 扩展性: - 使用 Kubernetes 的自动扩展功能,根据用户数量动态扩展实例。
- 定期清理未使用的实例,优化资源利用。
 
通过本教程,您可以成功搭建一个多租户版的 OpenHands 系统。如果您有任何问题或需要进一步的帮助,请随时联系!
