kubectl을 사용하여 Amazon S3 및 Amazon FSx에서 사용자 지정 미세 조정된 모델 배포 - Amazon SageMaker AI

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

kubectl을 사용하여 Amazon S3 및 Amazon FSx에서 사용자 지정 미세 조정된 모델 배포

다음 단계에서는 kubectl을 사용하여 Amazon S3 또는 Amazon FSx에 저장된 모델을 Amazon SageMaker HyperPod 클러스터에 배포하는 방법을 보여줍니다.

다음 지침에는 Amazon SageMaker Studio 또는 SageMaker 노트북 인스턴스와 같은 Jupyter 노트북 환경에서 실행되도록 설계된 코드 셀과 명령이 포함되어 있습니다. 각 코드 블록은 순차적으로 실행해야 하는 노트북 셀을 나타냅니다. 모델 검색 테이블 및 상태 모니터링 명령을 포함한 대화형 요소는 노트북 인터페이스에 최적화되어 있으며 다른 환경에서 제대로 작동하지 않을 수 있습니다. 계속하기 전에 필요한 AWS 권한이 있는 노트북 환경에 액세스할 수 있는지 확인합니다.

사전 조건

Amazon SageMaker HyperPod 클러스터에서 추론 기능을 설정했는지 확인합니다. 자세한 내용은 모델 배포를 위한 HyperPod 클러스터 설정 단원을 참조하십시오.

설정 및 구성

모든 자리 표시자 값을 실제 리소스 식별자로 바꿉니다.

  1. 클러스터 이름을 초기화합니다. 그러면 모델이 배포될 HyperPod 클러스터가 식별됩니다.

    # Specify your hyperpod cluster name here hyperpod_cluster_name="<Hyperpod_cluster_name>" # NOTE: For sample deployment, we use g5.8xlarge for deepseek-r1 1.5b model which has sufficient memory and GPU instance_type="ml.g5.8xlarge"
  2. 클러스터 네임스페이스를 초기화합니다. 클러스터 관리자가 네임스페이스에 하이퍼포드 추론 서비스 계정을 이미 생성했어야 합니다.

    cluster_namespace="<namespace>"
  3. 배포를 위한 YAML 파일을 생성하는 헬퍼 메서드 정의

    다음 헬퍼 함수는 모델을 배포하는 데 필요한 Kubernetes YAML 구성 파일을 생성합니다. 이 함수는 모델이 Amazon S3 또는 Amazon FSx에 저장되는지 여부에 따라 다른 YAML 구조를 생성하여 스토리지별 구성을 자동으로 처리합니다. 다음 섹션에서이 함수를 사용하여 선택한 스토리지 백엔드에 대한 배포 파일을 생성합니다.

    def generate_inferenceendpointconfig_yaml(deployment_name, model_id, namespace, instance_type, output_file_path, region, tls_certificate_s3_location, model_location, sagemaker_endpoint_name, fsxFileSystemId="", isFsx=False, s3_bucket=None): """ Generate a InferenceEndpointConfig YAML file for S3 storage with the provided parameters. Args: deployment_name (str): The deployment name model_id (str): The model ID namespace (str): The namespace instance_type (str): The instance type output_file_path (str): Path where the YAML file will be saved region (str): Region where bucket exists tls_certificate_s3_location (str): S3 location for TLS certificate model_location (str): Location of the model sagemaker_endpoint_name (str): Name of the SageMaker endpoint fsxFileSystemId (str): FSx filesystem ID (optional) isFsx (bool): Whether to use FSx storage (optional) s3_bucket (str): S3 bucket where model exists (optional, only needed when isFsx is False) """ # Create the YAML structure model_config = { "apiVersion": "inference.sagemaker.aws.amazon.com/v1alpha1", "kind": "InferenceEndpointConfig", "metadata": { "name": deployment_name, "namespace": namespace }, "spec": { "modelName": model_id, "endpointName": sagemaker_endpoint_name, "invocationEndpoint": "invocations", "instanceType": instance_type, "modelSourceConfig": {}, "worker": { "resources": { "limits": { "nvidia.com/gpu": 1, }, "requests": { "nvidia.com/gpu": 1, "cpu": "30000m", "memory": "100Gi" } }, "image": "763104351884.dkr.ecr.us-east-2.amazonaws.com/huggingface-pytorch-tgi-inference:2.4.0-tgi2.3.1-gpu-py311-cu124-ubuntu22.04-v2.0", "modelInvocationPort": { "containerPort": 8080, "name": "http" }, "modelVolumeMount": { "name": "model-weights", "mountPath": "/opt/ml/model" }, "environmentVariables": [ { "name": "HF_MODEL_ID", "value": "/opt/ml/model" }, { "name": "SAGEMAKER_PROGRAM", "value": "inference.py", }, { "name": "SAGEMAKER_SUBMIT_DIRECTORY", "value": "/opt/ml/model/code", }, { "name": "MODEL_CACHE_ROOT", "value": "/opt/ml/model" }, { "name": "SAGEMAKER_ENV", "value": "1", } ] }, "tlsConfig": { "tlsCertificateOutputS3Uri": tls_certificate_s3_location, } }, } if (not isFsx): if s3_bucket is None: raise ValueError("s3_bucket is required when isFsx is False") model_config["spec"]["modelSourceConfig"] = { "modelSourceType": "s3", "s3Storage": { "bucketName": s3_bucket, "region": region, }, "modelLocation": model_location } else: model_config["spec"]["modelSourceConfig"] = { "modelSourceType": "fsx", "fsxStorage": { "fileSystemId": fsxFileSystemId, }, "modelLocation": model_location } # Write to YAML file with open(output_file_path, 'w') as file: yaml.dump(model_config, file, default_flow_style=False) print(f"YAML file created successfully at: {output_file_path}")

