GKE의 Agent Substrate를 위한 인프라 설계

Google Kubernetes Engine(GKE)을 사용하면 GKE의 Agent Substrate GKE 클러스터를 확장하여 유휴 컴퓨팅 비용을 최소화하면서 동시 실행률이 높은 AI 에이전트 워크로드를 지원할 수 있습니다. 전용 시스템 인프라 노드 풀을 커스텀 ComputeClass 및 용량 버퍼와 결합하면 중요한 시스템 구성요소를 격리하고, Compute Engine 머신 시리즈 전반에서 하드웨어 대체를 자동화하며, 대기 워커 용량을 상시 가동 상태로 유지할 수 있습니다.

이 문서를 읽고 GKE 클러스터 구성요소의 크기를 적절하게 조정하고, 시스템 인프라와 데이터베이스 노드 풀을 격리하고, WorkerPool 리소스에 대한 자동 노드 프로비저닝을 구성하고, 클러스터 유지보수 및 업그레이드를 계획하세요. 이 문서는 GKE 인프라에서 Agent Substrate를 프로비저닝하고 관리하는 플랫폼 관리자를 대상으로 합니다.

시작하기 전에

확장을 위해 클러스터 인프라를 구성하기 전에 환경이 다음 요구사항을 충족하는지 확인합니다.

  • GKE 클러스터 모드 및 버전: 컨트롤 플레인과 노드 풀 모두 버전 1.37 이상을 실행하는 GKE Standard 클러스터를 사용해야 합니다. GKE의 Agent Substrate에는 GKE Autopilot 클러스터가 지원되지 않습니다.
  • GKE의 Agent Substrate 설치: GKE에 기존 Agent Substrate가 설치되어 있거나 시스템 인프라 노드 격리가 사용 설정된 GKE에 Agent Substrate를 설치할 계획이 있어야 합니다. 설치 단계는 GKE에 Agent Substrate 설치를 참조하세요.

Agent Substrate 클러스터 크기 조정

평균이 아닌 최대 동시 실행 및 최대 재개 속도에 맞게 클러스터 크기를 조정합니다. 워커 노드는 동시에 실행되는 최대 액터 수를 보유해야 하며 시스템 인프라 구성요소와 스토리지 경로는 액터 재개 및 정지의 가장 빠른 속도를 따라잡아야 합니다.

워크로드 피크 추정

프로덕션 측정값이 없는 경우 총 등록된 Actor 수(total_actors), 동시에 실행되는 Actor의 평균 비율(average_active_fraction), 트래픽 버스트 배수(burst_factor), Actor가 차례당 활성 상태로 유지되는 평균 시간(average_seconds_active_per_resume)에서 최대 동시 실행 및 재개 속도를 추정합니다.

peak_running_actors = total_actors × average_active_fraction × burst_factor
peak_resume_rate    = peak_running_actors / average_seconds_active_per_resume

예를 들어 총 액터가 100,000개이고 평균 10% 가 활성 상태(액터 10,000개)이고 버스트 계수가 2인 경우 클러스터는 실행 중인 액터 20,000개를 지원해야 합니다. 각 액터가 정지되기 전에 평균 100초 동안 실행되는 경우 이 최고점을 유지하려면 초당 200회의 재개와 초당 200회의 정지가 필요합니다.

GKE의 Agent Substrate는 유휴 상태의 Actor를 자동으로 정지하지 않습니다. 애플리케이션 또는 조정자가 정지를 트리거해야 합니다.

데이터 영역 크기 조정

이 섹션에서는 워커 포드, GKE 노드, 스냅샷 대역폭, atelet 노드 에이전트를 포함하여 데이터 영역의 크기를 조정하는 권장사항을 설명합니다.

워커 포드 및 GKE 노드 계산

WorkerPool의 각 작업자 포드는 여러 액터를 호스팅합니다. 작업자는 ateworker 컨테이너의 --max-actors 플래그로 설정된 한도보다 적은 수의 액터를 호스팅하고 액터 템플릿 한도에 맞게 CPU 및 메모리 용량이 충분히 남아 있는 동안 새 액터를 수락할 수 있습니다(기본값 1000). 작업자 한도가 작업자 한도와 상호작용하는 방법에 대한 자세한 내용은 오픈소스 Agent Substrate API 가이드의 리소스 적정 크기 조정을 참조하세요.

사용 가능한 예약 용량이 20% 인 필요한 워커 포드 수(0.8 계수)를 계산합니다.

slots_per_worker = min(max_actors, worker_memory / actor_memory, worker_cpu / actor_cpu)
total_workers    = peak_running_actors / (slots_per_worker × 0.8)

이 수식에서 max_actors 변수는 기본적으로 1000(--max-actors 플래그로 구성됨)입니다. worker_memory 값에서 작업자가 자체 프로세스에 예약하는 메모리를 뺍니다. 마이크로 VM WorkerPool 리소스의 경우 배치가 작업자 용량에 대해 해당 오버헤드를 계산하므로 작업자가 보고한 액터당 가상 머신 모니터(VMM) 메모리 오버헤드를 actor_memory 값에 추가합니다.

노드당 하나의 워커 포드가 있는 경우 워커 수는 GKE 워커 노드 수와 같습니다. 노드의 할당 가능한 CPU 및 메모리를 워커 포드에 100% 할당하지 마세요. 각 노드에 atelet DaemonSet(ate-system 네임스페이스) 및 GKE 시스템 데몬을 위한 용량을 남겨두세요. GKE Standard는 클러스터당 최대 65,000개의 노드와 노드당 최대 512개의 포드를 지원합니다. 기본 최댓값은 노드당 110개의 포드(--max-pods-per-node 플래그로 구성 가능)이며 대규모 클러스터에는 추가 요구사항이 있습니다.

스냅샷 대역폭 및 노드 디스크 크기 조정

