운영, 워크로드, 보안 & 전략

Block 4: 배치, GPU, 관측성, 망분리 검토, 비용과 도입 판단

배치는 label 하나에서 시작한다

Hybrid 노드에는 eks.amazonaws.com/compute-type=hybrid label이 자동으로 붙습니다. 위치 label(example.com/location)은 노드 소유자가 직접 부여합니다.

nodeSelector: eks.amazonaws.com/compute-type: hybrid example.com/location: onprem tolerations: # hybrid taint를 쓰는 경우에만 필요 - key: eks.amazonaws.com/compute-type operator: Equal value: hybrid effect: NoSchedule
affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: # term끼리 OR, term 안은 AND - matchExpressions: - {key: eks.amazonaws.com/compute-type, operator: In, values: [hybrid]} - {key: example.com/location, operator: In, values: [onprem]} - matchExpressions: - {key: example.com/location, operator: In, values: [cloud]} - {key: karpenter.sh/nodepool, operator: In, values: [cloud-burst-pool]} preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 preference: matchExpressions: - {key: example.com/location, operator: In, values: [onprem]}

Hybrid taint는 선택 사항입니다. 자동으로 붙지 않으며, 추가 전에 CNI, DNS, GPU 인프라 Pod의 toleration부터 확인합니다.

kubectl taint node "$NODE_NAME" \ eks.amazonaws.com/compute-type=hybrid:NoSchedule

NoSchedule은 새 스케줄링에만 영향을 줍니다. label이나 required affinity를 바꿔도 이미 실행 중인 Pod는 자동으로 이동하지 않습니다.

topologySpreadConstraints: - maxSkew: 2 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app: hybrid-burst-app

ScheduleAnyway는 점수 선호이며 maxSkew를 넘을 수 있습니다. zone label은 실제 장애 도메인에만 부여하고, 모든 Hybrid 호스트를 AWS AZ로 표시하지 않습니다.

버스팅은 Pending Pod가 트리거

온프레미스 용량 부족
스케줄 불가 Pod
→
Pod = Pending
toleration 보유
→
Karpenter NodePool
requirements 매칭
→
EC2 노드 생성
cloud-burst-pool
→
Pod 스케줄
자동 복귀 없음
온프레미스 용량이 돌아와도 실행 중인 cloud Pod는 자동으로 돌아오지 않습니다.
포화 감지기가 아님
Karpenter는 조건에 맞는 Pending Pod에 반응합니다. 온프레미스 슬롯을 먼저 채우는 것도 보장하지 않습니다.
버전 요구
Kubernetes 1.36은 Karpenter 1.13 이상, 1.37은 1.15.x가 필요합니다.
막힐 수 있는 곳
AWS quota, 인스턴스 가용성, subnet IP, IAM, 노드 bootstrap, 워크로드 의존성.

스케일-인 순서는 선호일 뿐

1. 할당 상태
미할당 Pod가 할당된 Pod보다 먼저
2. Pod 단계
Pending, Unknown, Running 순서
3. Ready 여부
NotReady가 Ready보다 먼저
4. deletion cost
그 뒤에야 낮은 값이 먼저 제거
CREATE webhook은 비권장
CREATE 시점의 Pod에는 최종 노드(spec.nodeName)가 아직 없어 위치를 신뢰성 있게 알 수 없습니다.
대안: 스케줄 후 패치
바인딩 뒤 소유한 Pod 한 개에 annotation을 부여하고, UID, resourceVersion, nodeName을 test로 검사합니다.

GPU마다 할당 관리자는 하나

경로할당 방식
독립 NVIDIA device pluginnvidia.com/gpu 등 확장 리소스 게시
독립 DRA driverResourceSlice 게시, DeviceClass/ResourceClaim으로 할당
GPU Operator + ClusterPolicyOperator가 관리하는 device-plugin 방식
GPU Operator 26.7 + GPUCluster신규 설치용 Operator 관리 DRA, ClusterPolicy와 상호 배타적
DRA 권고
AWS는 신규 EKS 1.34 이상에 DRA를 권고합니다.
Auto Mode는 DRA 미지원
Auto Mode는 GPU device plugin을 자체 관리합니다.
확인한 버전
GPU Operator 26.7.0, DRA driver 0.5.0, device plugin 0.20.0
DRA 0.5.0 요구
K8s 1.34.2+, driver 565+, toolkit 1.18+, CDI. Operator 관리 DRA는 driver 580+