Amazon S3 또는 Amazon FSx에서 모델 배포

Stage the model to Amazon S3
  1. Amazon S3 버킷을 생성하여 모델 아티팩트를 저장합니다. S3 버킷은 HyperPod 클러스터와 동일한 리전에 있어야 합니다.

    s3_client = boto3.client('s3', region_name=region_name, config=boto3_config) base_name = "hyperpod-inference-s3-beta" def get_account_id(): sts = boto3.client('sts') return sts.get_caller_identity()["Account"] account_id = get_account_id() s3_bucket = f"{base_name}-{account_id}" try: s3_client.create_bucket( Bucket=s3_bucket, CreateBucketConfiguration={"LocationConstraint": region_name} ) print(f"Bucket '{s3_bucket}' is created successfully.") except botocore.exceptions.ClientError as e: error_code = e.response["Error"]["Code"] if error_code in ("BucketAlreadyExists", "BucketAlreadyOwnedByYou"): print(f"Bucket '{s3_bucket}' already exists. Skipping creation.") else: raise # Re-raise unexpected exceptions
  2. 배포 YAML을 가져와 S3 버킷 데이터에서 모델을 배포합니다.

    # Get current time in format suitable for endpoint name current_time = datetime.now().strftime("%Y%m%d%H%M%S") model_id = "deepseek15b" ## Can be a name of your choice deployment_name = f"{model_id}-{current_time}" model_location = "deepseek15b" ## This is the folder on your s3 file where the model is located sagemaker_endpoint_name=f"{model_id}-{current_time}" output_file_path=f"inferenceendpointconfig-s3-model-{model_id}.yaml" generate_inferenceendpointconfig_yaml( deployment_name=deployment_name, model_id=model_id, model_location=model_location, namespace=cluster_namespace, instance_type=instance_type, output_file_path=output_file_path, sagemaker_endpoint_name=sagemaker_endpoint_name, s3_bucket=s3_bucket, region=region_name, tls_certificate_s3_location=tls_certificate_s3_location ) os.environ["INFERENCE_ENDPOINT_CONFIG_YAML_FILE_PATH"]=output_file_path os.environ["MODEL_ID"]=model_id