각 액터 정지는 /var/lib/ate 디렉터리 경로 아래의 로컬 노드 디스크에 스냅샷을 작성합니다. SYNCHRONOUS 모드에서 atelet 에이전트는 정지 작업이 반환되기 전에 스냅샷을 Cloud Storage에 업로드합니다. ASYNCHRONOUS 모드에서 atelet 에이전트는 스냅샷이 생성된 시점부터 약 --snapshot-upload-delay 플래그 값(기본값 5m)의 지연 후 Cloud Storage에 업로드를 예약합니다. 에이전트 기판은 --snapshot-detach-delay 플래그에 구성된 기간 동안 노드에 최신 스냅샷을 캐시합니다. 기본값은 30m입니다. 이 기간 내에 재개되는 액터는 동일한 노드에 예약되고 Cloud Storage에서 스냅샷을 다운로드하는 대신 로컬 디스크에서 복원됩니다.

압축되지 않은 스냅샷 크기(snapshot_size)를 ActorTemplate 메모리 한도에 쓰기 가능한 루트 파일 시스템 또는 영구 디렉터리에 기록된 데이터를 더한 값으로 추정합니다. 희소 파일 처리 및 zstd 압축은 Cloud Storage로 전송되는 압축된 스냅샷 크기(compressed_snapshot_size)를 줄입니다. 여기서 에이전트 기판은 행위자당 최대 2개의 스냅샷(이전 스냅샷과 진행 중인 스냅샷)을 저장합니다.

  • 최대 Cloud Storage 대역폭(각 방향): peak_resume_rate × compressed_snapshot_size
  • 노드당 최대 노드 디스크 쓰기 처리량: 2 × peak_resume_rate × snapshot_size / total_nodes (재개 다운로드와 정지 체크포인트 모두 노드 디스크에 기록됨)

GKE의 기본 100GiB hyperdisk-balanced 부팅 디스크는 3,600 IOPS 및 290MiB/s의 처리량(기본 성능은 디스크 크기에 따라 확장됨)을 제공하므로 과도한 게스트 I/O에서 스냅샷 작업을 제한할 수 있습니다. 워커 노드 풀을 만들 때 /var/lib/ate/snapshots 디렉터리 경로에 전용 디스크를 마운트하거나 gcloud container node-pools create 명령어와 함께 --boot-disk-provisioned-iops 및 --boot-disk-provisioned-throughput 플래그를 사용하여 부팅 디스크 성능을 높입니다.

보안 토큰 서비스 할당량 확인

Cloud Storage로 또는 Cloud Storage에서 스냅샷을 전송할 때마다 Actor로 범위가 지정된 토큰이 필요하며, ate-api-server 구성요소는 보안 토큰 서비스(STS) API에서 이 토큰을 요청합니다. ate-api-server 구성요소는 20~40분마다(일반적으로 해당 기간의 첫 번째 재개 시) Actor당 최대 1개의 STS 요청을 수행하고 만료 20분 전까지 토큰을 재사용합니다.

STS Exchange token global requests 할당량은 기본적으로 프로젝트당 분당 6,000개 요청이며 GKE용 워크로드 아이덴티티 제휴와 공유됩니다.

  • 필수 STS 할당량(분당 요청 수): 마지막 스냅샷 전송이 20분 이상 전에 이루어진 작업자의 재개 최대 속도의 최대 60배에 GKE용 워크로드 아이덴티티 제휴 용량을 더한 값으로 추정합니다. 이 비율을 모르는 경우 60 × peak_resume_rate 수식을 대체로 사용합니다. 예를 들어 초당 이력서 200개에는 분당 최대 12,000개의 요청이 필요합니다.
  • 할당량 상향 방법: Google Cloud 콘솔의 할당량 및 시스템 한도 페이지에서 할당량 상향을 요청합니다. 스냅샷 전송은 프로젝트에서 Security Token Service API를 사용 설정하지 않아도 작동하지만 할당량 및 시스템 한도 페이지에 할당량이 표시되도록 하려면 API를 사용 설정해야 합니다. 자세한 내용은 GKE용 워크로드 아이덴티티 제휴 문서의 보안 토큰 서비스의 Exchange Token API 할당량을 참조하세요.

atelet 노드 에이전트 조정

atelet DaemonSet는 워커 노드당 하나의 포드를 실행하여 액터를 복원하고 체크포인트를 만듭니다. 각 atelet 포드에서 objectstore-plugin 컨테이너는 스냅샷을 압축하고 Cloud Storage로 전송합니다.

다음 표에서는 atelet 및 objectstore-plugin 컨테이너의 주요 크기 조정 설정을 설명합니다.

설정 기본값 크기 조정 가이드
atelet 및 objectstore-plugin 컨테이너 CPU 및 메모리 요청: 50mCPU, 128MiB 메모리, 한도 없음 메모리 한도에 도달하면 노드 에이전트가 중지되고 노드의 모든 재개가 중지되므로 두 컨테이너에서 메모리 한도를 생략하여 메모리 한도 없이 버스트 가능 QoS를 구성합니다. 최대 재개 속도에서 전체 노드의 측정된 최대 사용량과 일치하도록 CPU 및 메모리 요청을 높여 작업자 포드가 atelet 에이전트에 필요한 리소스를 사용하지 않도록 합니다.
--upload-memory-budget 플래그(objectstore-plugin 컨테이너) 및 --snapshot-upload-workers 플래그(atelet 컨테이너) 512MiB 예산, 업로드 작업자 2명

정지율이 높은 멀티 액터 노드에서 동시 스냅샷 업로드가 큐에 추가되지 않도록 하려면 다음을 수행합니다.

  • --upload-memory-budget 플래그 값을 늘리고 objectstore-plugin 컨테이너 메모리 요청을 이 예산보다 높게 설정합니다.
  • --snapshot-upload-workers 플래그 값을 늘립니다.