MIG는 격리, time-slicing은 공유

MIG는 GPU를 하드웨어 기반 compute, memory 인스턴스로 나눕니다. 아래는 A100 40 GB profile입니다.

Profile명목 메모리최대 인스턴스
1g.5gb5 GB7
2g.10gb10 GB3
3g.20gb20 GB2
4g.20gb20 GB1
7g.40gb40 GB1

4g.40gb는 A100 80 GB의 profile입니다. MIG 활성화, 재구성은 GPU 워크로드를 중단할 수 있는 유지보수 작업이며, Pod 요청만 nvidia.com/mig-1g.5gb로 바꿔도 인스턴스가 생기지 않습니다.

# device-plugin 설정 조각 (Kubernetes 리소스가 아님) version: v1 sharing: timeSlicing: renameByDefault: true failRequestsGreaterThanOne: true resources: - name: nvidia.com/gpu replicas: 4

renameByDefault: true이면 nvidia.com/gpu.shared로 게시됩니다. replica 4개는 독립 메모리 영역 4개가 아니며, replica 사이에 메모리, 장애 격리가 없습니다.

NVIDIA 사양H100 SXMH200 SXM
GPU 메모리80 GB HBM3141 GB HBM3e
메모리 대역폭3.35 TB/s4.8 TB/s
MIG최대 7개최대 7개

공급자 사양이며 이 환경의 실측값이 아닙니다. NVL/PCIe variant는 값이 다르므로 SXM 행을 모든 H100에 일반화하지 않습니다.

hybrid 지표는 relabel로 구분

apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: hybrid-node-exporter namespace: monitoring labels: release: kube-prom spec: # selector, namespaceSelector 생략 attachMetadata: node: true endpoints: - port: http-metrics relabelings: - sourceLabels: [__meta_kubernetes_node_label_eks_amazonaws_com_compute_type] regex: hybrid action: keep - targetLabel: compute_type replacement: hybrid
# GPU utilization (이미 percent) DCGM_FI_DEV_GPU_UTIL{compute_type="hybrid"} # GPU framebuffer 사용률: used / (used + free) 100 * DCGM_FI_DEV_FB_USED{compute_type="hybrid"} / (DCGM_FI_DEV_FB_USED{compute_type="hybrid"} + DCGM_FI_DEV_FB_FREE{compute_type="hybrid"})

node_cpu_seconds_total 등 호스트 지표는 kubelet이 아니라 Node Exporter가 제공합니다. DCGM exporter는 별도로 설치되어 있어야 합니다.

Hybrid에서는 cluster, workload, Pod, container 지표를 지원합니다. node-level 지표는 EC2 IMDS에 의존하는데 Hybrid 호스트에는 없어서 제공되지 않습니다. 호스트 CPU, 메모리는 Node Exporter와 Prometheus로 보완합니다.

Pod Identity 환경에서도 Hybrid 호환을 위해 RUN_WITH_IRSA 변수가 필요합니다. 기존 AmazonCloudWatchAgent의 spec.env 목록에 추가하고 기존 항목은 보존합니다.

# 기존 AmazonCloudWatchAgent.spec.env 목록에 항목 추가 - name: RUN_WITH_IRSA value: "True"

CoreDNS는 양쪽에 최소 1개

애드온이 설계의 배치
AWS Load Balancer Controllercloud node (webhook 접근, routable Hybrid IP target)
CloudWatch agent/operatoragent는 지원 노드, operator webhook은 cloud 권장
cert-managerwebhook cloud 권장, routable이면 Hybrid 가능
Metrics Servercloud 또는 도달 가능한 Hybrid Pod endpoint
Cilium/CalicoHybrid Node (cloud node는 VPC CNI 유지)

