主题
AWS Terraform 架构
在 AWS EKS 上自托管 LangSmith 的平台层、服务、IRSA 角色、网络,以及模块依赖。
了解 AWS Terraform 模块预配什么以及各部分如何组合,以便你在运行 make apply 之前为你的 LangSmith 部署做容量规划、加固和定制。
把本页当作规划一次推行或排查现有推行时的参考。它涵盖:
- 平台层和应用核心服务。
- AWS 托管服务、IRSA 角色和集群基础设施。
- 网络拓扑、ingress 选项和 TLS/DNS 策略。
- LangSmith Deployment 附加组件。
- 模块依赖图与选择性启用的安全模块。
如果你已准备好安装,从部署演练开始。
平台层
LangSmith 在 AWS 上分两个阶段带一个可选附加组件部署。基础设施阶段预配云基础。应用阶段安装 LangSmith Helm chart。LangSmith Deployment 附加组件是选择性启用的,增加 host-backend、listener 和 operator 服务,用于从 UI 管理 LangGraph 应用。

| 阶段 | 层 | 它增加什么 |
|---|---|---|
| 基础设施 | AWS 基础设施 | VPC + 私有/公共子网 + 单个 NAT 网关、EKS 集群 + 托管节点组 + 集群自动伸缩器、RDS PostgreSQL、ElastiCache Redis、S3 存储桶 + VPC Gateway Endpoint、ALB 控制器 + EBS CSI 驱动 + 指标服务器、k8s-bootstrap(KEDA、ESO、可选的 Envoy Gateway)。可选:Network Firewall、WAF、CloudTrail、ALB 访问日志。 |
| 应用 | LangSmith 应用 | backend、frontend、playground、queue、ace-backend、clickhouse。存储:RDS PostgreSQL(元数据)+ S3(追踪 blob 经 VPC 端点)。Ingress:ALB、NGINX、Envoy Gateway 或 Istio。 |
附加组件(enable_deployments = true) | LangSmith Deployment | host-backend、listener、operator。每个已部署图:api-server、queue、redis、postgres(operator 管理)。需要 KEDA(随基础设施经 k8s-bootstrap 一起安装)。 |
组件到存储的映射
| 组件 | 存储后端 | 访问方式 |
|---|---|---|
backend | RDS PostgreSQL | 私有子网、安全组 |
backend | S3 存储桶 | IRSA + VPC Gateway Endpoint |
clickhouse | EBS 卷(GP3,EKS PVC) | 本地 |
redis | ElastiCache 或集群内 | 私有子网、安全组 |
| LGP operator | RDS PostgreSQL(共享) | 私有子网、安全组 |
应用核心服务
这些 pod 在每次部署上运行。所有都写日志和指标;较繁忙的组件(backend、queue、ingest-queue)水平扩展。
| 服务 | 目的 | 端口 | HPA | IRSA | 依赖于 |
|---|---|---|---|---|---|
langsmith-frontend | React UI | 3000 | 1 到 10 | 否 | backend、platform-backend |
langsmith-backend | 主 API(追踪、运行、项目、API 密钥、反馈) | 1984 | 3 到 10 | 是(S3) | Postgres、Redis、ClickHouse、S3 |
langsmith-platform-backend | 组织与用户管理、身份验证、计费、设置 | 1986 | 1 到 10 | 是(S3) | Postgres、Redis、S3 |
langsmith-playground | LLM 提示 playground UI | 3001 | 1 到 10 | 否 | backend |
langsmith-queue | 追踪摄取 worker(Redis 到 ClickHouse + S3) | — | 3 到 10 + KEDA | 是 | Redis、ClickHouse、S3 |
langsmith-ingest-queue | 专用高吞吐摄取 worker | — | 3 到 10 + KEDA | 是 | Redis、S3 |
langsmith-ace-backend | 异步计算(数据集运行、评估、后台作业) | — | 1 到 5 | 否 | Postgres、Redis |
langsmith-clickhouse | 列式存储(追踪 span、运行元数据、评估结果) | — | StatefulSet,单副本 | 否 | EBS GP3 PVC |
WARNING
集群内 ClickHouse 仅供开发/POC(单 pod,无复制,无备份)。对于生产,使用 LangChain Managed ClickHouse 或一个自管理的外部集群。
NOTE
SmithDB 是 LangSmith 专为其构建的可观测性后端,自托管版本 0.16.0 起可用于自托管(参见自托管支持)。这些 Terraform 模块预配 ClickHouse,因此前面各节中的指引适用于当前的部署。
一次性作业
Helm chart 在安装和升级时运行三个作业:
| 作业 | 目的 |
|---|---|
langsmith-backend-migrations | PostgreSQL schema 迁移 |
langsmith-backend-ch-migrations | ClickHouse schema 迁移 |
langsmith-backend-auth-bootstrap | 用 langsmith-config 中的 initial_org_admin_password 创建初始组织和 admin 账户 |
LangSmith Deployment 附加组件
当 enable_deployments = true 时,会安装三个额外的服务并注册一个 LangGraphPlatform CRD。用户在 LangSmith UI 中创建的每个部署都会在 langsmith 命名空间中产生一个由 operator 管理的 Kubernetes Deployment。
| 服务 | 目的 |
|---|---|
langsmith-host-backend | LangGraph 控制平面 API。管理部署生命周期,服务部署元数据。S3 访问用 IRSA。 |
langsmith-listener | 监视 host-backend 的部署状态变化,创建并更新 LangGraphPlatform CRD。S3 访问用 IRSA。 |
langsmith-operator | Kubernetes operator。协调 LangGraphPlatform CRD,为每个 agent 创建并删除 Deployment 和 Service。 |
AWS 托管服务
当 postgres_source = "external" 且 redis_source = "external"(推荐的生产设置)时,Terraform 预配以下 AWS 托管服务:
RDS PostgreSQL
- 默认大小:
db.t3.large,私有子网,端口 5432。 - 存放组织、用户、项目、API 密钥、设置。
- 密钥流:SSM
/langsmith/{base_name}/postgres-password→ ESO →langsmith-config。
ElastiCache Redis
- 默认大小:
cache.m6g.xlarge,私有子网,TLS 端口 6379。 - 追踪摄取队列、pub/sub、短期缓存。
- 密钥流:SSM
/langsmith/{base_name}/redis-auth-token→ ESO →langsmith-config。
S3 存储桶
- 追踪负载:大的输入和输出、附件。
- 通过
langsmith_irsa_role使用 IRSA(无静态密钥)。VPC Gateway Endpoint,无公共互联网。 - 前缀:
ttl_s/(短 TTL)和ttl_l/(长 TTL)。 - 无论哪一层级,S3 存储桶始终必需。禁用 blob 存储会在大负载下使集群崩溃。
SSM Parameter Store
- 所有 LangSmith 机密的集中式机密存储。
- 流程:
source infra/scripts/setup-env.sh把机密写到 SSM。ESO 的ClusterSecretStore读取它们并投射出一个langsmith-configKubernetes Secret,Helm chart 通过config.existingSecretName挂载它。 - 前缀:
/langsmith/{name_prefix}-{environment}/。
集群基础设施
两个 Terraform 模块安装 LangSmith 依赖的集群级服务。eks 模块通过 eks-blueprints-addons 安装 AWS 集成控制器;k8s-bootstrap 模块安装工作负载依赖和可选的 ingress 网关(见 Ingress 选项):
| 服务 | 由谁安装 | 命名空间 | IRSA | 目的 |
|---|---|---|---|---|
aws-load-balancer-controller | eks | kube-system | 是 | 从 Kubernetes Ingress 对象预配 AWS ALB。删除 Ingress 会撤销预配 ALB 并在重建时分配一个新的 DNS 名,这会破坏 DNS 记录和 OIDC 重定向 URI。 |
cluster-autoscaler | eks | kube-system | 是 | 基于 pod 调度压力扩展 EC2 节点组。 |
ebs-csi-driver | eks | kube-system | 是 | 为 PersistentVolumeClaims(ClickHouse 使用)预配 EBS 卷。 |
| KEDA | k8s-bootstrap | keda | 否 | Kubernetes 事件驱动自动伸缩。基于 Redis 队列深度扩展 queue 和 ingest-queue。LangSmith Deployment 附加组件必需。 |
| cert-manager | k8s-bootstrap | cert-manager | 可选 | 自动化 TLS 证书签发,为 DNS-01 质询使用 Route 53 IRSA。仅在 tls_certificate_source = letsencrypt 或 create_cert_manager_irsa = true 时安装。 |
| External Secrets Operator | k8s-bootstrap | external-secrets | 是 | 把 SSM 参数同步进 langsmith-config Kubernetes Secret。 |
IRSA 角色
IRSA 取代静态凭据。EKS 集群的 OIDC 颁发者是信任锚;langsmith 和 kube-system 中的服务账户用角色 ARN 做注解,pod 通过 EKS 令牌 webhook 接收临时凭据。
| 角色 | 定义于 | 被谁使用 | 权限 |
|---|---|---|---|
langsmith_irsa_role | modules/eks | backend、platform-backend、queue、ingest-queue、host-backend、listener | 在 LangSmith 存储桶上的 s3:GetObject、s3:PutObject、s3:DeleteObject、s3:ListBucket |
aws_iam_role.eso | aws/infra/main.tf | ESO 控制器 | 在 /langsmith/* 上的 ssm:GetParameter、ssm:GetParameters、ssm:GetParametersByPath |
网络拓扑
默认 ALB ingress
graph TD
Internet(["Internet"])
ALB["AWS Application Load Balancer<br/>port 80/443, TLS via ACM or Let's Encrypt"]
subgraph EKS["EKS cluster (private subnets)"]
KubeSystem["kube-system<br/>aws-load-balancer-controller, cluster-autoscaler,<br/>ebs-csi-driver, keda"]
LangSmith["langsmith<br/>backend, frontend, playground, queue, clickhouse"]
end
RDS[("RDS PostgreSQL<br/>private subnet")]
Cache[("ElastiCache Redis<br/>private subnet, or in-cluster")]
S3[("S3 bucket<br/>VPC Gateway Endpoint, no public route")]
Internet -->|HTTPS| ALB
ALB --> LangSmith
LangSmith --> RDS
LangSmith --> Cache
LangSmith --> S3
classDef trigger fill:#F6FFDB,stroke:#6E8900,stroke-width:2px,color:#2E3900
classDef process fill:#E5F4FF,stroke:#006DDD,stroke-width:2px,color:#030710
classDef output fill:#EBD0F0,stroke:#885270,stroke-width:2px,color:#441E33
class Internet trigger
class ALB,KubeSystem,LangSmith process
class RDS,Cache,S3 output
Envoy Gateway(选择性启用)
使用 Terraform 默认值(enable_envoy_gateway = true)时,预配的 ALB 保持在前,通过一个 TargetGroupBinding 在 8080 端口绑定到 Envoy 服务,如ingress 选项表所示。下面的独立 Network Load Balancer 路径是一个 overlay 变体(helm/values/examples/langsmith-values-ingress-envoy-gateway.yaml),其中 NLB 直接终止 TLS:
graph TD
Internet(["Internet"])
NLB["AWS Network Load Balancer<br/>ACM TLS termination at 443"]
subgraph EGS["envoy-gateway-system"]
Envoy["Envoy proxy<br/>GatewayClass: eg, Gateway: langsmith-gateway"]
end
LangSmith["langsmith namespace<br/>backend, frontend, playground, queue, clickhouse"]
Agents["langsmith-agents namespace (optional dataplane)<br/>langgraph-dataplane listener, operator, agent pods"]
Internet -->|HTTPS| NLB
NLB --> Envoy
Envoy -->|HTTPRoute| LangSmith
Envoy -->|HTTPRoute| Agents
classDef trigger fill:#F6FFDB,stroke:#6E8900,stroke-width:2px,color:#2E3900
classDef process fill:#E5F4FF,stroke:#006DDD,stroke-width:2px,color:#030710
classDef decision fill:#FDF3FF,stroke:#7E65AE,stroke-width:2px,color:#504B5F
classDef output fill:#EBD0F0,stroke:#885270,stroke-width:2px,color:#441E33
class Internet trigger
class NLB process
class Envoy decision
class LangSmith,Agents output
langsmith 和 langsmith-agents 都通过一个带 allowedRoutes: All 的 HTTPRoute 附加到共享的 langsmith-gateway。
带 Network Firewall 的出口路径
当 create_firewall = true 时,来自私有子网的所有出站互联网流量在到达 NAT 网关之前被检查:
txt
EKS pods / RDS / ElastiCache (private subnets)
→ AWS Network Firewall (TLS SNI + HTTP Host inspection)
ALLOWLIST: firewall_allowed_fqdns (default: beacon.langchain.com)
DROP: all other established connections
→ NAT Gateway (public subnet)
→ Internetpod 到 pod、pod 到 RDS、以及 pod 到 ElastiCache 流量使用本地 VPC 路由,从不触碰防火墙。
Ingress 选项
四个互斥的 ingress 选项随模块一同提供。这个选择决定是否支持分立的 dataplane(agent pod 在单独的命名空间中)。
| 选项 | 变量 | 分立 | 流量路径 | 何时使用 |
|---|---|---|---|---|
| ALB(AWS LBC) | 默认 | 否 | ALB → frontend NodePort | 默认。单命名空间部署、POC、经 ACM 的最简单 TLS。 |
| NGINX Ingress | enable_nginx_ingress = true | 否 | ALB → TGB → NGINX controller → frontend ClusterIP | 当 NGINX 是你组织中的标准 ingress 时。 |
| Envoy Gateway | enable_envoy_gateway = true | 是 | ALB → TGB → Envoy service:8080 → HTTPRoute → services | 跨命名空间 HTTPRoute 路由。对新的 AWS 部署上的分立 dataplane 推荐。 |
| Istio | enable_istio_gateway = true | 是 | ALB → TGB → istio-ingressgateway:80 → VirtualService → services | 已安装 Istio 的集群,或当需要一个 mTLS 网格时。 |
为何 ALB 无法支持分立 dataplane
标准 Kubernetes Ingress 是命名空间范围的。ALB 控制器只路由到与 Ingress 资源同命名空间的服务。langsmith-agents 中的 agent pod 对 langsmith 中的 Ingress 不可见。Envoy Gateway 和 Istio 都通过 Kubernetes Gateway API 支持跨命名空间路由。
ALB 加 Envoy Gateway(链式)
当现有的 ALB 已经提供 SSO(Okta 或 Cognito OIDC)、WAF 和 TLS 时,Envoy Gateway 嵌在其后而非取代它:
txt
Internet
→ ALB (unchanged: WAF, SSO, TLS, DNS)
→ Envoy Gateway NLB (internal-scheme, auto-provisioned by k8s-bootstrap)
→ HTTPRoute → langsmith namespace (control plane)
→ HTTPRoute → langsmith-agents namespace (split dataplane)与默认 ALB 路径唯一的改动是把 ALB 目标组重新指向 Envoy NLB。有关 values overlay,见模块仓库中的 helm/values/examples/langsmith-values-ingress-envoy-gateway.yaml。
TLS 和 DNS
tls_certificate_source 变量控制证书策略:
| 模式 | 行为 | 兼容的网关 |
|---|---|---|
none | 仅 HTTP,无证书 | 任意 |
acm | 带 HTTP→HTTPS 重定向的 HTTPS:443。ACM 证书,自动预配或自带。 | ALB、NGINX |
letsencrypt | 经 cert-manager 和 Let's Encrypt 的 HTTPS,使用一个经 ALB 求解的 HTTP-01 质询 | ALB |
为何用 ACM 而非 cert-manager
ACM 证书不可导出。AWS 把它们直接附加到 ALB,这使 ACM 成为当 TLS 在 ALB 终止时的正确选择。当 TLS 在集群内部终止时(Istio Gateway、Envoy Gateway)无法使用 ACM,因为那些网关需要证书材料作为 Kubernetes Secret。
letsencrypt 来源是 ALB 路径的一个参考实现:它安装带一个绑定到 ALB ingress class 的 Let's Encrypt HTTP-01 ClusterIssuer 的 cert-manager。对于 Istio 或 Envoy 上的集群内 TLS,改设 create_cert_manager_irsa = true,它使用一个经 Route 53 验证的 DNS-01 ClusterIssuer。HTTP-01(经 ALB)与 DNS-01(经 Route 53)互斥。在生产中,把 ClusterIssuer 换成任何与 cert-manager 兼容的 issuer。
| Issuer | 何时使用 |
|---|---|
| Let's Encrypt (默认) | 公共域名、互联网访问、免费 |
ACM Private CA(aws-privateca-issuer) | AWS 原生、气隙友好、私有域名、付费 |
Venafi(cert-manager-venafi) | 企业 PKI、受监管环境 |
HashiCorp Vault(cert-manager-vault) | 自托管 PKI |
| DigiCert、Sectigo、其他 | ACME 或自定义 issuer 插件 |
Terraform 模块预配 cert-manager IRSA 角色和 Route 53 权限。各 issuer 之间只有 ClusterIssuer 清单改变。
自动预配的 DNS
当设置了 langsmith_domain 且 acm_certificate_arn 为空时,Terraform 激活 dns 模块,后者创建:
- 一个该域名的 Route 53 托管区域。
- 一个带 DNS 验证记录的 ACM 证书。
- 一个把域名指向 ALB 的 Route 53 别名记录。
分阶段部署模式: 先设置 langsmith_domain 配合 tls_certificate_source = "none"。Terraform 创建托管区域和证书,而不阻塞在验证上。在你的注册商处委派 NS 记录,然后在后续 apply 中切换到 tls_certificate_source = "acm"。Terraform 会阻塞直到证书验证通过并把它接入 HTTPS 监听器。
自带证书
直接设置 acm_certificate_arn 以跳过 dns 模块。对于集群内网关,手动创建一个 Kubernetes TLS Secret 并在 Gateway 或 VirtualService 中引用它。
模块依赖图
txt
vpc ─► firewall (optional, create_firewall = true)
│
├─► eks ─► k8s-bootstrap (KEDA, ESO, Envoy Gateway [opt-in])
│ └─► cert-manager (Let's Encrypt DNS-01 via Route 53 IRSA)
│
├─► postgres (RDS, private subnets from VPC)
├─► redis (ElastiCache, private subnets from VPC)
├─► storage (S3 bucket + VPC Gateway Endpoint)
├─► alb (pre-provisioned ALB, public subnets)
│ └─► alb_access_logs (S3 bucket for access logs, opt-in)
├─► dns (Route 53 zone + ACM cert, optional)
├─► bastion (jump host for private EKS access, optional)
├─► cloudtrail (audit logging, optional)
├─► waf (WAF ACL on ALB, optional)
└─► firewall (Network Firewall egress filter, optional)
all ─► langsmith (root module)选择性启用的安全模块
| 模块 | 变量 | 默认 | 目的 |
|---|---|---|---|
| Network Firewall | create_firewall | false | 基于 FQDN 的出口过滤。只允许 firewall_allowed_fqdns 中的域名(TLS SNI + HTTP Host)。需要 create_vpc = true。成本 ≈ $0.40/hr/endpoint + $0.065/GB processed。 |
| ALB 访问日志 | alb_access_logs_enabled | false | 流量分析与合规 |
| CloudTrail | create_cloudtrail | false | API 调用日志。若组织轨迹已存在则跳过。 |
| WAF | create_waf | false | WAFv2 Web ACL:OWASP Top 10、IP 信誉、已知不良输入 |
默认资源大小
| 资源 | 默认 | vCPU | 内存 |
|---|---|---|---|
| EKS 节点 | m5.4xlarge | 16 | 64 GB |
| RDS PostgreSQL | db.t3.large | 2 | 8 GB |
| ElastiCache Redis | cache.m6g.xlarge | 4 | 13.07 GB |
| RDS 存储 | 10 GB | — | — |
已验证的行为与已知约束
这些约束在 2026 年 4 月的网关排列组合测试运行中得到验证。
| # | 领域 | 约束或修复 |
|---|---|---|
| 1 | ACM 通配符 SAN | langchain.com 有 0 issue "amazon.com" CAA 但没有 0 issuewild "amazon.com"。通配符 SAN 会以 CAA_ERROR 失败。dns 模块只申请顶级域名。 |
| 2 | 集群内 Redis | LangSmith Helm chart 部署 Redis 时不带 requirepass。k8s_bootstrap 模块写 redis://langsmith-redis:6379。除非你同时配置 Helm chart 的 Redis 值,否则不要添加 auth 令牌。 |
| 3 | name_prefix 长度 | 最多 15 个字符。像 dz-nginx-tst(12 个字符)这样的名字是有效的。 |
| 4 | Istio 端口 | Istio 1.23+ ingressgateway 通过 NET_BIND_SERVICE 监听 80 端口,而非 8080 端口。ALB TGB 健康检查和安全组规则必须以 80 端口为目标。 |
| 5 | NGINX TGB 端口 | NGINX ingress-nginx 控制器 pod 监听 80 端口。TargetGroupBinding 目标类型是 ip。 |
| 6 | Envoy Gateway 端口 | Envoy Gateway 代理通过一个 Kubernetes 服务暴露在 8080 端口。ALB TargetGroupBinding 的 servicePort 必须是 8080,目标类型为 ip。 |
| 7 | 销毁顺序 | 始终先运行 terraform destroy 并让 Terraform 处理命名空间和 Helm release 生命周期。预先删除命名空间会导致 helm_release 资源超时,因为 Helm 无法干净地卸载进一个正在终止的命名空间。 |
| 8 | 卡在终止中的命名空间 | KEDA 陈旧的 external.metrics.k8s.io/v1beta1 API 组会导致 NamespaceDeletionDiscoveryFailure。修复:在重新运行 terraform destroy 之前 kubectl delete apiservice v1beta1.external.metrics.k8s.io。 |
验证命令
bash
# EKS cluster status
aws eks describe-cluster --name <cluster-name> --query "cluster.status"
# Node health
kubectl get nodes -o wide
# ALB status
kubectl get ingress -n langsmith
# RDS status
aws rds describe-db-instances \
--query "DBInstances[?DBInstanceIdentifier=='<db-id>'].DBInstanceStatus"
# ElastiCache status
aws elasticache describe-replication-groups \
--query "ReplicationGroups[?ReplicationGroupId=='<group-id>'].Status"
# S3 access from a pod (via VPC endpoint)
kubectl run s3-test --rm -it --image=amazon/aws-cli -n langsmith -- \
aws s3 ls s3://<bucket-name>