用 Flask 代理打通外部访问 Amazon SageMaker MLflow 的 REST 通道

2026-05-29 23 预计阅读时间:1 分钟
来源:aws.amazon.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:10 分钟

很多团队在向云迁移的过程中,都会碰到一个现实问题:本地训练脚本、调度系统、监控面板已经围绕 MLflow 搭好了整套流程,但一旦把实验追踪服务搬到 Amazon SageMaker MLflow,外部系统就得装 MLflow SDK、配 VPC 网络才能连上——这对还在过渡期的组织来说改动面太大。AWS 最近给出的方案是:在 SageMaker MLflow 前面架一层 Flask REST 代理,外部调用方只需要一个 HTTPS endpoint,不再依赖任何 SDK。

为什么不能直接暴露 SageMaker MLflow

SageMaker MLflow Server 运行在 SageMaker 管控的 VPC 内,默认只对同一 VPC 里的资源开放访问。外部要连进来,常规做法有两条路:

  • 装 MLflow SDK,走 mlflow.set_tracking_uri()——这意味着每台要上报实验的机器都得装 Python 依赖、配 credential,非 Python 环境(比如 Java 微服务、Go 调度器)直接被排除。
  • 搭 VPN 或 VPC Peering——网络层面的工程量不小,而且一旦打通,暴露的是整个 MLflow Server 的全部 API,权限粒度粗。

代理方案的好处在于:你只需要暴露一个 HTTPS endpoint,可以按路由做细粒度鉴权,调用方用任何语言发 HTTP 请求就行。

代理的核心设计思路

Flask 代理要解决三个问题:

  1. 身份认证——外部请求进来,代理负责校验 token / IAM 签名,再以合法身份转发给 SageMaker MLflow。
  2. 协议适配——MLflow REST API 本身就是 HTTP,代理做的是路径映射和必要的 header 改写,不需要重写业务逻辑。
  3. HTTPS 终结——在代理层做 TLS,内部到 SageMaker 的调用走 VPC 内网。

整体数据流:

外部调用方 → HTTPS → API Gateway / ALB → Flask Proxy → SageMaker MLflow Server

实战:搭建一个最小可用的 Flask 代理

下面给出一个可以直接改造运行的 Flask 代理示例。假设你已经有一个运行中的 SageMaker MLflow Server,它的 VPC 内地址是 https://mlflow-server.internal:5000

代理服务代码

# app.py — Flask MLflow Proxy
import os
import requests
from flask import Flask, request, jsonify, Response

app = Flask(__name__)

# SageMaker MLflow 内网地址,从环境变量读取
MLFLOW_INTERNAL_URL = os.environ.get(
    "MLFLOW_INTERNAL_URL", "https://mlflow-server.internal:5000"
)

# 简易 token 校验(生产环境建议换成 IAM 签名或 OAuth)
API_TOKEN = os.environ.get("PROXY_API_TOKEN", "change-me-in-production")


def verify_token():
    """校验请求头中的 Authorization token"""
    auth = request.headers.get("Authorization", "")
    if auth != f"Bearer {API_TOKEN}":
        return jsonify({"error": "unauthorized"}), 401
    return None


@app.route("/api/2.0/mlflow/<path:subpath>", methods=["GET", "POST", "PUT", "DELETE"])
def proxy_mlflow(subpath):
    # 1. 鉴权
    err = verify_token()
    if err is not None:
        return err

    # 2. 构造转发目标 URL
    target_url = f"{MLFLOW_INTERNAL_URL}/api/2.0/mlflow/{subpath}"

    # 3. 复制请求头,去掉 host 和 authorization(避免泄露到内网)
    fwd_headers = {
        k: v for k, v in request.headers
        if k.lower() not in ("host", "authorization")
    }

    # 4. 转发请求
    resp = requests.request(
        method=request.method,
        url=target_url,
        headers=fwd_headers,
        data=request.get_data(),
        params=request.args,
        timeout=30,
        verify=False,  # 内网自签证书场景;生产环境应配 CA
    )

    # 5. 透传响应
    excluded_headers = {"content-encoding", "transfer-encoding"}
    response_headers = {
        k: v for k, v in resp.headers.items() if k.lower() not in excluded_headers
    }
    return Response(resp.content, status=resp.status_code, headers=response_headers)


@app.route("/health", methods=["GET"])
def health():
    return jsonify({"status": "ok"})


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

关键点说明:

  • 路径 /api/2.0/mlflow/<path:subpath> 覆盖了 MLflow REST API 的全部路由,包括 runs/createexperiments/searchartifacts/list 等,不需要逐个硬编码。
  • verify=False 是内网自签证书的妥协做法,生产部署应该把 CA 证书挂进容器,改成 verify="/path/to/ca-bundle.crt"
  • token 校验是最简版本;在 AWS 环境下,更推荐用 API Gateway + IAM Authorizer 或者 Lambda Authorizer 做鉴权,代理层只做转发。