Stage the model to Amazon FSx
  1. (선택 사항) FSx 볼륨을 생성합니다. 이 단계는 사용하려는 HyperPod 클러스터와 VPC, 보안 그룹 및 서브넷 ID가 동일한 기존 FSx 파일 시스템이 이미 있을 수 있으므로 선택 사항입니다.

    # Initialize the subnet ID and Security Group for FSx. These should be the same as that of the HyperPod cluster. SUBNET_ID = "<HyperPod-subnet-id>" SECURITY_GROUP_ID = "<HyperPod-security-group-id>" # Configuration CONFIG = { 'SUBNET_ID': SUBNET_ID, 'SECURITY_GROUP_ID': SECURITY_GROUP_ID, 'STORAGE_CAPACITY': 1200, 'DEPLOYMENT_TYPE': 'PERSISTENT_2', 'THROUGHPUT': 250, 'COMPRESSION_TYPE': 'LZ4', 'LUSTRE_VERSION': '2.15' } JUMPSTART_MODEL_LOCATION_ON_S3 = "s3://jumpstart-cache-prod-us-east-2/deepseek-llm/deepseek-llm-r1-distill-qwen-1-5b/artifacts/inference-prepack/v2.0.0/" # Create FSx client fsx = boto3.client('fsx') # Create FSx for Lustre file system response = fsx.create_file_system( FileSystemType='LUSTRE', FileSystemTypeVersion=CONFIG['LUSTRE_VERSION'], StorageCapacity=CONFIG['STORAGE_CAPACITY'], SubnetIds=[CONFIG['SUBNET_ID']], SecurityGroupIds=[CONFIG['SECURITY_GROUP_ID']], LustreConfiguration={ 'DeploymentType': CONFIG['DEPLOYMENT_TYPE'], 'PerUnitStorageThroughput': CONFIG['THROUGHPUT'], 'DataCompressionType': CONFIG['COMPRESSION_TYPE'], } ) # Get the file system ID file_system_id = response['FileSystem']['FileSystemId'] print(f"Creating FSx filesystem with ID: {file_system_id}") print(f"In subnet: {CONFIG['SUBNET_ID']}") print(f"With security group: {CONFIG['SECURITY_GROUP_ID']}") # Wait for the file system to become available while True: response = fsx.describe_file_systems(FileSystemIds=[file_system_id]) status = response['FileSystems'][0]['Lifecycle'] if status == 'AVAILABLE': break print(f"Waiting for file system to become available... Current status: {status}") time.sleep(30) dns_name = response['FileSystems'][0]['DNSName'] mount_name = response['FileSystems'][0]['LustreConfiguration']['MountName'] # Print the file system details print("\nFile System Details:") print(f"File System ID: {file_system_id}") print(f"DNS Name: {dns_name}") print(f"Mount Name: {mount_name}")
  2. (선택 사항) FSx를 탑재하고 S3에서 FSx로 데이터를 복사합니다. 모델 데이터가 FSx 파일 시스템에 이미 존재할 수 있으므로이 단계는 선택 사항입니다. 이 단계는 S3에서 FSx로 데이터를 복사하려는 경우에만 필요합니다.

    참고

    file_system_id, dns_name 및 mount_name 값을 이전 단계의 fsx를 사용하지 않고 자체 FSX를 사용하는 FSX IN CASE로 바꿉니다.

    ## NOTE: Replace values of file_system_id, dns_name, and mount_name with your FSx in case you are not using the FSx filesystem from the previous step and using your own FSx filesystem. # file_system_id = response['FileSystems'][0]['FileSystemId'] # dns_name = response['FileSystems'][0]['DNSName'] # mount_name = response['FileSystems'][0]['LustreConfiguration']['MountName'] # print(f"File System ID: {file_system_id}") # print(f"DNS Name: {dns_name}") # print(f"Mount Name: {mount_name}") # FSx file system details mount_point = f'/mnt/fsx_{file_system_id}' # This will create something like /mnt/fsx_20240317_123456 print(f"Creating mount point at: {mount_point}") # Create mount directory if it doesn't exist !sudo mkdir -p {mount_point} # Mount the FSx Lustre file system mount_command = f"sudo mount -t lustre {dns_name}@tcp:/{mount_name} {mount_point}" !{mount_command} # Verify the mount !df -h | grep fsx print(f"File system mounted at {mount_point}") !sudo chmod 777 {mount_point} !aws s3 cp $JUMPSTART_MODEL_LOCATION_ON_S3 $mount_point/deepseek-1-5b --recursive !ls $mount_point !sudo umount {mount_point} !sudo rm -rf {mount_point}
  3. 배포 YAML을 가져와 FSx 데이터에서 모델을 배포합니다.

    # Get current time in format suitable for endpoint name current_time = datetime.now().strftime("%Y%m%d%H%M%S") model_id = "deepseek15b" ## Can be a name of your choice deployment_name = f"{model_id}-{current_time}" model_location = "deepseek-1-5b" ## This is the folder on your s3 file where the model is located sagemaker_endpoint_name=f"{model_id}-{current_time}" output_file_path=f"inferenceendpointconfig-fsx-model-{model_id}.yaml" generate_inferenceendpointconfig_yaml( deployment_name=deployment_name, model_id=model_id, model_location=model_location, namespace=cluster_namespace, instance_type=instance_type, output_file_path=output_file_path, region=region_name, tls_certificate_s3_location=tls_certificate_s3_location, sagemaker_endpoint_name=sagemaker_endpoint_name, fsxFileSystemId=file_system_id, isFsx=True ) os.environ["INFERENCE_ENDPOINT_CONFIG_YAML_FILE_PATH"]=output_file_path os.environ["MODEL_ID"]=model_id
클러스터에 모델 배포
  1. kubectl 인증을 위해 HyperPod 클러스터 ARN에서 Amazon EKS 클러스터 이름을 가져옵니다.

    cluster_arn = !aws sagemaker describe-cluster --cluster-name $hyperpod_cluster_name --query "Orchestrator.Eks.ClusterArn" --region $region_name cluster_name = cluster_arn[0].strip('"').split('/')[-1] print(cluster_name)
  2. 자격 AWS 증명을 사용하여 Hyperpod EKS 클러스터로 인증하도록 kubectl 구성

    !aws eks update-kubeconfig --name $cluster_name --region $region_name
  3. InferenceEndpointConfig 모델을 배포합니다.

    !kubectl apply -f $INFERENCE_ENDPOINT_CONFIG_YAML_FILE_PATH

