본문으로 건너뛰기
클러스터 설정 — Fargate+karpenter 토폴로지와 Terraform 리소스

클러스터 설정 — Fargate+karpenter 토폴로지와 Terraform 리소스

  • managed nodegroup은 0개입니다. Fargate가 CoreDNS와 karpenter 컨트롤러만 호스팅하고 나머지는 전부 karpenter NodePool(system 풀 포함)이 프로비저닝합니다.
  • Fargate 3제약이 토폴로지를 지배합니다 — amd64 전용 · DaemonSet 미부착 · 동적 EBS 불가.
  • Terraform 최대 리스크는 둘입니다. OIDC 이중등록(빠뜨리면 external-secrets 포함 cross-account IRSA 전체가 아무 에러 없이 깨집니다), 그리고 ebs-csi IRSA 롤(스펙에 필드 자체가 없어 놓치기 쉽습니다).
  • karpenter 인프라 전체(IRSA·노드 롤·interruption·discovery 태그)는 이 레포에 전무해 처음부터 짜야 합니다.

이 페이지는 배경의 결정과 목표버전 1.35 위에서, 클러스터가 무엇인가(토폴로지 + Terraform 리소스)를 다룹니다. “어떤 순서로 올리나"는 04 부트스트랩이, EKS managed addon 버전·설정은 03 managed addon이 이어받습니다.

1. 목표 토폴로지

Karpenter를 Fargate 위에서 돌리는 것은 karpenter 공식 getting-started가 정식으로 제공하는 옵션(“managedNodeGroups 대신 fargateProfiles 사용”)입니다. 이 프로젝트는 그 옵션 위에 CoreDNS까지 추가해 managed nodegroup을 아예 두지 않는 형태로 갑니다.

Fargate profile({ns:karpenter}, {ns:kube-system·k8s-app:kube-dns})에 CoreDNS·karpenter(amd64, arm64 affinity 제거)를 두고, karpenter가 system(arm64)·service/airflow(amd64) NodePool을 프로비저닝합니다. 플랫폼 컨트롤러·DaemonSet은 arch=arm64 required affinity.
도식 텍스트
  • Fargate profile
  • NodePool: system (arm64)
  • NodePool: service·airflow
  • CoreDNS — replica 2 · Fargate
  • karpenter — controller · IRSA
  • ebs-csi — controller
  • 플랫폼 컨트롤러 — alb·ESO·argo·metrics
  • DaemonSet — datadog·fluentbit·…
  • 일반 워크로드
  • 프로비저닝
  • 프로비저닝

managed nodegroup이 없으므로 첫 EC2 노드는 karpenter 자신이 만듭니다. CoreDNS와 karpenter는 EC2 노드 없이 Fargate에서 뜰 수 있는 유일한 두 컴포넌트입니다. 그 둘이 살아나야 나머지(ebs-csi·ALB controller·external-secrets 등)가 착지할 EC2 노드가 생깁니다. 노드 없이 뜨는 두 컴포넌트가 나머지의 착지장을 만듭니다. 토폴로지의 뼈대가 여기 있습니다. 단계별 부트스트랩 순서(닭-달걀 풀기)는 04 부트스트랩이 다룹니다. arm64 required affinity가 걸린 플랫폼 컴포넌트는 arm64 풀이 system 하나뿐이라 전부 거기로 몰립니다. system 풀 사이징은 이 컴포넌트 총합을 수용해야 합니다(§3).

2. Fargate 3대 물리 제약