--drain-timeout 플래그 및 terminationGracePeriodSeconds 필드 5분(--drain-timeout 플래그), 330초(terminationGracePeriodSeconds 필드) 노드 드레이닝 또는 업그레이드 중에 포드가 중지될 때 atelet 에이전트가 진행 중인 복원 및 스냅샷 업로드를 완료하는 시간을 제어합니다. 대규모 스냅샷의 --drain-timeout 플래그 값을 늘리는 경우 atelet DaemonSet에서 terminationGracePeriodSeconds 필드 값도 늘려 업로드가 완료되기 전에 kubelet 에이전트가 atelet 에이전트를 중지하지 않도록 합니다.

시스템 인프라 구성요소 및 데이터베이스 크기 조정

수평으로 확장되는 ate-system 네임스페이스의 스테이트리스(Stateless) 시스템 구성요소 배포의 경우 노드 중단을 허용하기 위해 사용 가능한 용량의 35%(0.65 계수)와 예비 복제본 1개(+ 1)를 더한 값으로 필요한 복제본 수를 추정합니다.

replicas = ceil(peak_load / (capacity_per_replica × 0.65)) + 1

공유 종속 항목(예: PostgreSQL CPU 또는 연결 한도)이 용량에 도달하면 수평 확장이 처리량 개선을 중지합니다. 시스템 인프라 구성요소와 데이터베이스의 크기를 함께 조정합니다. 구성요소 플래그에 대한 자세한 내용은 오픈소스 연산자 설치 가이드를 참조하세요.

다음 표에서는 각 시스템 인프라 구성요소의 리소스 및 확장 규칙을 설명합니다.

구성요소 QoS 및 리소스 규칙 확장 및 연결 조정
인그레스 라우터(atenet-router) 보장된 QoS 구성: Go 런타임이 스레드 수를 컨테이너 CPU 예산에 맞추도록 일치하는 CPU 및 메모리 요청과 한도를 설정합니다. 초당 최대 인그레스 요청, mTLS 오버헤드, 요청 페이로드 크기를 기준으로 복제본을 수평으로 확장합니다.
API 서버(ate-api-server) 보장된 QoS 구성: Go 런타임이 스레드 수를 컨테이너 CPU 예산에 맞추도록 일치하는 CPU 및 메모리 요청과 한도를 설정합니다. 초당 최대 재개 및 정지 주기(재개 및 정지 주기당 약 4ms의 CPU)와 인그레스 요청 조회 부하를 기준으로 복제본을 확장합니다. ateapi.postgres.poolMaxConns 설정을 명시적으로 설정합니다. 각 복제본은 최대 poolMaxConns + 6개의 데이터베이스 연결을 열고 모든 복제본의 합계는 PostgreSQL max_connections 설정보다 작아야 합니다.
데이터베이스(PostgreSQL) 보장된 메모리로 버스트 가능한 QoS 구성: 메모리 요청을 한도와 동일하게 설정하여 메모리에 shared_buffers 캐시를 잠그고 메모리 부족(OOM) 제거를 방지합니다. 커널 CPU 제한으로 인해 체크포인트 및 자동 비우기 버스트가 느려지지 않도록 전용 ate-postgres 노드에서 실행할 때 CPU 한도를 생략합니다. 이 단일 인스턴스 StatefulSet을 수직으로 확장합니다. 최대 부하에서 사용률이 80% 미만으로 유지되도록 충분한 CPU를 프로비저닝하고, Actor 테이블을 캐시할 수 있는 충분한 RAM(shared_buffers 매개변수를 메모리의 약 25% 로 설정)을 프로비저닝하고, 설치 시 ateapi.postgres.storageClass 설정으로 설정된 SSD 지원 StorageClass(예: C4 또는 N4의 dynamic-rwo StorageClass 또는 C3 또는 N2의 premium-rwo StorageClass)를 프로비저닝합니다. 모든 ate-api-server 복제본에 맞게 postgres-config ConfigMap(postgresql.conf 파일)의 max_connections 매개변수를 늘립니다.
이그레스 프록시(atenet-egress) 리소스 규칙: CPU 요청을 512mCPU(한도 8vCPU)로 설정하고 메모리 요청을 512MiB(한도 1GiB)로 설정합니다. 발신 Actor 트래픽의 지연 시간이 증가하면 요청 및 한도를 늘립니다. Actor 아웃바운드 요청 트래픽을 기반으로 복제본을 수평으로 확장합니다.
작업자 컨트롤러(ate-controller) 리소스 규칙: 복제본을 하나로 유지합니다(리더 선택 없음). 대규모 WorkerPool 수평 확장 이벤트 중 최대 사용량을 기준으로 CPU 및 메모리 요청을 설정합니다. 대규모 Fleet에서 새 작업자 포드를 등록하는 데 너무 오래 걸리는 경우 --worker-sync-concurrency 플래그 값을 늘립니다(기본값 2).
인증서 컨트롤러(podcertificate-controller) 리소스 규칙: podcertificate-controller-system 네임스페이스에서 실행되어 새 작업자 포드가 액터를 수락하기 전에 mTLS 인증서에 서명합니다. 수천 명의 작업자 Fleet의 경우 podcert.workersPerSigner 설정(기본값 0, 서명자당 1 작업자의 매니페스트 기본값 유지), --kube-api-qps 플래그(기본값 5), --kube-api-burst 플래그(기본값 10)의 값을 늘립니다.
ID 공급업체(ate-idp-server) 리소스 규칙: Actor JSON 웹 토큰(JWT)을 확인하기 위해 ate-system 네임스페이스에서 OpenID Connect(OIDC) 탐색 문서 및 JSON 웹 키 세트(JWKS)를 제공합니다. 최대 JWKS 쿼리 볼륨을 기준으로 CPU 및 메모리 요청을 설정합니다. 신뢰 당사자가 키를 캐시하지 않고 높은 요청 비율로 JWKS 엔드포인트를 쿼리하는 경우 복제본을 수평으로 확장합니다.
사용자 인증 정보 제공업체(k8s-credential-provider) 리소스 규칙: Kubernetes 보안 비밀 사용자 인증 정보 삽입이 사용 설정된 경우 ate-system 네임스페이스에서 실행됩니다. 발신 사용자 인증 정보 삽입 볼륨을 기준으로 CPU 및 메모리 요청을 설정합니다. atenet-egress 프록시에서 Kubernetes 보안 비밀 사용자 인증 정보 삽입이 필요한 아웃바운드 Actor 요청 비율에 따라 복제본을 수평으로 확장합니다.

