主题
AWS Terraform 故障排除
用 LangChain Terraform 模块部署、在 AWS EKS 上自托管 LangSmith 的常见问题、修复和诊断命令。
本页记录用 AWS Terraform 模块预配的 LangSmith 部署的常见问题、修复和诊断命令。
TIP
升级之前,查阅 LangSmith 自托管变更日志了解破坏性变更和必需的变量更新。在运行任何 kubectl 命令之前,先运行 aws eks update-kubeconfig --region <region> --name <cluster-name>。
有关本页各处所用 kubectl、helm 和 aws 调用的可复制粘贴参考,跳到诊断命令。
自动诊断
在运行单个命令之前,先试试随附的脚本:
bash
# Deployment status across all layers + next-step guidance
make status
# SSM parameter validation
./infra/scripts/manage-ssm.sh validate已知问题
EKS 节点组创建失败:CREATE_FAILED
症状
Error: waiting for EKS Node Group creation: unexpected state 'CREATE_FAILED'原因: 节点组创建开始时,EKS 控制平面尚未完全活动。在一次被打断的 apply 之后常见。
修复
bash
aws eks wait cluster-active --name <cluster-name> --region <region>
aws eks describe-nodegroup \
--cluster-name <cluster-name> \
--nodegroup-name <nodegroup-name> \
--region <region> \
--query "nodegroup.health"
terraform apply -var-file=terraform.tfvarskubectl 失败:"You must be logged in to the server"
症状: 所有 kubectl 命令都失败并报 error: You must be logged in to the server (Unauthorized)。
原因: kubeconfig 陈旧、AWS 凭据与创建集群者不同,或令牌已过期。
修复
bash
aws eks update-kubeconfig --region <region> --name <cluster-name>
kubectl cluster-info
aws sts get-caller-identity如果集群是用另一个 IAM 角色创建的,通过 aws-auth ConfigMap 授予访问:
bash
kubectl edit configmap aws-auth -n kube-system
# Add your IAM user or role under mapUsers / mapRolesHelm 安装后未创建 ALB
症状: 几分钟后 kubectl get ingress -n langsmith 不显示 ADDRESS。
原因: AWS Load Balancer Controller 未运行或缺少 IRSA 权限、Terraform 预配的 ALB 未被正确引用,或设了 alb_scheme = "internal"(内部 ALB 无公共地址;见 ALB 无公共地址)。
修复
bash
kubectl get pods -n kube-system | grep aws-load-balancer
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller --tail=50
kubectl get sa -n kube-system aws-load-balancer-controller -o yaml | grep eks.amazonaws.com
terraform output alb_dns_name
aws elbv2 describe-load-balancers --query "LoadBalancers[?DNSName=='<alb-dns-name>'].State"EKS pod 连接 RDS 被拒
症状: 后端日志显示到 RDS 端点的 connection refused 或 timeout。
原因: RDS 安全组不允许来自 EKS 节点或集群安全组的入站 TCP 5432。
修复
bash
aws eks describe-cluster --name <cluster-name> \
--query "cluster.resourcesVpcConfig.clusterSecurityGroupId"
aws rds describe-db-instances \
--db-instance-identifier <db-id> \
--query "DBInstances[0].VpcSecurityGroups"
aws ec2 describe-security-group-rules \
--filter "Name=group-id,Values=<rds-sg-id>"postgres 模块会自动设置安全组。如果规则缺失,重新 apply:
bash
terraform apply -var-file=terraform.tfvars -target=module.postgrespod 访问 S3 被拒(未配置 IRSA)
症状: 后端日志显示读写 S3 时 AccessDenied。
原因: LangSmith 服务账户缺少 IRSA 注解,或 S3 VPC Gateway Endpoint 未正确路由。
修复
bash
kubectl get sa langsmith -n langsmith -o yaml | grep eks.amazonaws.com
aws ec2 describe-vpc-endpoints \
--filters "Name=service-name,Values=com.amazonaws.<region>.s3" \
--query "VpcEndpoints[].State"
kubectl run s3-test --rm -it --image=amazon/aws-cli -n langsmith -- \
s3 ls s3://<bucket-name>如果缺少 IRSA 注解,核实 terraform.tfvars 中有 create_langsmith_irsa_role = true,且 Helm values 中的服务账户名与 langsmith 相匹配。
ElastiCache Redis 连接超时
症状: pod 无法连接 Redis。日志显示 dial tcp: i/o timeout。
原因: ElastiCache 安全组不允许来自 EKS 节点安全组的入站 TCP 6379。
修复
bash
aws elasticache describe-cache-clusters \
--cache-cluster-id <cluster-id> \
--query "CacheClusters[0].SecurityGroups"
kubectl run redis-test --rm -it --image=redis:7 -n langsmith -- \
redis-cli -h <elasticache-endpoint> -a <auth-token> pingEKS 节点不自动伸缩
症状: pod 保持 Pending。节点数不增加。
原因: Cluster Autoscaler 缺少 IAM 权限、指向了错误的 ASG,或节点组上 min_size = max_size。
修复
bash
kubectl logs -n kube-system -l app=cluster-autoscaler --tail=50
aws autoscaling describe-auto-scaling-groups \
--query "AutoScalingGroups[?contains(Tags[].Key, 'k8s.io/cluster-autoscaler/<cluster-name>')].[AutoScalingGroupName]" \
--output tablecert-manager 无法签发 Let's Encrypt 证书
症状: kubectl get certificate -n langsmith 显示 READY=False。HTTP01 质询失败。
原因: ALB 未把端口 80 转发到 cert-manager 求解器 pod,或该域名的 DNS 记录没指向 ALB。
修复
bash
kubectl describe certificate <cert-name> -n langsmith
kubectl get challenges -n langsmith
aws elbv2 describe-listeners --load-balancer-arn <alb-arn>
dig +short <your-langsmith-domain>
# Expected: CNAME to the ALB DNS namepostgres_deletion_protection 阻止 terraform destroy
症状
Error: deleting RDS DB Instance: InvalidParameterCombination:
Cannot delete, DeletionProtection is enabled.修复: 在 terraform.tfvars 中禁用删除保护,apply,然后 destroy:
hcl
postgres_deletion_protection = falsebash
terraform apply -var-file=terraform.tfvars
terraform destroyESO 同步失败:langsmith-config secret 缺失
症状: pod 卡在 CreateContainerConfigError。kubectl get secret langsmith-config -n langsmith 返回 NotFound。
原因: ESO 同步是全有或全无。如果 ExternalSecret 引用的任何一个 SSM 参数缺失,ESO 会拒绝创建 Kubernetes Secret。所有 pod 都失败,包括与缺失参数无关的那些。
修复
bash
kubectl get externalsecret langsmith-config -n langsmith
kubectl describe externalsecret langsmith-config -n langsmith
./infra/scripts/manage-ssm.sh validate
source ./infra/scripts/setup-env.sh
./helm/scripts/apply-eso.shdescribe 输出会显示哪个 remoteRef.key 失败。把它与 SSM 前缀 /langsmith/{name_prefix}-{environment}/ 对照匹配。
SSM 参数前缀不匹配
症状: manage-ssm.sh validate 通过但 ESO 仍无法同步。或 setup-env.sh 把参数写到了 ESO 所期望之外的另一个前缀下。
原因: SSM 前缀由 terraform.tfvars 中的 name_prefix 和 environment 派生。如果这些在初始设置后改变了,旧参数生活在旧前缀下,而 ESO 在新前缀下查找。
修复
bash
kubectl get externalsecret langsmith-config -n langsmith -o yaml | grep 'key:'
./infra/scripts/manage-ssm.sh list
./infra/scripts/migrate-ssm.shWARNING
绝不要在现有部署上更改 name_prefix 或 environment。
Terraform 校验拒绝 Postgres 密码
症状
Error: Invalid value for variable "postgres_password"
RDS master password must not contain '/', '@', '"', single quotes, or spaces.原因: 密码含有 RDS 不允许出现在主密码中的字符。
修复: 重新生成一个不含受限字符的密码。setup-env.sh 会自动生成一个合规密码;要手动更新:
bash
./infra/scripts/manage-ssm.sh set postgres-password "$(openssl rand -base64 24 | tr -d '/+= ')"
source ./infra/scripts/setup-env.sh
terraform apply -var-file=terraform.tfvars私有 EKS 集群不可达(需要 bastion)
症状: 当 enable_public_eks_cluster = false 时,kubectl 和 terraform apply 超时。
原因: EKS API 端点是私有的。命令必须在 VPC 内运行,通过 bastion 主机或 VPN 连接。
修复
bash
# If the bastion was provisioned (create_bastion = true)
aws ssm start-session --target <bastion-instance-id>
# From the bastion
aws eks update-kubeconfig --region <region> --name <cluster-name>
kubectl get nodes如果没有预配 bastion,设 create_bastion = true 并重新 apply,或临时设 enable_public_eks_cluster = true。
ALB 无公共地址(internal 方案)
症状: kubectl get ingress -n langsmith 显示一个 ADDRESS,但它只在 VPC 内解析。
原因: 在 terraform.tfvars 中设了 alb_scheme = "internal"。内部 ALB 只能从 VPC 内(VPN、对等或 PrivateLink)访问。
修复: 对私有部署是有意为之。要让 ALB 可被公共访问:
hcl
alb_scheme = "internet-facing"bash
terraform apply -var-file=terraform.tfvars
# Then redeploy Helm to pick up the new ALBingress 重建后 ALB 主机名改变
症状: LangSmith URL 停止工作。agent 部署卡在 DEPLOYING。DNS 记录或书签指向一个不再解析的旧 ALB 主机名。
原因: 删除 Kubernetes ingress(通过 helm uninstall、kubectl delete ingress 或命名空间删除)会撤销预配 ALB。当 ingress 被重建时,会签发一个带不同主机名的新 ALB。Helm values 中的 config.deployment.url 仍指向旧主机名,所以 operator 的健康检查失败,部署一直卡住。
如果 ALB 控制器创建了一个新 ALB 而非复用 Terraform 预配的那个,也会发生这种情况。要防止这一点,group.name 注解必须与 load-balancer-arn 一起设置。
预防
- 确保
group.name和load-balancer-arn注解都设置了。当存在一个预配的 ALB 时,init-values.sh会自动这样设置。 - 除非你打算更新所有依赖主机名的配置,否则不要删除 ingress。
- 避免不带
--server-side=false的helm rollback。ingress 的 SSA 冲突可能触发一次删除/重建循环。
修复
bash
# 1. Check what hostname the ingress currently has
kubectl get ingress langsmith-ingress -n langsmith \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
# 2. Check what Terraform expects
terraform output alb_dns_name
# 3. If they differ, re-run init-values.sh and redeploy
make init-values
make deployTerraform 未应用节点组伸缩更改
症状: 在 terraform.tfvars 中更改 min_size 或 max_size,terraform plan 显示“No changes”。
原因: ASG 被带外更改(AWS CLI、控制台或 cluster autoscaler),且 Terraform 状态已反映新值。社区 EKS 模块忽略 desired_size 更改以便 autoscaler 能管理它;min_size 和 max_size 应当正常传播。
修复
bash
terraform refresh
terraform plan
# For an immediate change, use the AWS CLI directly
aws eks update-nodegroup-config \
--cluster-name <cluster> \
--nodegroup-name <nodegroup> \
--scaling-config minSize=3,maxSize=8,desiredSize=5 \
--region <region>诊断命令
集群访问
bash
aws eks update-kubeconfig --region <region> --name <cluster-name>
kubectl config current-context
kubectl get nodes -o wide
aws sts get-caller-identityPod
bash
kubectl get pods -n langsmith
kubectl get pods -n langsmith -w
kubectl describe pod <pod-name> -n langsmith
kubectl logs <pod-name> -n langsmith --tail=50
kubectl logs <pod-name> -n langsmith --previous --tail=50
kubectl logs -n langsmith deploy/langsmith-backend --tail=100 -fALB 与 ingress
bash
kubectl get ingress -n langsmith
kubectl describe ingress -n langsmith
aws elbv2 describe-load-balancers --query "LoadBalancers[?contains(LoadBalancerName, 'langsmith')]"TLS 与证书
bash
kubectl get certificate -n langsmith
kubectl describe certificate <cert-name> -n langsmith
kubectl get challenges -n langsmith
kubectl get clusterissuerESO 与机密
bash
kubectl get externalsecret -n langsmith
kubectl describe externalsecret langsmith-config -n langsmith
kubectl get clustersecretstore langsmith-ssm
kubectl get secret langsmith-config -n langsmith -o jsonpath='{.data}' | jq 'keys'
./infra/scripts/manage-ssm.sh validate
./infra/scripts/manage-ssm.sh diffHelm
bash
helm status langsmith -n langsmith
helm history langsmith -n langsmith
helm get values langsmith -n langsmithIRSA 与 IAM
bash
kubectl get sa langsmith -n langsmith -o yaml | grep eks.amazonaws.com
terraform output langsmith_irsa_role_arn
aws iam get-role --role-name <irsa-role-name>LangSmith Deployment
bash
kubectl get pods -n langsmith | grep -E "host-backend|listener|operator"
kubectl get lgp -n langsmith
kubectl get crd | grep langchain
kubectl get pods -n keda快速健康检查
bash
echo "=== Context ===" && kubectl config current-context
echo "=== Nodes ===" && kubectl get nodes
echo "=== Pods ===" && kubectl get pods -n langsmith
echo "=== Ingress ===" && kubectl get ingress -n langsmith
echo "=== Helm ===" && helm status langsmith -n langsmith 2>/dev/null | grep -E "STATUS|LAST DEPLOYED"