EKS 공식 문서 기준으로 아래 제약이 설계 전체를 지배합니다.

  1. amd64 전용(Arm 미지원). CoreDNS·karpenter에 원래 붙어 있던 arm64 required nodeAffinity·toleration을 반드시 제거해야 합니다. 지우지 않으면 Fargate 스케줄러가 배치를 시도조차 하지 않아 영구 Pending이 됩니다.
  2. DaemonSet 미지원. Fargate는 파드 하나에 전용 micro-VM 하나를 붙이는 구조라 “노드” 개념이 없고 노드 기반 DaemonSet이 존재할 자리도 없습니다. csi-node·datadog·fluentbit·node-exporter·node-local-dns·kube-proxy·aws-node 어느 것도 Fargate 파드에는 붙지 않습니다(§4).
  3. 동적 EBS 마운트 불가. EBS CSI 컨트롤러 자체는 Fargate에서 돌 수 있지만 실제 볼륨을 붙이는 csi-node DaemonSet은 EC2 전용입니다. 그래서 Fargate 파드는 동적 프로비저닝 EBS PV를 쓸 수 없습니다(EFS 정적 프로비저닝은 예외적으로 가능하나 finance는 EFS를 쓰지 않아 무관합니다).

세 제약 모두 CoreDNS·karpenter에는 문제가 되지 않습니다 — 둘 다 EBS가 필요 없고 arm64 고정만 풀면 amd64로 문제없이 뜹니다. 제약이 실제로 부딪히는 곳은 DaemonSet 공백(§4)입니다.

3. 컴포넌트 배치 매트릭스

배치처는 Fargate(amd64 micro-VM), system pool(arm64 EC2), workload pool(amd64 EC2), DaemonSet(전 EC2 노드) 네 곳입니다.

컴포넌트배치처arch필요 조치
CoreDNSFargateamd64arm64/system-primary required affinity·toleration 전부 제거 + computeType: Fargate 추가
karpenter controllerFargateamd64arm64 affinity·toleration 제거, IRSA 유지, cpu=1/mem≥1Gi로 리소스 상향
ebs-csi controllersystem poolarm64nodegroup 셀렉터를 system 풀 라벨로 재타깃, arch=arm64 toleration 유지
ebs-csi node(csi-node)DaemonSet(EC2 전용)노드 arch변경 없음 — Fargate에는 원천적으로 안 붙는다
metrics-serversystem poolarm64변경 불요 — arm64 유일 풀이 system이라 자동 착지
ALB controllersystem poolarm64자동 착지. 옛 nodegroup 셀렉터 toleration은 무해한 잔재라 정리 권장
external-secrets(+cert+webhook)system poolarm64변경 불요
argo-rollouts(+dashboard)system poolarm64변경 불요
datadog agentDaemonSet(EC2 전용)노드 archFargate에는 안 붙는다(§4)
fluentbitDaemonSet(EC2 전용)노드 archFargate에는 안 붙는다(§4)
node-exporterDaemonSet(EC2 전용)노드 archFargate VM의 호스트 메트릭은 원천적으로 없다(§4)
node-local-dnsDaemonSet(EC2 전용)노드 archFargate 파드에는 적용되지 않는다(§4)
kube-proxy / aws-nodeDaemonSet노드 archFargate 노드는 자체 VPC CNI 내장, kube-proxy 불요(정상)
일반 워크로드workload poolamd64service/airflow 풀

4. DaemonSet 공백과 대안