시스템 인프라 및 워커 노드 풀 격리

프로덕션 클러스터에서 워커 노드의 높은 이탈률 Actor 예약 및 스냅샷 트래픽은 CPU, 메모리, 디스크 I/O를 두고 시스템 인프라 구성요소와 경쟁할 수 있습니다. GKE 클러스터를 세 가지 노드 풀 등급으로 분리합니다.

  • 데이터베이스 노드 풀(ate-postgres 라벨): 모든 액터 및 작업자 메타데이터를 저장하는 PostgreSQL StatefulSet의 전용 노드 풀입니다.
  • 시스템 인프라 노드 풀(ate-system-infra 라벨): 나머지 시스템 인프라 서비스(atenet-router, ate-api-server, atenet-egress, ate-controller, ate-idp-server, k8s-credential-provider 구성요소)를 위한 전용 노드 풀입니다.
  • 워커 노드 풀(WorkerPool): 활성 Actor 샌드박스를 호스팅하기 위해 GKE 커스텀 ComputeClass 및 GKE 용량 버퍼에서 관리하는 동적으로 확장되는 노드 풀입니다.

cordonSystemInfraComponents 설정(또는 --cordon-system-infra-components 플래그)을 사용하여 GKE에 Agent Substrate를 설치할 때 데이터베이스 및 시스템 인프라 구성요소를 전용 노드로 격리할 수 있습니다. 설치하기 전에 필수 라벨과 NoSchedule taint를 사용하여 두 노드 풀을 모두 만들어야 합니다.

# 1. Create the dedicated PostgreSQL node pool
gcloud container node-pools create ate-postgres-pool \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
    --node-locations=POSTGRES_ZONE \
    --machine-type=POSTGRES_MACHINE_TYPE \
    --num-nodes=1 \
    --node-labels=ate.dev/workloadType=ate-postgres \
    --node-taints=ate.dev/workloadType=ate-postgres:NoSchedule

# 2. Create the dedicated system infrastructure node pool
gcloud container node-pools create ate-system-infra-pool \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
    --machine-type=SYSTEM_INFRA_MACHINE_TYPE \
    --num-nodes=2 \
    --node-labels=ate.dev/workloadType=ate-system-infra \
    --node-taints=ate.dev/workloadType=ate-system-infra:NoSchedule

다음을 바꿉니다.

  • CLUSTER_NAME: GKE Standard 클러스터의 이름입니다.
  • LOCATION: 클러스터 컨트롤 플레인의 Compute Engine 영역 또는 리전입니다.
  • POSTGRES_ZONE: 단일 복제본 PostgreSQL StatefulSet의 단일 Compute Engine 영역입니다. 리전 클러스터의 경우 클러스터 리전 내에서 하나의 영역을 지정하여 노드 풀이 StatefulSet의 영구 디스크가 생성될 영역에 단일 노드를 프로비저닝하도록 합니다. 영역 클러스터의 경우 클러스터의 영역을 지정합니다.
  • POSTGRES_MACHINE_TYPE: PostgreSQL 인스턴스에 맞게 크기가 조정된 Compute Engine 머신 유형입니다.
  • SYSTEM_INFRA_MACHINE_TYPE: 시스템 인프라 구성요소에 맞게 크기가 조정된 Compute Engine 머신 유형입니다(예: c3-standard-8 머신 유형).

리전 클러스터에서 --num-nodes 플래그는 영역별로 적용됩니다(예: 3개 영역에 --num-nodes=2 플래그를 설정하면 총 6개의 노드가 생성됨). ate-system-infra-pool 노드 풀을 특정 영역에 배치하려면 --node-locations 플래그를 추가합니다.

설치 중에 cordonSystemInfraComponents 설정을 사용 설정하고 노드 풀이 누락된 경우 해당 시스템 포드는 Pending 상태로 유지됩니다.

커스텀 ComputeClass를 사용하여 하드웨어 타겟팅 자동화

GKE 커스텀 ComputeClasses를 사용하면 WorkerPool 노드의 Compute Engine 머신 시리즈에 우선순위가 지정된 목록을 정의하고 영역에서 리소스를 사용할 수 없는 경우 자동으로 보조 머신 시리즈로 대체할 수 있습니다.

런타임별 Compute Engine 머신 시리즈 선택

각 샌드박스 런타임에 별도의 ComputeClass를 구성합니다.

  • MicroVM 런타임(Cloud Hypervisor): ComputeClass 우선순위에서 enableNestedVirtualization: true 필드를 설정하고 중첩 가상화를 지원하는 x86 Compute Engine 머신 시리즈(예: N4, C3, C4, N2)를 타겟팅하거나 KVM을 기본적으로 실행하고 enableNestedVirtualization 필드가 필요하지 않은 x86 베어메탈 머신 유형을 사용합니다. 중첩된 가상화 제한사항에 나열된 Arm 기반 VM 및 머신 시리즈는 지원되지 않습니다.
  • gVisor 런타임: 중첩 가상화가 사용 설정되지 않은 범용 또는 컴퓨팅 최적화 x86 Compute Engine 머신 시리즈(예: N4, C3, C4, N2)를 타겟팅합니다. 혼합 CPU 마이크로아키텍처(예: E2) 및 Arm 기반 VM에서 실행되는 머신 시리즈는 GKE의 에이전트 서브스트레이트에서 지원되지 않습니다. ActorTemplate에서 선택하는 모든 WorkerPool 리소스는 동일한 CPU 아키텍처를 공유해야 합니다.