호환 기준이며 설치 target 버전이 아닙니다.

Add-onHybrid 호환 기준
Node monitoring agent1.2.0-eksbuild.1
External DNS0.19.0-eksbuild.1
FSx CSI1.7.0-eksbuild.1
Secrets Store provider2.1.1-eksbuild.1
Pod Identity Agent1.3.3-eksbuild.1 (Bottlerocket 1.3.7-eksbuild.2)
# CoreDNS Deployment.spec.template.spec 조각 nodeSelector: infrastructure.example.com/dns-eligible: "true" topologySpreadConstraints: - maxSkew: 1 minDomains: 2 topologyKey: example.com/location whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: k8s-app: kube-dns

적격 노드에 location 값 cloud 또는 onprem을 부여합니다. 한 도메인에 용량이 없으면 새 replica가 Pending일 수 있어 가용성 절충이며 failover 보장이 아닙니다.

외부 노출은 IP target과 BGP로

자체 관리형 AWS Load Balancer Controller는 도달 가능한 Hybrid Pod IP를 target으로 등록할 수 있습니다. ALB는 alb.ingress.kubernetes.io/target-type: ip, NLB는 service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip와 loadBalancerClass: service.k8s.aws/nlb를 사용합니다.

route, 반환 경로, security group/firewall, remote Pod network 구성이 맞아야 합니다. 컨트롤러는 cloud node에 두는 설계를 권장합니다.

nodeSelector: example.com/location: cloud
apiVersion: cilium.io/v2 kind: CiliumLoadBalancerIPPool metadata: name: on-prem-pool spec: blocks: - cidr: "10.90.0.0/24" serviceSelector: matchLabels: exposure: onprem-bgp

예시 CIDR은 인벤토리에서 예약한 비중복 대역으로 바꿉니다. IP 할당이 라우터 광고나 통신 성공을 보장하지는 않습니다.

apiVersion: cilium.io/v2 kind: CiliumBGPAdvertisement metadata: name: hybrid-service-advertisement labels: advertise: hybrid-services spec: advertisements: - advertisementType: Service service: addresses: [LoadBalancerIP] selector: matchLabels: exposure: onprem-bgp

CiliumBGPClusterConfig, CiliumBGPPeerConfig와 함께 구성합니다. 세션, 수락된 라우트, next hop, 반환 경로를 확인해야 완성입니다.

cilium.io/v2 BGP CRD는 Cilium 1.18 기준입니다. 1.17.x 클러스터는 Block 2 예제처럼 v2alpha1을 사용합니다.

Cilium Ingress와 Gateway API는 L7 proxy가 필요합니다. 그러나 Hybrid Nodes Gateway의 필수 설정은 vtep.enabled=true, l7Proxy=false이므로 같은 Cilium 설치에 함께 적용할 수 없습니다. 기능을 켜기 전에 네트워크 설계를 먼저 선택합니다.

Pod Identity는 6단계 체크

  • (Ubuntu, RHEL, AL2023) 호스트 NodeConfig에 credentials file 활성화
    spec: hybrid: enableCredentialsFile: true
  • 호스트마다 계획된 nodeadm init을 다시 실행 (한 호스트씩 검증)
  • Pod Identity Agent add-on에 Hybrid DaemonSet 활성화
    {"daemonsets": {"hybrid": {"create": true}}}
  • add-on 버전 확인: 일반 OS 1.3.3-eksbuild.1 이상. Bottlerocket은 add-on 1.3.7-eksbuild.2 + OS 1.39.0 이상이며, 1–3 대신 bootstrap 명령에 --enable-credentials-file=true, DaemonSet 키는 hybrid-bottlerocket
  • eks-auth 서비스 경로 + 노드 역할의 eks-auth:AssumeRoleForPodIdentity 권한
  • 워크로드별 Pod Identity association (namespace, ServiceAccount, IAM role 신뢰, 권한)

'endpoint'는 세 가지를 뜻한다