Fargate 파드(CoreDNS, karpenter)에는 노드 DaemonSet이 붙지 않습니다. 노드 기반 로그·메트릭 수집기가 이 두 파드를 놓칩니다.

  • fluentbit(컨테이너 로그) · 공백: CoreDNS/karpenter stdout 미수집 — Fargate 내장 로그 라우터로 대체합니다. ns aws-observability(label aws-observability: enabled) + ConfigMap aws-logging으로 output을 지정하면 AWS가 대신 Fluent Bit를 구동합니다. 단 pod-execution-role에 로깅 IAM 정책(logs:CreateLogStream/CreateLogGroup/PutLogEvents)을 별도 부착해야 동작합니다 — 기본 정책엔 없습니다.
  • datadog agent(노드 메트릭·APM) · 공백: CoreDNS/karpenter 메트릭 미수집 — Fargate에서는 파드별 사이드카로만 수집합니다. CoreDNS/karpenter에 사이드카는 과하므로 karpenter /metrics는 Prometheus 계열 스크레이퍼로 직접 긁습니다.
  • node-exporter(호스트 메트릭) · 공백: Fargate micro-VM 호스트 메트릭 없음 — 설계상 호스트에 접근할 수 없습니다. kubelet 파드 지표(cAdvisor)로 대체하고 대시보드는 Fargate 노드 제외 필터를 씁니다.
  • node-local-dns(노드별 DNS 캐시) · 공백: Fargate 파드는 로컬 캐시 미사용 — EC2 노드 DaemonSet(iptables 인터셉트) 기반이라 Fargate엔 셋업 자체가 없습니다. 클러스터 CoreDNS 서비스로 직접 질의합니다(로컬 캐시만 스킵). CoreDNS는 캐시가 필요 없고 karpenter는 조회량이 적어 영향이 미미합니다.
  • csi-node · 공백: Fargate 파드는 동적 EBS PV 불가 — EBS가 필요한 워크로드는 반드시 EC2 풀로 보냅니다.
  • kube-proxy / aws-node · 공백 없음 — Fargate 노드는 자체 VPC CNI 내장, kube-proxy 불요(정상).

5. CoreDNS·ebs-csi·karpenter config 변경

이 세 컴포넌트는 기존 값(system-primary 노드그룹·arm64 고정)을 그대로 두면 새 토폴로지에서 동작하지 않습니다. Fargate가 강제하는 config 값 변경만 정리합니다.

5.1 CoreDNS addon config

항목기존신규이유
computeType(없음)Fargate 추가compute-type: ec2 annotation 제거해야 Fargate 스케줄러가 잡는다
nodeAffinity(arm64 + system-primary)required전부 제거arm64 required가 남으면 영구 Pending
toleration(system-primary/arch=arm64)제거Fargate엔 taint 자체가 없어 무의미
replicaCount: 2유지Fargate micro-VM 2개로 그대로 뜬다
topologySpreadConstraints(zone, DoNotSchedule)유지하되 주의AZ 분산 유지, 단 Pending 위험(하단 참고)

topologySpreadConstraints는 profile subnet이 2 AZ 이상이면 분산되지만 DoNotSchedule이라 한 AZ만 여유가 있으면 두 번째 replica가 Pending될 수 있습니다.

5.2 ebs-csi addon config

항목기존신규이유
nodeAffinity(nodegroup=system-primary)required라벨로 변경managed nodegroup 폐지 → system 풀 라벨 사용
controller nodeAffinity(arm64)required유지system 풀 자체가 arm64
toleration(system-primary)제거(무해한 잔재)system 풀엔 arch=arm64 taint만, nodegroup taint는 없다
IRSA 롤스펙에 없음 ⚠️Terraform으로 신규 생성(§7·§10)미해결 최대 리스크 — 연결·PVC 검증은 하단 참고

IRSA 롤이 addon에 실제로 연결되는지·PVC가 붙는지 검증은 03 managed addon에서 확인합니다.

5.3 karpenter values

항목조치이유
컨트롤러 affinity.nodeAffinity(arm64 + system-primary)제거Fargate는 amd64 전용
컨트롤러 tolerations(arch/nodegroup/spot)제거Fargate엔 taint가 없다
controller.resourcescpu: 1 / mem ≥ 1Gi(requests=limits) 명시Fargate는 requests로 micro-VM 크기를 정한다
featureGates.drift제거(v1에서 무효)karpenter v1에서 drift가 GA돼 feature gate가 사라졌다
provisioner→nodePoolv1 NodePool/EC2NodeClass 재작성, arm64 system 풀 포함system 풀 누락 시 arm64 Pending

controller.resources 기본값(0.25 vCPU/256Mi)으로 두면 CPU가 굶어 리더 election이 반복 유실됩니다. 사내에서 실제로 겪은 사고이니 반드시 cpu: 1 / mem ≥ 1Gi로 상향합니다.