本地快速验证

# 安装依赖
pip install flask requests

# 设置环境变量
export MLFLOW_INTERNAL_URL="https://your-sagemaker-mlflow.internal:5000"
export PROXY_API_TOKEN="my-secret-token"

# 启动代理
python app.py

测试创建实验:

curl -X POST \
  http://localhost:8080/api/2.0/mlflow/experiments/create \
  -H "Authorization: Bearer my-secret-token" \
  -H "Content-Type: application/json" \
  -d '{"name": "proxy-test-experiment"}'

搜索实验:

curl -X GET \
  "http://localhost:8080/api/2.0/mlflow/experiments/search?max_results=10" \
  -H "Authorization: Bearer my-secret-token"

如果返回 JSON 和直接访问 MLflow Server 一致,代理就通了。

部署到 AWS:从本地到生产

本地跑通了,下一步是把代理放进 AWS 网络里,让外部能通过 HTTPS 安全访问。推荐架构:

外部 → Amazon API Gateway (IAM/Auth) → ALB → ECS/Fargate (Flask Proxy) → SageMaker MLflow

用 Fargate 部署代理的 Terraform 片段

# ecs_service.tf — 核心部分
resource "aws_ecs_task_definition" "mlflow_proxy" {
  family                   = "mlflow-proxy"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = "256"
  memory                   = "512"

  container_definitions = jsonencode([
    {
      name      = "proxy"
      image     = "your-registry/mlflow-proxy:latest"
      essential = true
      portMappings = [{ containerPort = 8080, protocol = "tcp" }]
      environment = [
        { name = "MLFLOW_INTERNAL_URL", value = var.mlflow_internal_url },
        { name = "PROXY_API_TOKEN",     value = var.proxy_api_token },
      ]
      logConfiguration = {
        logDriver = "awslogs"
        options = {
          "awslogs-group" = aws_cloudwatch_log_group.mlflow_proxy.name
          "awslogs-region" = var.region
        }
      }
    }
  ])
}

resource "aws_ecs_service" "mlflow_proxy" {
  name            = "mlflow-proxy"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.mlflow_proxy.arn
  launch_type     = "FARGATE"
  desired_count   = 2

  network_configuration {
    subnets         = var.private_subnet_ids   # 和 MLflow Server 同 VPC
    security_groups = [aws_security_group.proxy.id]
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.proxy.arn
    container_name   = "proxy"
    container_port   = 8080
  }
}

安全组规则要严格控制:

  • 入站:只允许 ALB 的安全组访问 8080 端口。
  • 出站:只允许访问 SageMaker MLflow Server 的安全组(端口 5000),以及 ECR 拉镜像的端口。

API Gateway 配置要点

在 API Gateway 上挂 IAM Authorizer,这样外部调用方用 AWS SigV4 签名即可鉴权,代理层可以去掉 token 校验逻辑,只做纯转发。API Gateway 还自带 HTTPS,省掉自己管证书的负担。

需要注意的边界和取舍

维度 说明
延迟 代理多了一跳,典型增加 5-15ms。对高频上报指标的流水线要评估是否可接受
大文件上传 MLflow artifact 上传可能涉及几百 MB 的模型文件,Flask 默认内存处理会撑爆。需要改成流式转发或直接走 S3 presigned URL
超时 MLflow 的 search_runs 在实验量大时可能返回慢,代理的 timeout 要留够余量,建议 60s+
路由覆盖度 MLflow REST API 有几十个端点,<path:subpath> 通配能兜住大部分,但 /mlflow-artifacts/ 这类静态文件路径需要单独映射
并发 Flask 单进程并发有限,生产部署用 gunicorn + 多 worker,或者直接换 FastAPI + uvicorn

迁移过渡期的实操建议

如果你正在从本地 MLflow 向 SageMaker MLflow 迁移,可以按这个节奏走:

  1. 先搭代理,不改调用方——所有本地脚本把 tracking_urihttp://local-mlflow:5000 换成代理的 HTTPS 地址,其余代码不动。
  2. 逐步收紧鉴权——初期用 token 快速验证连通性,稳定后切换到 IAM Authorizer。
  3. artifact 上传单独处理——大模型文件不走代理转发,改用 S3 presigned URL 直传,代理只负责元数据 API。
  4. 监控代理层——在 /health 之外加上对 MLflow Server 的连通性探测,一旦内网 MLflow 异常,代理层主动返回 503 而不是超时等待。

这个方案的核心价值不是技术复杂度,而是让迁移过程中的改动面最小:外部系统不需要装 SDK、不需要改语言栈、不需要配 VPC 网络,一个 HTTPS 地址就够了。等迁移完成、所有系统都跑在 AWS 内网后,代理可以逐步退役,调用方直接切到 SageMaker MLflow 的内网地址。


相关推荐