자세한 비교는 샌드박스 런타임 선택을 참조하세요.

에이전트 Substrate에 필요한 ComputeClass 규칙

GKE 워커 노드에서 Agent Substrate용 ComputeClass를 만들 때는 다음 규칙을 따르세요.

  • 노드 기반 ComputeClass 사용: 중첩 가상화를 지원하지 않는 포드 기반 결제(podFamily 필드)를 사용하지 않습니다.
  • nodePoolConfig.sandbox.type: microvm 필드를 설정하지 마세요. 이 설정은 포드 기반 워크로드에서 GKE Sandbox의 Kata 런타임을 사용 설정하고 GKE 워커의 에이전트 기판이 예약되지 않도록 하는 sandbox.gke.io/runtime=microvm taint를 적용합니다. GKE의 Agent Substrate는 자체 마이크로VM 런타임을 관리하며 표준 Container-Optimized OS(cos_containerd 이미지 유형) 노드에서 Compute Engine 중첩 가상화만 필요합니다.
  • 높은 샌드박스 밀도를 위한 Linux 커널 sysctl 설정 구성: 워커 노드가 약 800개 이상의 동시 샌드박스를 실행하는 경우 파일 시스템 모니터링(fs.inotify.* 매개변수) 및 주소 결정 프로토콜(ARP) 인접 테이블(net.ipv4.neigh.default.gc_thresh* 매개변수)에 대한 Linux 커널 한도를 늘려야 합니다. 설치 프로그램은 생성하는 클러스터에만 이러한 설정을 적용합니다. priorityDefaults.nodeSystemConfig.linuxNodeConfig.sysctls 필드를 사용하여 커스텀 ComputeClass를 구성하거나 --system-config-from-file 플래그를 사용하여 워커 노드 풀을 미리 만들 때 다음 sysctl 값을 직접 적용합니다.

    • fs.inotify.max_user_instances: 65536
    • fs.inotify.max_user_watches: 1048576
    • net.ipv4.neigh.default.gc_thresh1: 4096
    • net.ipv4.neigh.default.gc_thresh2: 16384
    • net.ipv4.neigh.default.gc_thresh3: 32768

    노드 sysctl 매개변수 구성에 대한 자세한 내용은 Sysctl 구성 옵션을 참조하세요.

마이크로 VM WorkerPool 리소스의 확장 패턴 선택

마이크로 VM 워커 포드는 ate.dev/kvm: 1 확장 리소스를 요청합니다. 이 리소스는 노드가 부팅되고 atelet 에이전트가 시작된 후에만 atelet 기기 플러그인에 의해 공지됩니다. GKE 노드 자동 프로비저닝은 프로비저닝되지 않은 노드 템플릿에서 ate.dev/kvm 확장 리소스를 볼 수 없으므로 대기 중인 microVM 워커 포드는 GKE가 복제본 0개에서 새 노드 풀을 자동으로 생성하도록 트리거할 수 없습니다. 하지만 노드 풀에 이미 실행 중인 노드가 하나 이상 있는 경우 GKE는 해당 노드 풀을 확장할 수 있습니다.

다음 표에서는 GKE에서 마이크로VM WorkerPool 리소스를 확장하는 데 지원되는 패턴을 비교합니다.

패턴 작동 방식 0개 노드로 확장되나요? 리소스 비가용성에 대한 다중 우선순위 대체? 가장 효과적인 경우
minimumCapacity 필드가 있는 크리에이터 풀 명시적 machineType 우선순위로 nodePoolAutoCreation.enabled: true 및 minimumCapacity.targetNodeCount: 1 필드를 설정합니다. 아니요(웜 노드 1개 실행 유지) 클래스 수준 minimumCapacity 필드의 초기 프로비저닝 시에만 해당합니다. 버스트 중간 대체에는 spec.priorities[] 필드의 각 대체 항목에 minimumCapacity.targetNodeCount: 1 필드를 설정해야 합니다(우선순위당 웜 노드 1개 유지). 자동화된 노드 풀 생성을 원하고 항상 하나 이상의 워커 노드를 실행 상태로 유지하려고 합니다.
용량 버퍼가 있는 자동 생성 풀 nodePoolAutoCreation.enabled: true 필드를 PodTemplate이 ate.dev/kvm 확장 리소스를 생략하는 활성 또는 대기 CapacityBuffer와 결합합니다. 대기 상태로 정지(예: 기본 100GiB 부팅 디스크가 있는 c3-standard-4 노드에서 실행 중인 컴퓨팅 비용의 약 8%) 예(버퍼 자리표시자는 우선순위 전반에서 노드 자동 프로비저닝 대체 트리거) 낮은 유휴 비용으로 빠른 버스트 확장(활성 상태 1~4초, 대기 노드 재개 20~35초, 새 작업자 준비까지 50~85초)을 원합니다.
노드 템플릿 라벨이 있는 사전 생성된 0 노드 풀 clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 라벨을 사용하여 자동 확장된 0 노드 풀을 미리 만들고 ComputeClass의 spec.priorities[].nodepools 필드에서 참조합니다. 예(실제 0개 노드, 유휴 컴퓨팅 비용 없음) 예, 사전 생성된 노드 풀 전체에서 대기 용량 버퍼를 유지하지 않고 진정한 Scale-to-zero를 원하는 경우

예시: minimumCapacity 필드가 있는 ComputeClass

minimumCapacity 필드를 사용하는 경우 spec.priorities 필드의 모든 항목은 machineFamily 필드만 지정하는 대신 명시적인 machineType 필드를 지정해야 합니다.

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
  name: substrate-microvm
