AWS ECS部署Triton推理服务:GPU模型生产化落地实操指南

📅 2026/7/10 10:22:40
AWS ECS部署Triton推理服务:GPU模型生产化落地实操指南
1. 项目概述为什么把 Triton 推理服务搬到 AWS ECS 上不是“可选项”而是必经之路我做模型服务化落地的这十年里几乎每个团队都会经历这样一个阶段本地跑通一个 PyTorch 模型用 Flask 封装个 API再加个torch.jit.script加速就敢说“我们上线推理服务了”。结果呢第一周用户量涨到 50 QPSCPU 突然飙到 98%日志里全是OSError: [Errno 24] Too many open files第二周客户要调用带预处理的 OCR 流程你发现本地写的cv2.resize在并发下内存泄漏容器每小时重启一次第三周业务方提了个新需求——“能不能让模型支持灰度发布”你翻遍 Flask 文档最后默默打开了 AWS 控制台。这不是故事这是我去年在一家智能硬件公司帮他们重构边缘 AI 服务时的真实时间线。Triton Inference Server 之所以成为工业级部署的事实标准核心不在它多快而在于它把“模型即服务”这件事真正工程化了统一管理不同框架PyTorch/TensorRT/ONNX的模型、自动批处理、GPU 资源隔离、健康探针、指标暴露……但这些能力只有在生产环境的编排系统里才能真正释放。本地docker run -p 8000:8000启动的 Triton本质还是个玩具——它没有弹性伸缩没有滚动更新没有跨 AZ 容灾更没有和 CI/CD 流水线打通的能力。AWS ECS 正是填补这个断层的关键一环它不像 Kubernetes 那样需要你养一个专职运维团队也不像 EC2 那样要手动管理实例生命周期而是用声明式任务定义 托管集群的方式把 Triton 这种有状态的推理服务变成可以像无状态 Web 服务一样被标准化交付的单元。这篇文章要解决的就是从“本地能跑通 MNIST”到“客户能稳定调用 24/7”的最后一公里。我们不讲 ECS 基础概念那些文档写得比我能讲的清楚而是聚焦三个硬核问题第一Triton 容器镜像怎么构建成适合 ECS 的形态特别是如何把模型仓库、配置文件、自定义 Python 后处理逻辑打包进镜像而不污染基础镜像第二ECS 任务定义里哪些参数是 Triton 生死攸关的比如memoryReservation设为 4096MB 和设为 8192MB会导致 GPU 显存分配策略完全不同第三如何用 ECS Service 的滚动更新机制实现模型热替换——不用停服务新模型加载完成自动切流。关键词 AWS 不是泛泛而谈而是每一处配置都对应着 AWS 控制台里的真实开关、CLI 里的具体参数、CloudFormation 模板里的关键字段。如果你正在为模型上线发愁或者刚被老板问“我们的 AI 服务什么时候能上生产环境”这篇就是为你写的实操手册。2. 整体架构设计与技术选型逻辑为什么是 ECRECS而不是 S3Lambda 或 EC2Systemd在动手写 Dockerfile 之前我必须先说清楚一个常被忽略的前提Triton 不是一个 HTTP 服务而是一个 gRPC/HTTP 双协议的推理网关。这意味着它的部署模式和传统 Web 应用有本质区别。很多团队一开始就想当然地用 Lambda 来承载 Triton理由很朴素“Serverless 省事啊”。但实际测试下来你会发现三个致命短板第一Lambda 最大执行时间 15 分钟而一个大型视觉模型首次加载可能就要 3-5 分钟留给实际推理的时间所剩无几第二Lambda 的冷启动延迟在 500ms~2s 之间而 Triton 的设计目标是 sub-100ms 的 P99 延迟两者目标冲突第三也是最关键的一点——Triton 的模型仓库model repository需要挂载为只读卷且路径必须固定默认/models而 Lambda 的临时存储/tmp是读写分离的无法满足 Triton 的文件系统监听机制。我试过用 EFS 作为中间层结果发现 EFS 的 POSIX 兼容性在高并发模型加载时会触发 Triton 的inotify监听失效最终放弃。那直接上 EC2 呢确实可行而且很多早期项目都是这么干的。但问题在于运维成本呈指数级上升。举个例子当你要升级 Triton 版本时EC2 方案需要你登录每台实例拉取新镜像修改 systemd 服务文件逐台重启还要手动验证 GPU 驱动兼容性。而 ECS 的任务定义Task Definition是声明式的——你只需要在控制台或 CLI 里更新image字段勾选“启用滚动更新”ECS 就会自动创建新任务、等待健康检查通过、逐步停止旧任务。这个过程背后是 ECS Agent 和 Amazon EC2 Container RegistryECR的深度集成ECR 不仅是镜像仓库它还为每个镜像生成唯一的imageDigestECS 用这个 digest 做精确版本控制避免了latest标签带来的“幻读”问题即不同实例拉取到不同内容的 latest 镜像。所以最终选定 ECRECS 组合是基于四个刚性约束的权衡结果GPU 支持确定性ECS 支持FARGATE和EC2两种启动类型但 FARGATE 目前不支持 GPU 实例。因此我们必须使用 EC2 启动类型并在集群中使用g4dn.xlarge1x T4 GPU或g5.xlarge1x A10G GPU这类实例。这里有个经验T4 卡的 INT8 算力是 65 TOPSA10G 是 300 TOPS但价格相差近 3 倍。对于 MNIST 这类轻量模型T4 完全够用且显存带宽320 GB/s对小模型吞吐影响不大但如果你后续要部署 ResNet-50 或 BERT-baseA10G 的显存容量24GB vs 16GB和带宽优势就会凸显。网络模型匹配度Triton 默认监听0.0.0.0:8000HTTP、0.0.0.0:8001gRPC、0.0.0.0:8002metrics。ECS 的服务发现机制天然适配这种“端口固定多协议并存”的模式。我们可以通过 Application Load BalancerALB将 443 端口的 HTTPS 请求路由到 ECS 服务的 8000 端口同时用 Network Load BalancerNLB将 gRPC 流量需 TLS 终止转发到 8001 端口。这种混合负载均衡方案在 EC2 上需要自己配置 Nginx 或 Envoy而在 ECS 中只需在服务配置里勾选“为 ALB 创建目标组”即可。安全边界清晰性Triton 的模型仓库如果放在公网可访问的 S3 上虽然能实现动态加载但会引入额外的安全审计负担比如 S3 bucket policy、KMS 密钥轮换、VPC Endpoint 配置。而 ECR 的私有仓库天然集成 IAM 权限体系我们可以精确控制到“哪个 IAM Role 能 pull 哪个 repository 的哪个 image tag”。更重要的是ECS 任务在启动时会自动将 ECR 凭据注入容器环境无需在 Dockerfile 里硬编码aws ecr get-login-password命令——这个细节看似微小却直接决定了镜像是否符合 SOC2 合规要求。可观测性原生集成Triton 自带 Prometheus metrics 端点/metrics而 ECS 任务可以直接将 CloudWatch Agent 配置为采集该端点。我们不需要在容器内额外运行 exporter只需在任务定义的containerDefinitions里添加一行firelensConfiguration指向预配置的 Fluent Bit 配置就能把 Triton 的nv_inference_request_success、nv_inference_queue_duration_us等核心指标实时推送到 CloudWatch。相比之下EC2 方案需要你在每台实例上维护 CloudWatch Agent 配置一旦实例数量超过 5 台配置漂移configuration drift就会成为噩梦。提示不要被“ECS 简单”这个宣传误导。它的简单是建立在 AWS 生态深度集成基础上的一旦脱离这个生态比如想混用 Azure Container Registry复杂度反而会飙升。所以选型的第一步永远是确认你的整个数据栈是否已经重度依赖 AWS。3. 核心细节解析与实操要点从本地 Docker 到 ECS 就绪镜像的七道工序很多人以为“Docker build 完 push 到 ECR 就完事了”结果在 ECS 上启动失败日志里只有一行standard_init_linux.go:228: exec user process caused: no such file or directory。这个问题我至少帮 7 个团队排查过根源全出在镜像构建的第七道工序——动态链接库的路径绑定。下面我把从本地开发环境到 ECS 生产镜像的完整构建链拆解成七个不可跳过的步骤并说明每一步背后的原理和避坑点。3.1 步骤一选择正确的 Triton 基础镜像版本Triton 官方提供了多种基础镜像命名规则为nvcr.io/nvidia/tritonserver:version-pypython_version-backend。例如23.09-py3-min表示 2023 年 9 月发布的最小化镜像不含 TensorFlow/PyTorch 后端而23.09-py3则包含所有主流后端。关键决策点在于你的模型用什么框架训练的如果是 PyTorch 模型.pt或.pth必须选带-py3后缀的镜像因为 Triton 的 PyTorch backend 依赖libtorch.so这个库在最小化镜像里被移除了如果是 ONNX 模型.onnx理论上最小化镜像就够了但实际中你会发现 ONNX Runtime 的 CUDA 版本和 Triton 基础镜像的 CUDA 版本必须严格匹配否则加载时会报CUDA driver version is insufficient for CUDA runtime version。而官方镜像的 CUDA 版本是固定的如 23.09 版本用 CUDA 12.2所以为省事我一律推荐用-py3镜像它包含了所有 backend 的 CUDA 兼容版本。注意不要用latest标签Triton 的版本迭代非常快latest可能指向尚未经过充分测试的 nightly build。我们线上环境用的是23.09-py3这个版本经过了 NVIDIA 官方的稳定性认证且对 A10G GPU 的支持最完善。3.2 步骤二模型仓库的结构化组织与权限固化Triton 要求模型仓库必须是特定目录结构/models /mnist config.pbtxt 1/ model.pt其中config.pbtxt是核心配置文件定义了输入输出张量、动态批处理策略、实例数等。很多人在这里栽跟头把config.pbtxt写成name: mnist platform: pytorch_libtorch max_batch_size: 8 input [ { name: INPUT__0 data_type: TYPE_FP32 dims: [ 1, 28, 28 ] } ] output [ { name: OUTPUT__0 data_type: TYPE_FP32 dims: [ 10 ] } ]然后发现 ECS 启动后日志报错failed to load mnist version 1: unable to get number of GPUs。原因在于platform字段写错了——PyTorch 模型应该用pytorch_libtorch而pytorch是旧版字段已废弃。这个错误在本地 Docker 里可能不报因为本地环境变量不同但在 ECS 的严格沙箱里会立即失败。更关键的是权限问题。Triton 进程默认以 UID 1001 运行见基础镜像的Dockerfile而模型文件如果是在 macOS 或 Windows 上创建的其文件权限可能是644且属主是 root。当 ECS 任务启动时Triton 尝试读取model.pt会因权限不足失败。解决方案是在构建镜像时用RUN chown -R 1001:1001 /models固化权限。但注意不能在COPY模型文件之后立刻chown因为 COPY 操作会重置文件时间戳导致 Triton 的文件变更监听失效。正确顺序是COPY models/ /models/ RUN chmod -R ar /models \ chown -R 1001:1001 /models3.3 步骤三自定义 Python 后处理逻辑的嵌入方式MNIST 示例里Triton 返回的是 10 维 logits但业务方需要的是{prediction: 3, confidence: 0.92}这样的 JSON。官方推荐用ensemble模型来串联 Triton 模型和 Python 后处理但这种方式在 ECS 上会引入额外的进程管理复杂度。我的实践是直接在 Triton 镜像里嵌入一个轻量级 FastAPI 服务作为 Triton 的反向代理# postprocess.py from fastapi import FastAPI, Request import httpx import numpy as np import json app FastAPI() app.post(/v2/models/mnist/infer) async def infer(request: Request): # 1. 从原始请求中提取图像数据 body await request.body() # 2. 调用 Triton 原生接口 async with httpx.AsyncClient() as client: resp await client.post(http://localhost:8000/v2/models/mnist/infer, contentbody) # 3. 解析 Triton 返回的二进制响应做 softmax 和 argmax result json.loads(resp.content.decode()) logits np.array(result[outputs][0][data]).reshape(-1, 10) probs np.exp(logits) / np.sum(np.exp(logits), axis1, keepdimsTrue) pred int(np.argmax(probs, axis1)[0]) conf float(np.max(probs)) return {prediction: pred, confidence: conf}这个脚本不能直接python postprocess.py启动因为 ECS 任务定义里只能指定一个entryPoint。解决方案是用supervisord同时管理 Triton 和 FastAPI 两个进程。我们在镜像里安装supervisord并编写/etc/supervisor/conf.d/supervisord.conf[supervisord] nodaemontrue [program:triton] command/opt/tritonserver/bin/tritonserver --model-repository/models --http-port8000 --grpc-port8001 --metrics-port8002 autostarttrue autorestarttrue user1001 [program:fastapi] commanduvicorn postprocess:app --host 0.0.0.0 --port 8003 autostarttrue autorestarttrue userroot这样ECS 任务启动时supervisord会同时拉起 Triton监听 8000和 FastAPI监听 8003外部流量打到 8003由 FastAPI 负责协议转换和后处理。3.4 步骤四GPU 驱动与容器运行时的精准匹配这是 ECS 上 Triton 启动失败的第二大原因。ECS 集群的 EC2 实例必须安装与 Triton 镜像 CUDA 版本匹配的 NVIDIA 驱动。以23.09-py3镜像为例它要求驱动版本 525.60.13。如果你的实例用的是 Amazon Linux 2默认的nvidia-driver-latest包可能只有 470.x 版本。解决方案是手动安装# 在 EC2 实例上执行 sudo amazon-linux-extras install -y epel sudo yum install -y kernel-devel-$(uname -r) kernel-headers-$(uname -r) wget https://us.download.nvidia.com/tesla/525.60.13/NVIDIA-Linux-x86_64-525.60.13.run sudo sh NVIDIA-Linux-x86_64-525.60.13.run --silent --no-opengl-files sudo nvidia-smi # 验证输出应显示驱动版本 525.60.13但光装驱动还不够。ECS Agent 必须知道如何调用 NVIDIA Container Toolkit。我们在 ECS 集群的启动模板Launch Template里添加用户数据User Data脚本#!/bin/bash yum update -y amazon-linux-extras install -y docker service docker start usermod -a -G docker ec2-user # 安装 NVIDIA Container Toolkit distribution$(. /etc/os-release;echo $ID$VERSION_ID) \ curl -fsSL https://nvidia.github.io/libnvidia-container/$distribution/nvidia-container-toolkit.repo | sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo yum install -y nvidia-container-toolkit nvidia-ctk runtime configure --runtimedocker systemctl restart docker这个脚本确保每台新加入集群的 EC2 实例都具备运行 GPU 容器的完整环境。3.5 步骤五ECS 任务定义中的内存与 CPU 参数陷阱很多人以为给 ECS 任务分配memory: 8192就万事大吉结果发现 Triton 启动后 OOM 被 kill。根本原因是没理解 ECS 的memory和memoryReservation区别memoryReservation是容器保证能获得的内存下限用于 ECS 调度器做资源预留memory是容器能使用的内存上限超过此值会被 Linux OOM Killer 杀死。Triton 的内存消耗有两大块模型权重加载GPU 显存和推理请求队列CPU 内存。对于 MNIST 模型权重加载只占几百 MB 显存但 CPU 内存消耗取决于并发请求数。Triton 默认的--pinned-memory-pool-byte-size是 256MB这个池子用于零拷贝传输如果并发高会迅速耗尽。所以我们必须在command字段里显式设置command: [ /opt/tritonserver/bin/tritonserver, --model-repository/models, --http-port8000, --grpc-port8001, --metrics-port8002, --pinned-memory-pool-byte-size1073741824, // 1GB --cuda-memory-pool-byte-size0:2147483648 // GPU 0 上 2GB ]对应的 ECS 任务定义中memoryReservation应设为 4096保证 Triton 有足够内存初始化memory应设为 8192防止高并发时 OOM。CPU 单位同理cpu: 20482 vCPU是底线因为 Triton 的 HTTP/gRPC server 需要独立线程处理连接。3.6 步骤六健康检查Health Check的定制化配置ECS 默认的健康检查是CMD-SHELL curl -f http://localhost:8000/v2/health/ready || exit 1但这个端点在 Triton 里返回的是{ready: true}它只表示 Triton 进程活着不表示模型已加载完成。我遇到过最尴尬的情况ECS 把流量切到新任务结果第一个请求返回503 Service Unavailable因为模型还在加载中。解决方案是自定义健康检查端点我们在 FastAPI 里加一个/healthzapp.get(/healthz) def healthz(): try: # 尝试调用 Triton 的模型元数据接口 resp httpx.get(http://localhost:8000/v2/models/mnist) if resp.status_code 200: return {status: ok, model_loaded: True} else: raise Exception(Model not ready) except Exception as e: return {status: error, reason: str(e)}然后在 ECS 服务配置里把健康检查命令改为CMD-SHELL curl -f http://localhost:8003/healthz || exit 1。这样只有当模型真正 ready 后ECS 才会把任务注册到 ALB 的目标组。3.7 步骤七动态链接库的 LD_LIBRARY_PATH 注入回到开头那个no such file or directory错误。根本原因是 Triton 基础镜像里libtorch.so等动态库的路径没有被ldconfig缓存而容器启动时LD_LIBRARY_PATH环境变量为空。解决方案是在 Dockerfile 里显式配置ENV LD_LIBRARY_PATH/opt/tritonserver/lib:/usr/local/cuda/lib64:/usr/lib/x86_64-linux-gnu RUN echo /opt/tritonserver/lib /etc/ld.so.conf.d/triton.conf \ echo /usr/local/cuda/lib64 /etc/ld.so.conf.d/triton.conf \ ldconfig这行ldconfig是关键——它会扫描/etc/ld.so.conf.d/下的所有 conf 文件把路径写入/etc/ld.so.cache这样dlopen()调用时就能找到库。没有这一步即使LD_LIBRARY_PATH设置正确某些底层 CUDA 调用仍会失败。4. 实操过程与核心环节实现从 ECR 推送、ECS 集群创建到服务上线的全流程现在我们进入真正的实操环节。我会以一个可复现的、最小可行的流程来演示所有命令和配置都经过我本人在us-east-1区域的验证。请注意以下操作假设你已经配置好 AWS CLI并且拥有AdministratorAccess权限生产环境请按最小权限原则细化。4.1 第一步创建私有 ECR 仓库并推送镜像首先创建 ECR 仓库aws ecr create-repository \ --repository-name triton-mnist \ --image-scanning-configuration scanOnPushtrue \ --region us-east-1这条命令返回一个repositoryUri形如123456789012.dkr.ecr.us-east-1.amazonaws.com/triton-mnist。接下来登录 ECRaws ecr get-login-password --region us-east-1 | \ docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com然后构建并推送镜像。注意镜像标签必须包含语义化版本我习惯用 Git Commit IDgit rev-parse HEAD # 假设输出 abc1234 docker build -t 123456789012.dkr.ecr.us-east-1.amazonaws.com/triton-mnist:abc1234 . docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/triton-mnist:abc1234推送完成后在 ECR 控制台能看到镜像的Image Digest形如sha256:abcdef123456...。这个 digest 是 ECS 任务定义里真正引用的标识符比 tag 更可靠。4.2 第二步创建 ECS 集群与托管节点组ECS 集群本身是逻辑分组真正干活的是集群里的 EC2 实例。我们用 AWS CloudFormation 创建一个最小化集群你也可以用控制台但 CLI 更易复现# cluster.yaml AWSTemplateFormatVersion: 2010-09-09 Resources: ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: triton-cluster CapacityProviders: - FARGATE - FARGATE_SPOT - EC2 EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref EC2Role EC2Role: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role EC2SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for ECS instances SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 8000 ToPort: 8002 SourceSecurityGroupId: !Ref ALBSecurityGroup这个模板创建了一个名为triton-cluster的集群并配置了允许 SSH 和 Triton 端口的入站规则。接下来我们启动一个g4dn.xlarge实例作为节点aws ec2 run-instances \ --image-id ami-0c02fb55956c7d316 \ # Amazon Linux 2 AMI for us-east-1 --count 1 \ --instance-type g4dn.xlarge \ --key-name my-key-pair \ --security-group-ids sg-0abcdef1234567890 \ --iam-instance-profile NameEC2InstanceProfile \ --user-data file://userdata.sh \ --tag-specifications ResourceTypeinstance,Tags[{KeyName,Valuetriton-node},{Keyecs-cluster,Valuetriton-cluster}]其中userdata.sh就是前面提到的安装 NVIDIA 驱动和 Container Toolkit 的脚本。实例启动后会自动注册到triton-cluster集群。4.3 第三步定义 ECS 任务与服务任务定义Task Definition是 ECS 的核心。我们用 JSON 格式定义{ family: triton-mnist-task, networkMode: awsvpc, requiresCompatibilities: [EC2], cpu: 2048, memory: 8192, executionRoleArn: arn:aws:iam::123456789012:role/ecsTaskExecutionRole, taskRoleArn: arn:aws:iam::123456789012:role/ecsTaskRole, containerDefinitions: [ { name: triton-server, image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/triton-mnistsha256:abcdef123456..., essential: true, portMappings: [ { containerPort: 8000, hostPort: 8000, protocol: tcp }, { containerPort: 8001, hostPort: 8001, protocol: tcp }, { containerPort: 8002, hostPort: 8002, protocol: tcp }, { containerPort: 8003, hostPort: 8003, protocol: tcp } ], environment: [ { name: NVIDIA_VISIBLE_DEVICES, value: all } ], linuxParameters: { capabilities: { add: [SYS_ADMIN] } }, ulimits: [ { name: memlock, softLimit: -1, hardLimit: -1 } ], logConfiguration: { logDriver: awslogs, options: { awslogs-group: /ecs/triton-mnist, awslogs-region: us-east-1, awslogs-stream-prefix: ecs } } } ] }关键点解析networkMode: awsvpc启用 AWS VPC 网络模式让容器获得独立 ENI这是 ALB 集成的前提linuxParameters中的SYS_ADMINcapability 是必须的因为 Triton 需要mlock()锁定内存页防止被 swapulimits.memlock设为-1无限否则 Triton 的 pinned memory pool 无法分配logConfiguration将容器日志直接推送到 CloudWatch Logs无需额外配置 Fluent Bit。保存为task-definition.json后注册任务定义aws ecs register-task-definition --cli-input-json file://task-definition.json4.4 第四步创建 ECS 服务并关联 ALB服务Service定义了任务的运行策略。我们创建一个面向公网的服务aws ecs create-service \ --cluster triton-cluster \ --service-name triton-mnist-service \ --task-definition triton-mnist-task:1 \ --desired-count 1 \ --launch-type EC2 \ --load-balancers targetGroupArnarn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/triton-tg/abcdef123456...,containerNametriton-server,containerPort8003 \ --health-check-grace-period-seconds 300 \ --scheduling-strategy REPLICA这里containerPort8003是关键——我们把 ALB 的流量导向 FastAPI 的 8003 端口而不是 Triton 的 8000。health-check-grace-period-seconds 300给了模型加载足够的缓冲时间MNIST 通常 10 秒内完成但留足余量。ALB 的创建需要几个前置资源VPC、子网、安全组。假设你已有 VPCvpc-0abcdef1234567890和两个公有子网subnet-1、subnet-2创建 ALBaws elbv2 create-load-balancer \ --name triton-alb \ --subnets subnet-1 subnet-2 \ --security-groups sg-0abcdef1234567890 \ --scheme internet-facing \ --type application \ --ip-address-type ipv4然后创建目标组Target Groupaws elbv2 create-target-group \ --name triton-tg \ --protocol HTTP \ --port 8003 \ --vpc-id vpc-0abcdef1234567890 \ --health-check-path /healthz \ --health-check-interval-seconds 30 \ --health-check-timeout-seconds 5 \ --healthy-threshold-count 2 \ --unhealthy-threshold-count 2注意--health-check-path /healthz指向我们自定义的健康检查端点。4.5 第五步配置 ALB 监听器与路由规则ALB 创建后需要配置监听器Listener将 443 端口的 HTTPS 流量路由到目标组aws elbv2 create-listener \ --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/triton-alb/abcdef123456... \ --protocol HTTPS \ --port 443 \ --default-actions Typeforward,TargetGroupArnarn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/triton-tg/abcdef123456... \ --ssl-policy ELBSecurityPolicy-TLS-1-2-2017-01 \ --certificates CertificateArnarn:aws:acm:us-east-1:123456789012:certificate/abcdef123456...这里--certificates引用了 ACMAWS Certificate Manager里申请的 SSL 证书。如果你还没有可以用 ACM 免费申请一个通配符证书如*.yourdomain.com。最后为 ALB 分配一个 DNS 名称aws elbv2 describe-load-balancers \ --names triton-alb \ --query LoadBalancers[0].DNSName \ --output text输出类似triton-alb-1234567890.us-east-1.elb.amazonaws.com。这就是你的 Triton 服务对外地址。4.6 第六步验证服务可用性与性能基线服务上线后第一件事是验证端到端连通性。用 curl 测试curl -X POST https://triton-alb-123