Kubernetes API private endpoint
kubelet, Pod, 운영자가 TCP 443으로 접근하는 사설 진입점. control plane의 온프레미스행 연결을 없애지 않습니다.
EKS control-plane ENI
API server와 VPC, remote node/Pod network 사이의 연결 지점. DLP나 망연계 장비가 아닙니다.
interface VPC endpoint (PrivateLink)
eks, ssm, rolesanywhere 등 AWS 서비스 API용. kubelet 연결의 중계 서비스가 아닙니다.
세션 A: 노드가 시작 kubelet → API (TCP 443)
세션 B: API server가 시작 API → kubelet (TCP 10250), 사용 시 webhook 포트도 온프레미스 inbound
private endpoint ≠ 망분리 준수 노드가 먼저 연결했다는 이유로 control plane발 연결이 사라지지 않습니다.

망분리는 요건별로 따진다

고객 요구이 설계의 판단
인터넷 비노출, 승인된 사설 관리 통신 허용검토 가능한 후보 (증명 필요)
물리 단절, 외부 CP와 실시간 연결 불가연결 전제와 충돌
클라우드발 신규 연결 전면 금지kubelet, webhook 흐름과 충돌
업무 영역별 관리 주체, 권한 독립공통 cluster 관리자 범위 심사, 필요 시 cluster 분리
K8s 객체, Secret, 로그까지 온프레미스에만AWS control plane 구성과 충돌 가능

Direct Connect는 기본적으로 전송 중 암호화를 제공하지 않습니다. Kubernetes API, kubelet의 TLS와 인증을 유지하고, 회선 구간 암호화가 필요하면 IPsec over DX 또는 MACsec 적용 범위를 검토합니다.

MACsec은 지원 DX 연결의 링크 보호이며 종단 간 TLS와 범위가 다릅니다. Hybrid Nodes Gateway(VXLAN)도 자체 암호화가 없습니다.

get nodes/proxy를 단순 조회 권한으로 분류하지 않습니다. kubelet API를 통한 컨테이너 명령 실행이 가능할 수 있고, Kubernetes audit, admission 경로를 우회할 수 있습니다.

pods/log, pods/exec, pods/attach, pods/portforward, nodes/proxy와 workload 생성 권한을 함께 검토합니다.

다음은 준비할 증거 목록이며 점검 결과가 아닙니다.

심사 질문증거
private-only가 실제 적용됐는가endpoint 설정, DNS 응답, DX 경로, 경계 flow 기록
AWS에서 어디까지 접근 가능한가ENI/subnet, remote CIDR, route, SG, firewall 대응표
누가 어떤 API 작업을 했는가EKS audit 로그, CloudTrail
무엇이 망을 통과했는가VPC Flow Logs, 방화벽 기록

규제 대응은 증거로 말한다

AWS에 있는 것
Kubernetes API 객체 (Pod 사양, ConfigMap, Secret) 와 control-plane metadata. 노드 임시 자격 증명 발급도 AWS 서비스를 거칩니다.
온프레미스에 있는 것
워크로드 실행과 Pod가 처리하는 대용량 업무 데이터. 자동으로 AWS에 복제되지 않습니다.
경계를 넘을 수 있는 것
앱이 출력한 logs, 허가된 exec/cp/port-forward, 애플리케이션 egress, SSM 관리 경로.
"충족" 대신 "검토 범위와 조건" node selector나 label만으로 데이터 주권, 규정 준수가 입증되지 않습니다. 업무 데이터, API 객체, 로그, 이미지, 자격 증명을 각각 분류해 저장 위치와 조회 권한을 기록합니다.

비용은 vCPU-hour 구간 과금

월 사용량 구간 (vCPU-hour)요금
처음 576,000$0.020
다음 576,000$0.014
다음 4,608,000$0.010
다음 5,760,000$0.008
11,520,000 초과$0.006
노드월 vCPU-h연환산 노드 요금+ 클러스터 1개
10233,600$56,064$56,940
501,168,000$236,928$237,804
1002,336,000$377,088$377,964

