Amazon Sagemaker AI 실시간 엔드포인트 구성(인스턴스 유형, 인스턴스 수 또는 환경 변수 변경)을 업데이트하면 AWS CloudFormation 또는 AWS Cloud Development Kit(AWS CDK)를 통한 배포가 실패합니다. SageMaker AI는 엔드포인트를 업데이트하기 전에 확장 가능 대상(scalable target)의 등록을 해제할 것을 요구하지만, 등록을 해제하면 CloudFormation이 AWS Application Auto Scaling 리소스를 추적할 수 없게 됩니다.
이 게시물에서는 재사용 가능한 CDK 구성과 AWS CloudFormation 사용자 지정 리소스를 사용하여 엔드포인트 업데이트 중에 자동 확장 등록 해제 및 등록을 자동으로 조율하는 방법을 보여줍니다. 수동 개입 없이 단일 배포에서 엔드포인트 구성과 자동 확장 파라미터를 모두 업데이트할 수 있습니다.
이 문제가 발생하는 이유
네이티브 CloudFormation 자동 확장 리소스로 SageMaker AI 엔드포인트를 배포한 후, 엔드포인트 구성을 변경하고 재배포하면 여러 가지 실패 모드가 나타납니다. 구체적인 실패 양상은 무엇을 변경했는지, 그리고 이 문제를 어떻게 우회했는지에 따라 달라집니다.
자동 확장이 등록된 상태에서 엔드포인트 구성 변경
확장 가능 대상이 여전히 등록된 상태에서 CloudFormation이 엔드포인트 업데이트를 시도합니다. SageMaker AI는 다음 오류와 함께 업데이트를 거부합니다:
The variant(s) "[AllTraffic]" must be deregistered as scalable targets with Application Auto Scaling before they can be removed or have their instance type updated.
CloudFormation이 자동 확장 리소스에 도달하기 전에 SageMaker AI가 엔드포인트 업데이트를 차단합니다.
자동 확장 등록을 수동으로 해제한 후 엔드포인트 구성만 변경
AWS Command Line Interface(AWS CLI)를 통해 확장 가능 대상의 등록을 해제하고 엔드포인트 구성만 변경하여 재배포하면 배포는 성공합니다. 그러나 CloudFormation 템플릿에 자동 확장이 포함되어 있음에도 CloudFormation은 이를 등록하지 않습니다. CloudFormation 템플릿의 자동 확장 파라미터가 변경되지 않았기 때문에 CloudFormation은 확장 가능 대상을 등록하거나 확장 정책을 다시 적용하지 않습니다. 이로써 엔드포인트는 자동 확장 없이 실행 중이며, 문제가 발생했음을 나타내는 오류도 없습니다.
자동 확장 등록을 수동으로 해제한 후 자동 확장 파라미터 변경
AWS CLI를 통해 확장 가능 대상의 등록을 해제하고 자동 확장 파라미터 변경과 함께 재배포하면, CloudFormation은 더 이상 존재하지 않는 ScalableTarget 리소스의 업데이트를 시도합니다:
Resource of type 'AWS::ApplicationAutoScaling::ScalableTarget' with identifier 'endpoint/<name>/variant/AllTraffic|sagemaker:variant:DesiredInstanceCount|sagemaker' was not found.
이 실패가 주목할 만한 이유는 롤백도 실패하기(UPDATE_ROLLBACK_FAILED) 때문이며, 이로 인해 스택이 손상된 상태로 남아 CloudFormation 콘솔에서 수동 개입이 필요합니다.
솔루션 개요
이 CDK 구성을 사용하여 네이티브 AWS::ApplicationAutoScaling::ScalableTarget 및 AWS::ApplicationAutoScaling::ScalingPolicy CloudFormation 리소스를 세 개의 사용자 지정 리소스로 대체할 수 있습니다. 이 사용자 지정 리소스들은 엔드포인트 업데이트를 중심으로 자동 확장 등록 해제 및 등록을 명시적 의존성 순서로 수행하며, 이 순서는 CDK에서 node.add_dependency 호출을 통해 강제됩니다. 전체 순서는 다음과 같습니다:
- 등록 해제 (사용자 지정 리소스): 엔드포인트 업데이트가 시작되기 전에 확장 가능 대상을 제거합니다. 첫 배포 시에는 확장 가능 대상이 아직 존재하지 않으므로, 핸들러가 해당 오류를 우아하게 처리하고 계속 진행합니다.
- 엔드포인트 업데이트 (CDK 관리): CDK가 엔드포인트 리소스를 정상적으로 업데이트하여 새 엔드포인트 구성으로 교체합니다.
- 확장 가능 대상 등록(Register Scalable Target) (사용자 지정 리소스): 엔드포인트가
InService상태에 도달할 때까지 기다린 후 확장 가능 대상을 등록합니다. - 확장 정책 연결(Attach Scaling Policy) (사용자 지정 리소스): 확장 가능 대상이 조회 가능해질 때까지 기다린 후 대상 추적(target tracking) 정책을 적용합니다.
그림 1: CDK 관리 엔드포인트 업데이트를 중심으로 한 SageMaker AI 엔드포인트 자동 확장의 사용자 지정 리소스 조율.
확장 가능 대상 등록(Register Scalable Target) 및 확장 정책 연결(Attach Scaling Policy)은 CDK 제공자의 비동기 완료 패턴을 사용합니다. 각 사용자 지정 리소스는 즉시 반환하는 on_event 핸들러와 그리고 하나의 is_complete handler. 공급자의 웨이터는 readiness 검사가 통과할 때까지 is_complete 핸들러를 일정 간격(30초마다)으로 다시 호출합니다. 공급자의 total_timeout (Register Scalable Target의 경우 1시간, Attach Scaling Policy의 경우 15분)이 대기 시간을 제한하므로, 단일 Lambda 호출의 타임아웃에 제한되지 않습니다.
각 커스텀 리소스의 ConfigHash 속성은 구성 값이 변경될 때마다 CloudFormation이 Lambda 함수를 다시 호출하도록 강제합니다. 엔드포인트 구성과 오토 스케일링 파라미터는 단일 ConfigHash 가 오토 스케일링 오케스트레이션을 주도하기 때문에 함께 정의됩니다.
이 구성체(construct)는 세 개의 커스텀 리소스를 정의하지만, 배포된 스택에는 세 개 이상의 Lambda 함수가 포함되어 있습니다. 각 커스텀 리소스는 CDK cr.Provider로 뒷받침되며, 프로바이더 프레임워크가 자체 헬퍼 Lambda 함수를 생성합니다. 동기식 프로바이더(Deregister)는 프레임워크 함수를 하나 추가합니다. 비동기식 프로바이더(Register Scalable Target 및 Attach Scaling Policy)는 함수 세 개(onEvent, isComplete및 onTimeout)와 웨이터를 구동하는 AWS Step Functions 상태 머신을 추가합니다. 결과적으로 배포된 스택에는 커스텀 리소스 세 개, Step Functions 상태 머신 두 개, Lambda 함수 열두 개가 포함됩니다. 그중 다섯 개의 리소스는 구성체 자체의 핸들러 코드를 담고 있고(Deregister용 하나, 그리고 각 비동기식 리소스를 위한 on_event 및 is_complete 쌍), 나머지 일곱 개는 프로바이더 프레임워크가 생성한 것입니다. 프레임워크가 생성한 함수를 직접 작성하거나 유지 관리하지는 않지만, 이 함수들은 스택에 존재하며 배포된 리소스를 검토할 때 고려할 가치가 있습니다.
실습 안내
이 실습에서는 제공된 예제 스택을 사용하여 오토 스케일링이 적용된 SageMaker AI 엔드포인트를 배포한 후, 구성 업데이트가 올바르게 작동하는지 확인합니다.
실습은 다음 단계로 구성됩니다:
- 리포지토리를 복제하고 의존성을 설치합니다.
- 엔드포인트 및 오토 스케일링 설정을 구성합니다.
- 배포하고 검증합니다.
- 업데이트를 테스트합니다.
소스 코드는 링크된 GitHub 리포지토리.
에서 이용할 수 있습니다.
사전 조건
- Amazon SageMaker AI, AWS Lambda, AWS Identity and Access Management(IAM), Application Auto Scaling, Amazon CloudWatch에 대한 권한이 있는 AWS 계정.
- AWS CDK v2 AWS CDK v2
- Python 3.12 Python 3.12
- 이상. Python 의존성 관리를 위한 uv
- Amazon Simple Storage Service(Amazon S3)에 있는 SageMaker AI 모델 아티팩트와 Amazon Elastic Container Registry(Amazon ECR)에 있는 컨테이너 이미지, 또는 SageMaker AI 내장 알고리즘 컨테이너.
Amazon Simple Storage Service(Amazon S3)에 있는 SageMaker AI 모델 아티팩트와 Amazon Elastic Container Registry(Amazon ECR)에 있는 컨테이너 이미지, 또는 SageMaker AI 내장 알고리즘 컨테이너.
- 리포지토리 복제 및 의존성 설치
git clone https://github.com/aws-samples/sample-sagemaker-endpoint-autoscaling.git cd sample-sagemaker-endpoint-autoscaling - 리포지토리를 복제합니다:
uv sync
의존성을 설치합니다:
엔드포인트 및 오토 스케일링 설정 구성config.yaml 엔드포인트와 오토 스케일링 설정은 config/ 디렉터리에서 함께 정의됩니다. 단일 config_hash 이(가) 오토 스케일링 오케스트레이션을 구동하기 때문입니다. 어느 한 섹션의 변경은 전체 시퀀스를 트리거합니다.
config/ 편집config.yaml 당신의 가치관과 일치하는:
endpoint:
endpoint_name: "my-model-endpoint"
image: "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-model:latest"
model_data_url: "s3://my-bucket/models/model.tar.gz"
instance_type: "ml.m5.large"
initial_instance_count: 1
environment: {}
autoscaling:
min_capacity: 1
max_capacity: 10
target_value: 100
scale_in_cooldown: 600
scale_out_cooldown: 120
엔드포인트 파라미터는 SageMaker AI에 매핑됩니다. CreateModel 그리고 CreateEndpointConfig API. 자동 조정 파라미터는 Application Auto Scaling의 RegisterScalableTarget 그리고 PutScalingPolicy API입니다.
배포 및 검증
- 아직 준비되지 않았다면 AWS 환경을 부트스트랩하세요:
uv run cdk bootstrap - 스택을 배포하세요:
uv run cdk deploy InferenceStack
CloudFormation은 SageMaker AI 모델, 엔드포인트 구성 및 엔드포인트를 생성한 다음, 세 개의 사용자 지정 리소스를 순서대로 실행하여 auto scaling을 등록합니다.
- 배포가 확장 가능 대상(scalable target)을 등록했는지 확인하세요:
aws application-autoscaling describe-scalable-targets --service-namespace sagemaker --resource-ids endpoint/my-model-endpoint/variant/AllTraffic - 배포가 조정 정책(scaling policy)을 적용했는지 확인하세요:
aws application-autoscaling describe-scaling-policies --service-namespace sagemaker --resource-id endpoint/my-model-endpoint/variant/AllTraffic
업데이트 테스트
config/에서 값을 변경하세요config.yaml. 예를 들어, 인스턴스 유형을 ml.m5.large 에서 ml.m5.xlarge(으)로 업데이트하고 다시 배포하세요:
uv run cdk deploy InferenceStack
배포가 완료되면 auto scaling이 여전히 등록되어 있고 업데이트된 값을 가지고 있는지 확인하세요:
aws application-autoscaling describe-scalable-targets
--service-namespace sagemaker
--resource-ids endpoint/my-model-endpoint/variant/AllTraffic
기존 스택과의 통합
새로 시작하거나 참조 구현이 필요하다면 예제 스택을 사용하세요. SageMaker AI 리소스가 포함된 CDK 스택이 이미 있다면 해당 구성 요소를 직접 사용하세요.
기존 스택과 통합하려면 다음을 복사하십시오 sagemaker_autoscaling/constructs/ 프로젝트에 디렉터리를 추가하고 엔드포인트 리소스와 함께 이 구성(construct)을 추가하세요:
import json
from sagemaker_autoscaling.constructs.sagemaker_autoscaling_construct import (
AutoscalingConfig,
SagemakerAutoscalingConstruct,
SagemakerAutoscalingProps,
)
# Both endpoint and auto scaling values must be in config_hash so that
# a change to either triggers the auto scaling orchestration.
config_hash = json.dumps({
"endpoint": {
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-model:latest",
"modelDataUrl": "s3://my-bucket/models/model.tar.gz",
"instanceType": "ml.m5.large",
"initialInstanceCount": 1,
},
"autoscaling": {
"minCapacity": 1,
"maxCapacity": 10,
"targetValue": 100,
"scaleInCooldown": 600,
"scaleOutCooldown": 120,
},
})
SagemakerAutoscalingConstruct(
self, "Autoscaling",
props=SagemakerAutoscalingProps(
endpoint=your_endpoint, # your CfnEndpoint
autoscaling=AutoscalingConfig(
min_capacity=1,
max_capacity=10,
target_value=100,
scale_in_cooldown=600,
scale_out_cooldown=120,
),
config_hash=config_hash,
),
)
이 구조체가 작동하는 방식
이 섹션에서는 다음의 핵심 구현 세부 사항을 살펴봅니다. SagemakerAutoscalingConstruct.
등록 해제
Deregister 커스텀 리소스 호출 deregister_scalable_target 엔드포인트 업데이트 이전에 처리합니다. 이는 다음을 처리합니다. ObjectNotFoundException 확장 가능한 대상이 존재하지 않는 최초 배포의 경우:
def handler(event, context):
resource_id = event["ResourceProperties"]["ResourceId"]
if event["RequestType"] in ("Create", "Update"):
try:
client.deregister_scalable_target(
ServiceNamespace="sagemaker",
ResourceId=resource_id,
ScalableDimension="sagemaker:variant:DesiredInstanceCount",
)
except client.exceptions.ObjectNotFoundException:
pass # No scalable target on first deploy
return {"PhysicalResourceId": f"deregister-{resource_id}"}
의존성은 CDK에서 설정됩니다:
props.endpoint.node.add_dependency(deregister)
확장 가능 대상 등록
CloudFormation이 업데이트가 수락되는 시점에 엔드포인트 리소스를 완료된 것으로 처리하더라도, 확장 가능 대상은 엔드포인트가 도달한 후에만 등록할 수 있습니다 InService. 해당 대기를 위해 단일 Lambda 호출을 블로킹하는 대신, Register Scalable Target은 공급자의 비동기 완료 패턴을 사용합니다. The on_event handler는 즉시 반환되며, 공급자(provider)의 웨이터가 다시 호출합니다 is_complete 핸들러 on query_interval 엔드포인트가 될 때까지 InService. 해당 제공자의 total_timeout (1시간)이 대기 시간을 제한하며, 개별 Lambda 호출의 타임아웃이 아닙니다:
def handler(event, context):
props = event["ResourceProperties"]
resource_id = props["ResourceId"]
endpoint_name = resource_id.split("/")[1]
if event["RequestType"] == "Delete":
return {"IsComplete": True}
status = sm_client.describe_endpoint(EndpointName=endpoint_name)["EndpointStatus"]
if status == "Failed":
raise Exception("Endpoint in Failed state")
if status != "InService":
return {"IsComplete": False}
as_client.register_scalable_target(
ServiceNamespace="sagemaker",
ResourceId=resource_id,
ScalableDimension="sagemaker:variant:DesiredInstanceCount",
MinCapacity=int(props["MinCapacity"]),
MaxCapacity=int(props["MaxCapacity"]),
)
return {"IsComplete": True}
스택 삭제 시, on_event 핸들러가 정리를 위해 확장 가능 대상(scalable target)의 등록을 해제합니다.
확장 정책 연결
다음 시점 이후에는 짧은 기간이 있습니다. RegisterScalableTarget 대상이 아직 쿼리 가능하지 않은 경우에도 반환됩니다. 정책 연결(Attach Scaling Policy)은 동일한 비동기 완료 패턴을 사용합니다: on_event 핸들러는 즉시 반환되며, 그 이후 is_complete handler reports completion only once the scalable target is queryable, at which point it applies the policy. The provider’s를 한국어로 번역합니다:
핸들러는 확장 가능 대상을 쿼리할 수 있게 된 후에야 완료를 보고하며, 그 시점에 정책을 적용합니다. 이 프로바이더의 total_timeout (15분) 대기 시간을 제한합니다:
def handler(event, context):
props = event["ResourceProperties"]
resource_id = props["ResourceId"]
if event["RequestType"] == "Delete":
return {"IsComplete": True}
resp = client.describe_scalable_targets(
ServiceNamespace="sagemaker",
ResourceIds=[resource_id],
ScalableDimension="sagemaker:variant:DesiredInstanceCount",
)
if not resp.get("ScalableTargets"):
return {"IsComplete": False}
client.put_scaling_policy(
PolicyName=props["PolicyName"],
ServiceNamespace="sagemaker",
ResourceId=resource_id,
ScalableDimension="sagemaker:variant:DesiredInstanceCount",
PolicyType="TargetTrackingScaling",
TargetTrackingScalingPolicyConfiguration=json.loads(props["ScalingPolicyConfig"]),
)
return {"IsComplete": True}
스택 삭제 시, on_event 핸들러가 정리를 위해 스케일링 정책을 삭제합니다.
정리하기
향후 요금이 부과되지 않도록 다음 리소스를 삭제하세요:
uv run cdk destroy InferenceStack
이 과정에서는 SageMaker AI 엔드포인트, 엔드포인트 구성, 모델, Lambda 함수, IAM 역할, 대상 추적 조정 정책에 의해 생성된 Amazon CloudWatch 알람을 제거하고 조정 가능 대상의 등록을 해제합니다.
결론
이번 포스트에서는 재사용 가능한 CDK 구성(construct)을 사용해 오토 스케일링을 자동으로 등록 해제 및 등록함으로써 SageMaker AI 엔드포인트 업데이트를 오케스트레이션하는 방법을 보여드렸습니다. 이 구성은 명시적인 종속성 순서를 갖는 세 개의 CloudFormation 사용자 지정 리소스와 그rlen다. ConfigHash 배포 전반에 걸쳐 자동 확장을 그대로 유지하기 위한 속성입니다.
시작하려면 다음을 클론하세요: sample-sagemaker-endpoint-autoscaling 레포지토리에서 설정 지침을 따르십시오. 레포지토리에는 바로 배포할 수 있는 예제 스택이 포함되어 있으며, 기존 CDK 스택에 구성체(construct)를 통합할 수도 있습니다.
SageMaker AI용 Application Auto Scaling에 대한 자세한 내용은 다음을 참조하세요. Amazon SageMaker AI 모델 자동 확장. CloudFormation 사용자 지정 리소스에 대한 자세한 내용은 AWS CloudFormation User Guide.