spec:
  priorityDefaults:
    enableNestedVirtualization: true
    nodeSystemConfig:
      linuxNodeConfig:
        sysctls:
          fs.inotify.max_user_instances: 65536
          fs.inotify.max_user_watches: 1048576
          net.ipv4.neigh.default.gc_thresh1: 4096
          net.ipv4.neigh.default.gc_thresh2: 16384
          net.ipv4.neigh.default.gc_thresh3: 32768
  priorities:
  - machineType: n4-standard-4
  - machineType: c3-standard-4
  - machineType: n2-standard-4
  nodePoolAutoCreation:
    enabled: true
  minimumCapacity:
    targetNodeCount: 1
  nodePoolConfig:
    imageType: cos_containerd
  whenUnsatisfiable: DoNotScaleUp

이 ComputeClass에 WorkerPool을 타겟팅하려면 WorkerPool 포드 템플릿에 nodeSelector: {cloud.google.com/compute-class: substrate-microvm} 필드를 추가합니다.

ComputeClass가 여러 x86 머신 시리즈(예: N4에서 C3 또는 N2로)에서 대체되는 경우 메모리 충실도(SNAPSHOT_FIDELITY_MEMORY 모드)로 영구 스냅샷을 복원하려면 CPU 기능이 스냅샷의 CPU 기능의 상위 집합인 작업자가 필요합니다. 호환되는 작업자에 용량이 없으면 에이전트 기판은 복원을 루트 파일 시스템 충실도(SNAPSHOT_FIDELITY_ROOTFS 모드)로 다운그레이드합니다. 이 모드는 액터의 프로세스를 다시 시작하는 동안 루트 파일 시스템과 영구 볼륨 데이터를 보존합니다.

예시: 사전 생성된 0 노드 풀을 사용하여 0에서 확장

  1. 고밀도 Linux 커널 sysctl 설정을 system-config.yaml 파일로 저장합니다.

    linuxConfig:
      sysctl:
        fs.inotify.max_user_instances: '65536'
        fs.inotify.max_user_watches: '1048576'
        net.ipv4.neigh.default.gc_thresh1: '4096'
        net.ipv4.neigh.default.gc_thresh2: '16384'
        net.ipv4.neigh.default.gc_thresh3: '32768'
    
  2. GKE 클러스터 자동 확장 처리가 빈 풀에서 ate.dev/kvm 확장 리소스를 제공한다는 것을 알 수 있도록 --system-config-from-file=system-config.yaml 플래그와 clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 라벨을 사용하여 노드 0개에서 기본 및 대체 중첩 가상화 노드 풀을 미리 만듭니다.

    # Primary N4 pool (0 nodes)
    gcloud container node-pools create microvm-n4-pool \
        --cluster=CLUSTER_NAME \
        --location=LOCATION \
        --machine-type=n4-standard-4 \
        --enable-nested-virtualization \
        --system-config-from-file=system-config.yaml \
        --num-nodes=0 \
        --enable-autoscaling --total-min-nodes=0 --total-max-nodes=10 \
        --node-labels=cloud.google.com/compute-class=substrate-microvm-zero,clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 \
        --node-taints=cloud.google.com/compute-class=substrate-microvm-zero:NoSchedule
    
    # Fallback C3 pool (0 nodes)
    gcloud container node-pools create microvm-c3-pool \
        --cluster=CLUSTER_NAME \
        --location=LOCATION \
        --machine-type=c3-standard-4 \
        --enable-nested-virtualization \
        --system-config-from-file=system-config.yaml \
        --num-nodes=0 \
        --enable-autoscaling --total-min-nodes=0 --total-max-nodes=10 \
        --node-labels=cloud.google.com/compute-class=substrate-microvm-zero,clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 \
        --node-taints=cloud.google.com/compute-class=substrate-microvm-zero:NoSchedule
    

    다음을 바꿉니다.

    • CLUSTER_NAME: GKE Standard 클러스터의 이름입니다.
    • LOCATION: 클러스터의 Compute Engine 영역 또는 리전입니다. --total-min-nodes 및 --total-max-nodes 플래그를 사용하면 영역별이 아닌 전체 노드 풀에서 자동 확장 경계를 설정합니다.
  3. ComputeClass에서 사전 생성된 풀을 우선순위 순서로 참조합니다.

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: substrate-microvm-zero
    spec:
      nodePoolAutoCreation:
        enabled: false
      priorities:
      - nodepools:
        - microvm-n4-pool
      - nodepools:
        - microvm-c3-pool
      whenUnsatisfiable: DoNotScaleUp
    

    priorityDefaults 필드는 nodepools 필드를 사용하는 우선순위에 적용되지 않습니다. 노드 설정이 사전 생성된 노드 풀에서 가져오기 때문입니다. 자동 생성된 대체 우선순위와 마찬가지로 CPU 기능이 스냅샷 CPU 기능의 상위 집합이 아닌 대체 머신 시리즈에서 액터를 재개하면 복원이 SNAPSHOT_FIDELITY_ROOTFS 모드로 다운그레이드되고 액터의 프로세스가 다시 시작됩니다.

ComputeClass 구성에 관한 자세한 내용은 커스텀 ComputeClass로 자동 확장 노드 속성 제어를 참조하세요.

WorkerPool 버스트 확장을 위한 용량 버퍼 구성