가정: 노드당 32 vCPU, 월 730시간, 같은 월을 12번 반복, 표준 지원 클러스터 1개($0.10/시간) 포함. 청구서나 실측이 아닌 계산 모델입니다.

경쟁 솔루션 비교는 의도적으로 싣지 않았습니다 출처를 확인하지 못한 과거 추정치는 폐기했습니다. 하드웨어, 전력, OS 구독, 인력, 이전 비용이 포함된 자체 TCO 모델로 비교하세요.

도입 판단은 제약 확인부터

Hybrid Nodes가 맞는 신호
온프레미스 GPU, 대규모 로컬 데이터, edge 처리, 기존 하드웨어 활용. AWS와 안정적인 사설 양방향 연결을 유지할 수 있는 경우.
먼저 확인할 제약
IPv4만 지원. 간헐적, 단절(DDIL) 환경용이 아님. 연결이 끊기면 노드는 Unknown이 되고, toleration 없는 Pod는 기본 300초 뒤 eviction. GovCloud(US)와 중국 리전 제외. OS, 아키텍처, CNI 조합 확인.
맞지 않는 경우
완전 단절이 필요하거나 클라우드발 신규 연결이 전면 금지된 정책. AWS Region, Local Zone, Outposts, 타사 클라우드를 hybrid 인프라로 쓰는 것은 미지원.
운영 책임
Control plane은 AWS가 관리하지만 host, OS, 연결, workload 운영은 계속 사용자 책임입니다.
대안과의 비교 동등한 가용성, 지원 범위로 자체 TCO 모델을 만들어 비교하세요. 이 자료는 특정 대안의 우열을 주장하지 않습니다.

핵심 요약: 4개 블록, 6가지

1. 구조와 전제
AWS가 control plane을, 사용자가 host, 연결, workload를 운영합니다. AWS와의 사설 양방향 연결이 필수입니다.
2. 네트워크
kubelet 10250과 webhook은 AWS에서 시작하는 inbound입니다. Gateway는 선택이며 직접 라우팅도 유효합니다.
3. 라이프사이클
nodeadm으로 설치, join, 업그레이드합니다. rollback 명령이 없으므로 업그레이드, 복구 모두 in-place보다 호스트 교체를 우선합니다.
4. 워크로드 배치
compute-type label로 배치하고, 버스팅은 Pending Pod가 트리거하며 자동 복귀는 없습니다.
5. GPU와 관측성
GPU마다 할당 관리자는 하나, 신규 1.34 이상은 DRA 권고. hybrid 지표는 relabel로 구분합니다.
6. 보안과 비용
private endpoint는 망분리 준수의 증거가 아닙니다. 비용은 보고된 vCPU-hour 구간 과금입니다.

Knowledge Check (1/2)

Q1: Karpenter 클라우드 버스팅의 트리거는 무엇인가요?
Q2: 하나의 물리 GPU에 대한 설명으로 맞는 것은?

Knowledge Check (2/2)

Q3: pod-deletion-cost에 대한 설명으로 맞는 것은?
Q4: "private endpoint를 쓰므로 망분리를 준수한다"는 주장은?

참고 자료 & Q&A

AWS 공식 문서
docs.aws.amazon.com/eks/latest/userguide/
hybrid-nodes-overview.html
hybrid-nodes-networking.html
hybrid-nodes-add-ons.html
hybrid-nodes-webhooks.html
hybrid-nodes-gateway-cni.html
GPU
docs.aws.amazon.com/eks/latest/userguide/
device-management-nvidia.html
NVIDIA GPU Operator 문서 (platform-support)
비용, 스케줄링
aws.amazon.com/eks/pricing/
karpenter.sh/docs/upgrading/compatibility/
kubernetes.io ReplicaSet pod-deletion-cost
Q&A 이 자료의 예제는 검토 기준(EKS 1.36, nodeadm 1.0.20)이며 대부분 실제 클러스터에서 실행한 결과가 아닙니다. 적용 전 최신 AWS 문서로 지원 조합을 확인하세요.

Thank You

운영, 워크로드, 보안 & 전략, 감사합니다

수고하셨습니다!

← 목차로 돌아가기