karpenter 0.36.2→1.14.0 버전 업그레이드 자체(CRD v1beta1→v1·IAM·배포 절차)는 컴포넌트별 마이그레이션 — karpenter가 이어받습니다.

6. 기존 Terraform 자산 실사 — 무엇을 재활용하고 무엇을 버리나

IaC 레포에는 EKS 클러스터를 만드는 모듈이 이미 있지만 실제로 쓰이는 것은 거의 없습니다. 호출 여부(참조 카운트)를 기준으로 재활용 판정을 내립니다.

  • modules/clusters/eks(호출 0건) · aws_eks_cluster + aws_eks_node_group(관리형, AL2_ARM_64 하드코딩) + 런치템플릿 + OIDC provider — 부분 재활용: 클러스터 셸은 유효하나 access_config·encryption_config 필드가 없어 추가해야 합니다. 노드그룹·런치템플릿은 삭제합니다(Fargate-only와 충돌 + AL2는 1.33+ 신규 노드그룹에 선택 불가).
  • modules/clusters/addons(호출 0건) · aws_eks_addon 4종 generic for_each + config JSON file() 주입 — 구조 재활용 가치가 높아 버전 문자열만 1.35로 바꾸면 됩니다. 단 ebs-csi 전용 블록엔 service_account_role_arn 인자가 없어 IRSA 롤은 generic 블록을 경유해 주입합니다.
  • modules/clusters/security_groups(호출 0건) · cluster SG에 ALB→8080/15021 ingress 등 SG 규칙만 — 재활용 가능합니다. SG 리소스 정의는 여전히 이 레포 밖에 있습니다.
  • modules/clusters/sqs(호출 0건) · 범용 앱 DLQ(main+dead-letter, redrive, prevent_destroy) — karpenter interruption 큐로는 재활용할 수 없습니다. EventBridge 배선도 큐 정책도 없습니다. §8에서 전용으로 새로 씁니다.
  • modules/irsa(실사용 다수) · IRSA 롤 팩토리 — 트러스트가 data.aws_eks_cluster[name].identity[0].oidc.issuer로 동적 바인딩 — 재활용: §10 재바인딩 메커니즘 자체.

dead code의 시대감각: modules/clusters/ekseks_version 기본값이 관리형 노드그룹이 표준이던 시절 값입니다. Fargate-only·karpenter-only가 확정된 지금은 그대로 재활용하기보다 골격만 참조해 다시 쓰는 편이 현실적입니다.

이미 존재하는 Fargate 프로토타입 (stage)

“Fargate로 coredns+karpenter만” 패턴은 사실 stage에 이미 Terraform으로 작성돼 있습니다(ring0-blue의 Fargate 패턴을 따랐다는 주석이 남아 있습니다).