배포 상태 확인

  1. 모델이 성공적으로 배포되었는지 확인합니다.

    !kubectl describe InferenceEndpointConfig $deployment_name -n $cluster_namespace

    이 명령은 다음과 비슷한 출력을 반환합니다.

    Name:                             deepseek15b-20250624043033
    Reason:                           NativeDeploymentObjectFound
    Status:
      Conditions:
        Last Transition Time:  2025-07-10T18:39:51Z
        Message:               Deployment, ALB Creation or SageMaker endpoint registration creation for model is in progress
        Reason:                InProgress
        Status:                True
        Type:                  DeploymentInProgress
        Last Transition Time:  2025-07-10T18:47:26Z
        Message:               Deployment and SageMaker endpoint registration for model have been created successfully
        Reason:                Success
        Status:                True
        Type:                  DeploymentComplete
  2. 엔드포인트가 성공적으로 생성되었는지 확인합니다.

    !kubectl describe SageMakerEndpointRegistration $sagemaker_endpoint_name -n $cluster_namespace

    이 명령은 다음과 비슷한 출력을 반환합니다.

    Name:         deepseek15b-20250624043033
    Namespace:    ns-team-a
    Kind:         SageMakerEndpointRegistration
    
    Status:
      Conditions:
        Last Transition Time:  2025-06-24T04:33:42Z
        Message:               Endpoint created.
        Status:                True
        Type:                  EndpointCreated
        State:                 CreationCompleted
  3. 배포된 엔드포인트를 테스트하여 올바르게 작동하는지 확인합니다. 이 단계에서는 모델이 성공적으로 배포되었으며 추론 요청을 처리할 수 있는지 확인합니다.

    import boto3 prompt = "{\"inputs\": \"How tall is Mt Everest?\"}}" runtime_client = boto3.client('sagemaker-runtime', region_name=region_name, config=boto3_config) response = runtime_client.invoke_endpoint( EndpointName=sagemaker_endpoint_name, ContentType="application/json", Body=prompt ) print(response["Body"].read().decode())
    [{"generated_text":"As of the last update in July 2024, Mount Everest stands at a height of **8,850 meters** (29,029 feet) above sea level. The exact elevation can vary slightly due to changes caused by tectonic activity and the melting of ice sheets."}]

배포 관리

배포 테스트를 마치면 다음 명령을 사용하여 리소스를 정리합니다.

참고

계속하기 전에 배포된 모델 또는 저장된 데이터가 더 이상 필요하지 않은지 확인합니다.

리소스 정리
  1. 추론 배포 및 연결된 Kubernetes 리소스를 삭제합니다. 이렇게 하면 실행 중인 모델 컨테이너가 중지되고 SageMaker 엔드포인트가 제거됩니다.

    !kubectl delete inferenceendpointconfig.inference.sagemaker.aws.amazon.com/$deployment_name
  2. (선택 사항) FSx 볼륨을 삭제합니다.

    try: # Delete the file system response = fsx.delete_file_system( FileSystemId=file_system_id ) print(f"Deleting FSx filesystem: {file_system_id}") # Optional: Wait for deletion to complete while True: try: response = fsx.describe_file_systems(FileSystemIds=[file_system_id]) status = response['FileSystems'][0]['Lifecycle'] print(f"Current status: {status}") time.sleep(30) except fsx.exceptions.FileSystemNotFound: print("File system deleted successfully") break except Exception as e: print(f"Error deleting file system: {str(e)}")
  3. 정리가 성공적으로 완료되었는지 확인합니다.

    # Check that Kubernetes resources are removed kubectl get pods,svc,deployment,InferenceEndpointConfig,sagemakerendpointregistration -n $cluster_namespace # Verify SageMaker endpoint is deleted (should return error or empty) aws sagemaker describe-endpoint --endpoint-name $sagemaker_endpoint_name --region $region_name
문제 해결
  1. Kubernetes 배포 상태를 확인합니다.

    !kubectl describe deployment $deployment_name -n $cluster_namespace
  2. InferenceEndpointConfig 상태를 확인하여 상위 수준 배포 상태와 구성 문제를 확인합니다.

    kubectl describe InferenceEndpointConfig $deployment_name -n $cluster_namespace
  3. 모든 Kubernetes 객체의 상태를 확인합니다. 네임스페이스의 모든 관련 Kubernetes 리소스를 포괄적으로 볼 수 있습니다. 이를 통해 실행 중인 항목과 누락된 항목에 대한 간략한 개요를 확인할 수 있습니다.

    !kubectl get pods,svc,deployment,InferenceEndpointConfig,sagemakerendpointregistration -n $cluster_namespace