액터 트래픽 급증이 실행 중인 WorkerPool 포드의 용량을 초과하면 새 작업자 포드는 액터를 제공하기 전에 Compute Engine 노드 프로비저닝, atelet 에이전트 초기화, 샌드박스 애셋 사전 준비를 기다려야 합니다. GKE 용량 버퍼는 노드 프로비저닝과 atelet 애셋 미리 준비를 중요한 경로에서 제외합니다.

  • 활성 용량 버퍼(buffer.x-k8s.io/active-capacity 전략): 사전 프로비저닝된 노드를 실행 및 준비 상태로 유지하여 Compute Engine VM의 전체 실행 비용으로 1~4초 내에 새 워커 포드를 예약합니다.
  • 대기 용량 버퍼(buffer.gke.io/standby-capacity 전략): GKE가 Compute Engine VM을 정지하기 전 대기 초기화 기간 동안 노드를 프로비저닝하고 atelet 에이전트가 디스크에서 샌드박스 애셋(runsc 바이너리 또는 Cloud Hypervisor 및 Kata 이미지)을 초기화하고 예열하도록 합니다. 이 기간은 기본적으로 5분(5m)이며 CapacityBuffer의 buffer.gke.io/standby-capacity-init-time 주석으로 구성됩니다. 애셋 사전 준비에 5분 이상 걸리는 경우 이 주석의 값을 늘립니다. 버스트가 발생하면 GKE는 약 20~35초 내에 정지된 노드를 재개하고 엔드 투 엔드 WorkerPool 준비(Worker 포드 예약, 포드 인증서 발급, ate-api-server 구성요소에 용량 등록)는 약 50~85초 내에 완료됩니다. 일시정지된 동안에는 일시정지된 VM 메모리 및 부팅 디스크 스토리지에 대한 비용만 지불합니다. 예를 들어 정지된 스토리지는 기본 100GiB hyperdisk-balanced 부팅 디스크가 있는 c3-standard-4 노드에서 실행 중인 컴퓨팅 비용의 약 8% 를 차지합니다. 정확한 비율은 머신 형태, 부팅 디스크 크기, 프로비저닝된 IOPS 또는 처리량에 따라 다릅니다.

버퍼 전략에 관한 자세한 내용은 시작 지연 시간을 줄이기 위한 전략을 참고하세요.

용량 버퍼의 제한사항 및 규칙

GKE에서 Agent Substrate의 용량 버퍼를 구성할 때는 다음 규칙을 적용합니다.

  • 대기 버퍼에 대한 Compute Engine 머신 형태 제한사항: Compute Engine 인스턴스 정지는 로컬 SSD가 연결된 VM 또는 메모리가 208GB를 초과하는 머신 형태(예: c3-highmem-88 머신 유형 또는 베어메탈 형태)에서 지원되지 않습니다. 대형 워커 노드 형태 또는 로컬 SSD가 있는 노드의 경우 대기 버퍼 대신 활성 용량 버퍼를 사용합니다.
  • scalableRef 필드가 복제본이 0개인 WorkerPool 또는 마이크로 VM 배포를 가리키지 않도록 합니다.
    • 풀이 복제본 0개로 확장되면 GKE CapacityBuffer 컨트롤러가 커스텀 리소스(kind: WorkerPool)를 확인할 수 없습니다.
    • microVM WorkerPool 리소스의 경우 배포 포드 템플릿에 ate.dev/kvm: 1 확장 리소스가 포함되어 있으므로 scalableRef 필드가 기본 배포를 가리키지 않도록 합니다. 이로 인해 노드 자동 프로비저닝이 빈 풀을 수평 확장하지 못합니다. 대신 ate.dev/kvm 확장 리소스를 요청하지 않고 ComputeClass를 선택하는 PodTemplate(podTemplateRef 필드)을 참조하여 버퍼를 구성합니다.
    • gVisor WorkerPool 리소스(ate.dev/kvm 확장 리소스를 요청하지 않음)의 경우 scalableRef 필드를 WorkerPool 기본 배포로 직접 가리키거나 PodTemplate을 사용할 수 있습니다.

예시: PodTemplate을 사용하는 대기 CapacityBuffer

다음 매니페스트는 마이크로VM 또는 gVisor WorkerPool 리소스에 작동하는 PodTemplate 및 대기 CapacityBuffer를 정의합니다.

apiVersion: v1
kind: PodTemplate
metadata:
  name: substrate-worker-buffer-template
  namespace: WORKERPOOL_NAMESPACE
template:
  spec:
    nodeSelector:
      cloud.google.com/compute-class: COMPUTE_CLASS_NAME
    containers:
    - name: buffer-placeholder
      image: registry.k8s.io/pause:3.9
      resources:
        requests:
          cpu: "WORKER_CPU_REQUEST"
          memory: "WORKER_MEMORY_REQUEST"
---
apiVersion: autoscaling.x-k8s.io/v1beta1
kind: CapacityBuffer
metadata:
  name: substrate-standby-buffer
  namespace: WORKERPOOL_NAMESPACE
spec:
  podTemplateRef:
    name: substrate-worker-buffer-template
  replicas: BUFFER_REPLICAS
  provisioningStrategy: buffer.gke.io/standby-capacity

다음을 바꿉니다.

  • WORKERPOOL_NAMESPACE: WorkerPool의 Kubernetes 네임스페이스(예: my-workerpool)
  • COMPUTE_CLASS_NAME: WorkerPool에서 타겟팅하는 커스텀 ComputeClass의 이름입니다(예: substrate-microvm).
  • WORKER_CPU_REQUEST 및 WORKER_MEMORY_REQUEST: WorkerPool에 있는 단일 작업자 포드의 CPU 및 메모리 요청(예: 4-vCPU 노드의 2 CPU 및 4Gi 메모리)으로, atelet 에이전트 및 GKE 시스템 데몬에 대한 노드 용량을 남겨둡니다. 이러한 값을 하나의 워커 포드 요청과 일치시키면 각 버퍼 복제본이 단일 노드에 여러 버퍼 자리표시자를 압축하는 대신 하나의 대기 워커 노드를 프로비저닝할 수 있습니다.
  • BUFFER_REPLICAS: 사전 준비 상태로 유지할 대기 워커 노드 수입니다(예: 4 노드).