리소스정의
Fargate pod-exec trusteks-fargate-pods.amazonaws.com, aws:SourceArn = fargateprofile/${cluster_name}/*로 스코핑
Fargate pod-exec role${cluster_name}-fargate-role + AmazonEKSFargatePodExecutionRolePolicy
aws_eks_fargate_profile${cluster_name}-fargate, subnet = green private only, selector 2종
selector{ns: karpenter} + {ns: kube-system, labels:{k8s-app: kube-dns}}

재활용 판정은 높습니다. cluster_name을 blue 이름으로, subnet 필터를 blue private subnet으로만 바꾸면 그대로 동작합니다(stage blue subnet은 이미 선provisioned 상태입니다). prod에는 이 Fargate 스택 자체가 없습니다. stage 패턴을 복제해 새로 써야 하고 prod blue 클러스터용 subnet도 아직 어디에도 정의돼 있지 않습니다. prod 재구축 전에 subnet 확보가 선행돼야 합니다. 또 selector는 파드 생성 시점에만 평가되므로 프로필 생성 후 대상 워크로드를 rollout restart해야 합니다. coredns의 arm64 nodeAffinity도 먼저 제거해야 합니다(§2).

kube-proxy addon mode 변수화 — nftables opt-in 준비

modules/clusters/addonsconfiguration_values를 정적 JSON으로 주입하는 구조라 kube-proxy mode도 코드에 박혀 있습니다. 이번 이관은 iptables를 유지하되(정정 상세는 03 managed addon), 향후 전환을 한 줄 변경으로 끝내도록 kube-proxy 블록만 변수화해 둡니다.

variable "kube_proxy_mode" {
  description = "kube-proxy 프록시 모드. EKS addon 기본값은 iptables이며, addon v1.31+ 계열부터 nftables opt-in 가능(ipvs는 1.35 deprecated, 코드 삭제는 KEP-5495 기준 ~v1.43 예정)."
  type        = string
  default     = "iptables"
  validation {
    condition     = contains(["iptables", "nftables"], var.kube_proxy_mode)
    error_message = "kube_proxy_mode는 iptables 또는 nftables만 허용한다."
  }
}

기본값은 iptables로 두고 전환 시 kube_proxy_mode = "nftables"로 apply한 뒤 kubectl -n kube-system rollout restart ds kube-proxy로 기존 규칙셋을 정리합니다.

7. CAPA → Terraform 매핑

CAPI 스펙(clusterapi.yaml)이 만들던 것을 Terraform 리소스로 1:1 대응시킵니다.

#CAPA가 하던 것Terraform 대체비고
1클러스터 IAM roleaws_iam_role + AmazonEKSClusterPolicy(신규)롤 자체 신규 작성
2aws_eks_cluster 설정(버전·VPC·endpoint·로깅·태그)모듈 골격 재사용(상세 하단)
3OIDC provider(워크로드 계정에만)aws_iam_openid_connect_provider ×2(워크로드+mgmt)§10
4인증/roleMappingaccess_config(API_AND_CONFIG_MAP) + aws_eks_access_entry§9
5managed addon 4종aws_eks_addon ×4(버전 1.35)03 상세
6ebs-csi SA-role(스펙에 없음)modules/irsa로 신규 생성(상세 하단)최우선 리스크(§10)
7Fargate 프로필 2셀렉터aws_eks_fargate_profile + pod-exec role(§6 재활용)
8부트스트랩 관리형 노드그룹없음(삭제)Fargate+karpenter가 대체
9securityGroupOverridesvpc_config.security_group_ids + SG 모듈SG 정의는 레포 밖
10additionalControlPlaneIngressRulesaws_security_group_rule(cluster SG ingress)
11secrets KMS 암호화(현재 미설정)(선택) encryption_config + aws_kms_key보안 baseline 권장
12bastion해당 없음CAPI 스펙에 없음

2번 상세: version=1.35, blue subnet, endpoint_private_access=true/public_access=false, enabled_cluster_log_types=["audit"]. 6번 상세: modules/irsaebs-csi-controller-sa IRSA + AmazonEBSCSIDriverPolicyV2(신규)를 생성합니다. 8번은 부트스트랩 관리형 노드그룹이 사라지고 Fargate가 coredns+karpenter를, karpenter가 나머지를 프로비저닝하는 구조로 대체됩니다.

8. karpenter 인프라 신규 작성 — 레포에 전무한 부분

컨트롤러 IRSA·노드 롤·interruption SQS·discovery 태그 어느 것도 이 레포에 없습니다. karpenter 공식 CloudFormation 레퍼런스와 getting-started를 근거로 전부 새로 씁니다.

8.1 컨트롤러 IRSA role

karpenter 컨트롤러를 Fargate로 호스팅하므로 인증 경로는 IRSA(OIDC) 입니다 — Pod Identity는 DaemonSet 기반 Agent가 필요해 Fargate를 지원하지 않습니다. 트러스트는 신규 OIDC issuer + system:serviceaccount:karpenter:karpentermodules/irsa 동적 바인딩 패턴 그대로 작성합니다. karpenter 1.14 기준 컨트롤러 정책은 6묶음입니다.

NodeLifecyclePolicy       # RunInstances/CreateFleet/CreateLaunchTemplate/TerminateInstances (태그 스코핑)
IAMIntegrationPolicy      # PassRole(노드 롤), CreateInstanceProfile/AddRoleToInstanceProfile — 클러스터명 스코핑
EKSIntegrationPolicy      # eks:DescribeCluster
InterruptionPolicy        # sqs:DeleteMessage/GetQueueUrl/ReceiveMessage
ZonalShiftPolicy          # arc-zonal-shift:GetManagedResource
ResourceDiscoveryPolicy   # ec2:Describe*, ssm:GetParameter, pricing:GetProducts, iam:ListInstanceProfiles(v1.7+)

v1.11+에서 ec2:DescribePlacementGroups, v1.12+에서 ec2:DescribeInstanceStatus가 추가로 필요합니다.

8.2 노드 IAM role + instance profile

EC2 trust aws_iam_role + managed policy 4종: AmazonEKSWorkerNodePolicy, AmazonEKS_CNI_Policy, AmazonEC2ContainerRegistryPullOnly(구 ReadOnly 대체), AmazonSSMManagedInstanceCore. instance profile은 karpenter v1.7+가 자동 관리할 수 있으나 finance는 정적 instance profile 참조 방식을 유지합니다. vpc-cni가 스펙에 SA-role이 없는 구조라 노드 롤에는 AmazonEKS_CNI_Policy를 유지하는 편이 안전합니다.

8.3 Interruption SQS + EventBridge

aws_sqs_queue(이름은 차트 settings.interruptionQueue 값과 일치해야 소비됩니다) + aws_sqs_queue_policy(principal events.amazonaws.com+sqs.amazonaws.com, sqs:SendMessage, aws:SecureTransport:false deny). aws_cloudwatch_event_rule+target 5종을 큐로 연결합니다.

규칙sourcedetail-type
ScheduledChangeaws.healthAWS Health Event
SpotInterruptionaws.ec2EC2 Spot Instance Interruption Warning
Rebalanceaws.ec2EC2 Instance Rebalance Recommendation
InstanceStateChangeaws.ec2EC2 Instance State-change Notification
CapacityReservationInterruptionaws.ec2EC2 Capacity Reservation Instance Interruption Warning

8.4 subnet / SG의 discovery 태그

karpenter는 subnet·SG의 karpenter.sh/discovery: ${CLUSTER_NAME} 태그로 프로비저닝 대상을 발견합니다(EC2NodeClass의 selectorTerms). 이 태그는 현재 TF에 0건이라 blue subnet·SG에 새로 붙여야 karpenter가 노드를 띄웁니다. 내부 ALB 전제라 ALB용 kubernetes.io/role/internal-elb=1 태그도 같은 subnet에 함께 붙입니다.

8.5 karpenter 노드 롤의 클러스터 접근

access entries를 채택하면(§9) 노드 롤은 **aws_eks_access_entry(type=EC2_LINUX)**로 조인시킵니다. 관리형 노드그룹·Fargate profile 롤은 EKS가 access entry를 자동 생성하지만 karpenter가 띄우는 노드는 self-managed 취급이라 이 access entry만은 명시 작성해야 조인합니다.

9. 인증 모드 — access entries

CAPA를 쓰지 않으므로 IAMAuthenticator(aws-auth) 강제가 사라집니다. AWS는 access entries를 권장 방법으로 명시하고 aws-auth는 deprecated로 표기합니다. 신규 클러스터는 **authentication_mode = API_AND_CONFIG_MAP**로 만들고 주체를 access entry로 등록합니다.

대상리소스type비고
클러스터 인증 모드authentication_mode = "API_AND_CONFIG_MAP"access entry + aws-auth 병행
karpenter 노드 롤aws_eks_access_entryEC2_LINUX노드 join 자동 권한. kubernetes_groups·정책 연결 불가
CI/admin 롤aws_eks_access_entry + policy assocSTANDARDAmazonEKSClusterAdminPolicy 등(하단 참고)
개발자 조회aws_eks_access_entry(STANDARD) + policy assocSTANDARDAmazonEKSViewPolicy, namespace scope 가능

CI/admin 롤의 AmazonEKSClusterAdminPolicy 등 access policy는 cross-account ARN을 쓸 경우 STANDARD 타입만 허용합니다.

Fargate pod-exec role은 별도 조치가 필요 없습니다 — Fargate profile 롤은 access entry가 자동 생성되므로 karpenter 노드 롤(EC2_LINUX)만 명시 작성하면 됩니다. bootstrapClusterCreatorAdminPermissions는 기본 true입니다. 감사 측면에서는 false로 두고 생성 principal을 access entry로 별도 등록하는 편이 낫습니다.

10. OIDC 이중등록과 IRSA 재바인딩

신규 blue 클러스터는 신규 OIDC issuer URL + provider ARN을 갖습니다. 여기가 이 프로젝트에서 가장 파급이 큰 함정입니다.

기존 IRSA 롤은 data.aws_eks_cluster[name].identity[0].oidc.issuer로 동적 바인딩돼 있어 클러스터 이름이 같으면 apply만으로 갱신됩니다. OIDC provider lookup은 항상 management 계정에서 수행됩니다(실사용 IRSA 스택 데이터 소스에 명시). CAPA가 수행하던 associateOIDCProvider워크로드 계정에만 provider를 등록해왔습니다. 신규 blue 클러스터는 워크로드 계정 + management 계정 양쪽에 aws_iam_openid_connect_provider를 등록해야 external-secrets 포함 IRSA 전체가 붙습니다. 이름이 다른 신규 클러스터(green→blue)라면 클러스터 registry에 신규 이름을 추가해야 재바인딩이 트리거됩니다.

재바인딩 대상:

  • Terraform 관리(동적, apply만으로): 워크로드·management 양쪽의 시크릿 관리용 IRSA 롤 — registry에 신규 클러스터명만 추가하면 자동으로 붙습니다.
  • Terraform 레포 밖(외부 관리, 별도 재발급 경로 확인): karpenter 컨트롤러 IRSA, ALB controller IRSA, argo-rollouts IRSA, fluentbit·datadog·cloudwatch-agent IRSA, 그리고 ebs-csi IRSA(스펙에 SA-Role이 없어 신규 OIDC로 wiring됐는지부터 확인). ebs-csi IRSA는 이 프로젝트의 최대 리스크입니다 — 롤 자체는 이 페이지에서 새로 만들되 addon 연결·PVC 검증은 03 managed addon에서 확인합니다.
  • ArgoCD: 신규 blue API endpoint로 클러스터 등록 secret을 새로 발급합니다(정적 SA bearerToken). tier-1 허브 push 앱은 하드코딩 endpoint 교체가 선행돼야 합니다 → 04 부트스트랩.

11. amiType·IMDS

amiType — AL2_ARM_64에서 AL2023_ARM_64_STANDARD로(필수, blocking). EKS는 AL2 AMI 발행을 중단했고 1.32가 AL2 AMI의 마지막 버전이라 1.33+ 신규 관리형 노드그룹에는 AL2 amiType을 아예 선택할 수 없습니다. karpenter EC2NodeClass는 이미 AL2023 amiFamily라 마이너별 AMI 핀만 목표 버전용으로 갱신합니다. 라이브 노드는 이미 AL2023으로 교체가 끝나 OS 리스크는 낮고 스펙-라이브 정합 문제로만 남습니다.

IMDS hop limit = 2(필수). AL2023 신규 노드는 hop limit이 1이면 IRSA 토큰 취득이 실패해 vpc-cni·ebs-csi가 함께 깨집니다. 신규 노드그룹/런치템플릿 생성 시 반드시 2로 설정합니다.

워크로드 API endpoint가 ArgoCD app-of-apps 레포에 다수 하드코딩돼 있어 클러스터를 세울 때마다 재바인딩해야 합니다. 파일별 분포·전체 목록·교체 절차는 04 부트스트랩이 다룹니다.

12. Terraform 체크리스트

클러스터 코어

  • aws_iam_role(클러스터) + AmazonEKSClusterPolicy — CAPA 롤 대체
  • aws_eks_cluster — version 1.35, vpc_config(blue subnet + endpoint private-only), enabled_cluster_log_types=["audit"], 노드그룹/런치템플릿 제거
  • access_config { authentication_mode = "API_AND_CONFIG_MAP" }
  • (선택) encryption_config + aws_kms_key
  • aws_iam_openid_connect_provider ×2(워크로드 + management)

Fargate(coredns + karpenter 호스팅)

  • aws_iam_role(pod-exec) + AmazonEKSFargatePodExecutionRolePolicy — stage 프로토타입 재활용
  • aws_eks_fargate_profile — selector 2종, blue private subnet
  • prod Fargate 스택 신규 작성 + prod blue subnet 신규 확보(둘 다 현재 부재)

managed addon 4종 + SA-role

  • aws_eks_addon ×4 — addons 모듈 재활용, 버전 1.35, coredns/ebs-csi config 재전달
  • modules/irsaebs-csi-controller-sa + AmazonEBSCSIDriverPolicyV2, addon service_account_role_arn에 주입
  • kube-proxy configuration_values.mode 변수화(기본 iptables)

karpenter 인프라(전부 신규)

  • 컨트롤러 IRSA(v1 6정책, 클러스터명 스코핑)
  • 노드 IAM role + 4 managed policy + instance profile
  • interruption SQS + queue policy + EventBridge 규칙 ×5
  • subnet/SG karpenter.sh/discovery=<cluster> 태그
  • aws_eks_access_entry(type=EC2_LINUX) 노드 롤

인증/접근

  • aws_eks_access_entry(STANDARD) + policy association — CI/admin/개발자
  • 클러스터 registry에 신규 클러스터명 추가 → IRSA 재바인딩 트리거

SG/네트워크

  • vpc_config.security_group_ids 결정(전용 SG vs 기본)
  • security_groups 모듈 — ALB→cluster ingress 규칙
  • additionalControlPlaneIngressRules 재현(VPC간 CIDR)
  • ALB subnet 태그 kubernetes.io/role/elb·internal-elb

클러스터 밖(Terraform 아님 — 04 부트스트랩이 다룸)

  • ArgoCD cluster 등록(정적 SA 토큰), 하드코딩 endpoint 교체, CAPA ApplicationSet에서 finance 분리, green 클러스터 통제 삭제

우리 케이스에서는

Terraform으로 신규 blue 클러스터를 세우는 작업은 새로 만들기보다 CAPA가 암묵적으로 해오던 12가지를 명시적으로 재현하는 일에 가깝습니다. 클러스터 셸·addon 스키마·Fargate 프로필은 기존 자산을 재활용할 수 있지만 karpenter 인프라 전체는 레포에 전무해 처음부터 짜야 합니다. 가장 위험한 두 곳은 성격이 다릅니다 — OIDC 이중등록은 빠뜨리면 cross-account IRSA 전체가 에러 하나 없이 깨지는 blocking 이슈이고 ebs-csi IRSA 롤은 스펙에 필드가 없어 존재 자체를 놓치기 쉬운 최대 리스크입니다. 여기에 prod Fargate 스택·prod blue subnet이 아직 없다는 사실까지 더하면 prod 이관은 stage 검증 후에도 별도 신규 작성이 남습니다.

마지막 수정 일자