aws-samples / aws-samples/sample-eks-enterprise-quickstart
首次 apply 时的两个 race condition:CA Pod Identity 传播延迟 + ALB Controller webhook 时序
- Dominant language
- Shell
- Stars
- 5
- Forks
- 3
- Avg merge
- 34m
- Merged PRs (30d)
- 2
Description
## 现象
在全新账号上跑 `terraform apply` 时遇到两个 race condition,都发生在 terraform 资源创建完成 ↔ K8s 控制器真正 ready 这个边界。
### 1. Cluster Autoscaler ↔ Pod Identity Association
**症状**:首次 apply 看似成功完成,但 `cluster-autoscaler` pod 一直 CrashLoopBackOff。
**完整 pod 日志**(部署后约 12 分钟):
```
I0531 12:27:03.374052 1 aws_manager.go:81] AWS SDK Version: 1.40.1
I0531 12:27:03.374111 1 auto_scaling_groups.go:429] Regenerating instance to ASG map for ASG names: []
I0531 12:27:03.374118 1 auto_scaling_groups.go:436] Regenerating instance to ASG map for ASG tags: map[k8s.io/cluster-autoscaler/: k8s.io/cluster-autoscaler/enabled:]
E0531 12:27:03.400875 1 aws_manager.go:133] Failed to regenerate ASG cache: operation error Auto Scaling: DescribeAutoScalingGroups, https response error StatusCode: 403, RequestID: , api error AccessDenied: User: arn:aws:sts:::assumed-role/EKSNodeRole-/ is not authorized to perform: autoscaling:DescribeAutoScalingGroups because no identity-based policy allows the autoscaling:DescribeAutoScalingGroups action
F0531 12:27:03.400899 1 aws_cloud_provider.go:469] Failed to create AWS Manager: ...
```
注意 caller 是 `assumed-role/EKSNodeRole-` —— **节点 instance role**,不是 Pod Identity 关联的 role。说明 SDK 没拿到 Pod Identity 注入的 credentials,fallback 到了节点 IRSA,而节点 role 没 autoscaling 权限,导致 AccessDenied。
**确认 association + role 都是对的**:
```bash
$ aws eks list-pod-identity-associations --cluster-name --region us-west-2 \
--query 'associations[?serviceAccount==`cluster-autoscaler`]'
[
{
"clusterName": "",
"namespace": "kube-system",
"serviceAccount": "cluster-autoscaler",
"associationArn": "arn:aws:eks:us-west-2::podidentityassociation//",
"associationId": ""
}
]
$ aws iam get-role-policy --role-name -cluster-autoscaler \
--policy-name ClusterAutoscalerPolicy --query 'PolicyDocument.Statement[*].Action[]' --output json
[
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeLaunchConfigurations",
...
]
```
association 有,role policy 也有 `DescribeAutoScalingGroups` —— 但 pod 没用上。
**关键证据**:CA pod env 里**没有** Pod Identity 注入应该有的 `AWS_CONTAINER_CREDENTIALS_FULL_URI` / `AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE`:
```yaml
$ kubectl get pod -n kube-system -o yaml | grep -A 30 'env:'
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
- name: AWS_REGION
value: us-west-2
```
**Workaround**:`kubectl rollout restart deployment cluster-autoscaler -n kube-system`,新 pod 立刻拿到 `AWS_CONTAINER_CREDENTIALS_FULL_URI` env,正常拉 ASG list:
```
$ kubectl rollout restart deployment cluster-autoscaler -n kube-system
deployment.apps/cluster-autoscaler restarted
$ sleep 30; kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-cluster-autoscaler
NAME READY STATUS RESTARTS AGE
cluster-autoscaler- 1/1 Running 0 37s
```
**根因**:terraform 这边 `helm_release.cluster_autoscaler` 已经有 `depends_on = [aws_eks_pod_identity_association.cluster_autoscaler]`(参见 `terraform/modules/eks-addons/main.tf` line ~270),顺序是对的。但 EKS 控制面 association 创建调用**返回成功** ≠ Pod Identity Agent 的 admission webhook cache 已经识别这个 association。第一个被 webhook 处理的 CA pod 没拿到 `AWS_CONTAINER_*` env → SDK fallback 到节点 IRSA。
---
### 2. metrics-server ↔ ALB Controller webhook
**症状**:首次 apply 在 `aws_eks_addon.metrics_server` 失败:
```
module.eks_addons.aws_eks_addon.coredns: Creation complete after 24s [id=:coredns]
module.eks_addons.aws_eks_addon.metrics_server: Still creating... [00m30s elapsed]
╷
│ Error: waiting for EKS Add-On (:metrics-server) create: unexpected state 'CREATE_FAILED', wanted target 'ACTIVE'. last error: : AdmissionRequestDenied: Internal error occurred: failed calling webhook "mservice.elbv2.k8s.aws": failed to call webhook: Post "https://aws-load-balancer-webhook-service.kube-system.svc:443/mutate-v1-service?timeout=10s": no endpoints available for service "aws-load-balancer-webhook-service"
│
│ with module.eks_addons.aws_eks_addon.metrics_server,
│ on modules/eks-addons/main.tf line 44, in resource "aws_eks_addon" "metrics_server":
│ 44: resource "aws_eks_addon" "metrics_server" {
```
注意:`module.eks_addons.helm_release.alb_controller: Creation complete after 19s` —— helm release 已经"成功",但实际 ALB Controller pod / webhook endpoint 还没真正 ready。
**Workaround**:直接重跑 `terraform apply`(idempotent,这次能过,因为 ALB Controller 已经完全起来了)。
**根因**:
1. `aws_eks_addon.metrics_server` 没有显式 `depends_on = [helm_release.alb_controller]`(参见 `terraform/modules/eks-addons/main.tf` line 44),terraform 调度上可能在 ALB 之前就开始创建。
2. 即便有 depends_on,helm provider 默认 `wait=true` 是等 Deployment Available 就返回,但 webhook 的 Service endpoint 注册有几秒滞后。
ALB Controller 装好后会注册一个 admission webhook,拦截集群里**所有 Service 的 mutation**。metrics-server addon 创建过程里要建一个 Service → 触发 webhook → 此时 webhook Service 还没 endpoint → AdmissionRequestDenied。
---
## 可能的修法
这些都有 caveat,留给 maintainer 决定:
**Option A:加 `time_sleep` 强制等传播**
```hcl
resource "time_sleep" "wait_for_pod_identity_propagation" {
create_duration = "30s"
depends_on = [aws_eks_pod_identity_association.cluster_autoscaler]
}
resource "helm_release" "cluster_autoscaler" {
...
depends_on = [time_sleep.wait_for_pod_identity_propagation]
}
```
需要在 `versions.tf` 加 `time` provider。
优点:简单。
缺点:30s 是经验值,EKS 服务端响应变慢时还是可能 race。同样的模式要在 metrics-server / Karpenter / 其他 helm release 各处复制一次。
**Option B:用 `null_resource` provisioner 显式 `kubectl wait`**
等 ALB webhook 的 `endpoints` 真正 populate 出来再继续 metrics-server:
```hcl
resource "null_resource" "wait_alb_webhook_ready" {
provisioner "local-exec" {
command = "kubectl wait --for=jsonpath='{.subsets[*].addresses[0].ip}' endpoints/aws-load-balancer-webhook-service -n kube-system --timeout=120s"
}
depends_on = [helm_release.alb_controller]
}
resource "aws_eks_addon" "metrics_server" {
depends_on = [null_resource.wait_alb_webhook_ready]
...
}
```
优点:确定性。
缺点:apply runner 必须装 kubectl,而且要配好 kubeconfig(用 `local-exec` 时这通常 OK,但跨平台兼容性要注意)。
**Option C:不改代码,只在 README 说明**
README 加一段:"如果首次 apply 在 metrics-server 失败,重跑 apply 即可;如果 CA pod CrashLoopBackOff,跑 `kubectl rollout restart deployment cluster-autoscaler -n kube-system`"。
优点:零代码改动。
缺点:对 `aws-samples` 这种面向新用户的仓库 first-impression 不好。
我个人倾向 **Option C** —— 在 terraform 代码里背这些 EKS 服务端传播延迟的 workaround 维护成本高,而且 30s sleep 这种经验值难证明在所有 region / 所有时段都够。但这是你的选择。
如果你倾向 A 或 B,我可以提对应的 PR。
---
## 复现环境
- AWS 账号:全新(此前没用过 EKS,无任何 EKS / EKS-NG / AutoScaling / Spot / ELB SLR 预存)
- Region: us-west-2
- 仓库 commit: `110da9c` (main HEAD at time of repro)
- terraform: 1.10.x
- AWS provider: 6.x
- helm provider: 2.17.x
- kubernetes provider: 2.33.x
- EKS K8s 版本: 1.35
- 跑的 stack: 默认 on 部分(VPC Endpoints + EKS + System NG + Addons + EBS CSI + Cluster Autoscaler + ALB Controller),不带 Karpenter / 不带 GPU NG。
第一次 `terraform apply` 同时复现两个问题。重跑 apply 后 metrics-server 能过,CA 仍然需要手动 `kubectl rollout restart`。
Contributor guide
Assessment
This issue has not been assessed yet.