대기 용량 버퍼를 사용하는 경우 대체 atelet 포드가 일시중지된 대기 노드에서 예약된 상태를 유지할 수 있도록(예: DaemonSet 순차적 업데이트 중) atelet DaemonSet에 buffer.gke.io/standby-capacity-node-suspended taint(operator: "Exists" 필드 포함)에 대한 톨러레이션을 추가합니다. DaemonSet 구성 예시는 대기 버퍼에 이미지 미리 로드를 참조하세요.

여러 워크로드가 동일한 ComputeClass를 공유하는 경우 GKE가 다른 워크로드에서 요청하지 않는 전용 taint 노드를 프로비저닝하도록 일치하는 워크로드 분리 톨러레이션(toleration) 및 nodeSelector 라벨을 WorkerPool 포드 템플릿과 버퍼 PodTemplate 모두에 추가합니다. 또한 atelet 에이전트가 해당 전용 노드에서 예약할 수 있도록 일치하는 톨러레이션(toleration)을 atelet DaemonSet에 추가합니다. 단계별 안내는 용량 버퍼 구성을 참조하세요.

업그레이드 및 자동 확장 처리 상호작용 관리

이 섹션에서는 활성 Actor를 중단하지 않고 atelet DaemonSet 업데이트, 클러스터 자동 확장 처리 축소 이벤트, 노드 업그레이드를 관리하는 방법을 설명합니다.

대기 버퍼로 atelet DaemonSet 업데이트

정지된 대기 버퍼 노드는 정지된 동안 buffer.gke.io/standby-capacity-node-suspended taint 및 연결할 수 없는 taint를 전달하므로 정지된 노드의 kubelet 에이전트가 포드 삭제를 인식할 수 없습니다. atelet DaemonSet가 buffer.gke.io/standby-capacity-node-suspended taint를 허용하는지 확인합니다(operator: "Exists" 필드 사용). 이러한 허용이 있더라도 atelet DaemonSet의 표준 순차적 업데이트(maxUnavailable: 1 필드 사용) 중에 정지된 노드의 포드가 Terminating 상태로 전환되고 실행 중인 노드에서 업데이트가 진행되지 않도록 차단할 수 있습니다.

대기 노드가 정지된 클러스터에서 atelet DaemonSet를 업데이트하기 전에 다음 중 하나를 수행합니다.

  • 연결할 수 없는 대기 노드가 업데이트 예산을 소진하지 않도록 atelet DaemonSet의 spec.updateStrategy.rollingUpdate.maxUnavailable 필드를 정지된 대기 노드의 최대 개수보다 큰 값으로 설정합니다.
  • atelet DaemonSet를 업데이트하기 전에 대기 CapacityBuffer 복제본을 0으로 일시적으로 확장하고 클러스터 자동 확장 처리가 모든 정지된 대기 버퍼 노드를 삭제할 때까지 기다립니다(일반적으로 10~15분). 아직 Suspended 조건 상태가 True인 노드가 있는지 확인하려면 다음 명령어를 실행합니다.

    kubectl get nodes -o custom-columns='NAME:.metadata.name,SUSPENDED:.status.conditions[?(@.type=="Suspended")].status'
    

축소 및 업그레이드 중에 활성 액터 보호

활성 액터는 개별 Kubernetes 포드가 아닌 atelet 에이전트에서 관리하는 샌드박스 내에서 실행되므로 해당 노드의 워커 포드가 활성 액터를 호스팅하는 경우에도 노드의 CPU 및 메모리 요청이 GKE 클러스터 자동 확장 처리에 낮게 표시될 수 있습니다. 노드가 드레이닝되면 kubelet 에이전트가 워커 포드에 SIGTERM 신호를 전송하고 워커는 호스팅하는 모든 작업자의 각 컨테이너의 기본 프로세스에 SIGTERM 신호를 전달합니다. 그러면 각 활성 Actor는 Worker가 중지되기 전에 정지될 때까지 최대 30분이 주어집니다. 모든 스테이트풀(Stateful) Actor에 신호에서 종료되지 않고 DURABILITY_MODE_SYNCHRONOUS 모드로 SuspendActor 메서드를 호출하는 SIGTERM 핸들러를 제공합니다. 기본 프로세스가 SIGTERM 신호로 종료되는 액터는 저장되지 않은 상태를 즉시 잃게 됩니다. 활성 액터를 호스팅하는 동안 워커 포드가 중지되면 액터가 ACTOR_STATE_CRASHED 상태로 전환됩니다.

축소 이벤트 및 GKE 클러스터 업그레이드 중에 중단을 최소화하려면 다음 권장사항을 적용하세요.

  • 스팟 VM 선점은 노드를 중지하기 전에 15초에서 2분 사이의 종료 알림만 제공하므로 스테이트풀(Stateful) WorkerPool 노드에 스팟 VM을 사용하지 마세요.
  • 활성 작업자가 체크포인트되고 작업자 포드가 중지되기 전에 정지되도록 조정자에서 드레이닝을 조정하거나 클러스터 자동 확장 처리가 활성 작업자 포드를 제거하지 못하도록 합니다(예: cluster-autoscaler.kubernetes.io/safe-to-evict: "false" 포드 주석 사용). WorkerPool 포드 템플릿에서 safe-to-evict: "false" 주석을 정적으로 설정하면 클러스터 자동 확장 처리는 활성 작업자가 없는 경우에도 작업자 포드가 예약된 노드를 축소하지 않습니다. 유휴 노드를 해제하려면 WorkerPool 복제본을 축소하거나 주석을 동적으로 관리해야 합니다. 작업자 제거 수명 주기 및 RevertActor 메서드를 사용한 비정상 종료된 액터 복구에 대한 자세한 내용은 Agent Substrate API 가이드의 제거를 참조하세요.
  • 기존 워커 노드가 차단 및 드레이닝되기 전에 새 워커 노드가 프로비저닝되도록 GKE 일시 급증 업그레이드를 구성하고 리소스가 제한된 환경에서 업그레이드를 검토합니다.

다음 단계