

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

# 사용자 지정 추론 코드가 있는 컨테이너
<a name="your-algorithms-inference-main"></a>

Amazon SageMaker AI를 사용하면 Docker 컨테이너와 상호 작용하고 다음 두 가지 중 한 가지 방법으로 자체 추론 코드를 실행할 수 있습니다.
+ 영구 엔드포인트에서 자체 추론 코드를 사용하여 한 번에 하나의 예측을 얻으려면 SageMaker AI 호스팅 서비스를 사용합니다.
+ 자체 추론 코드를 사용하여 전체 데이터세트에 대한 예측을 얻으려면 SageMaker AI 배치 변환을 사용합니다.

**Topics**
+ [호스팅 서비스를 사용한 사용자 지정 추론 코드](your-algorithms-inference-code.md)
+ [배치 변환을 사용한 사용자 지정 추론 코드](your-algorithms-batch-code.md)

# 호스팅 서비스를 사용한 사용자 지정 추론 코드
<a name="your-algorithms-inference-code"></a>

이 섹션에서는 호스팅 서비스를 위한 자체 추론 코드를 실행하는 Docker 컨테이너와 Amazon SageMaker AI가 상호 작용하는 방법을 설명합니다. 이 정보를 사용하여 추론 코드를 작성하고 Docker 이미지를 생성합니다.

**Topics**
+ [SageMaker AI가 추론 이미지를 실행하는 방법](#your-algorithms-inference-code-run-image)
+ [SageMaker AI가 모델 아티팩트를 로드하는 방법](#your-algorithms-inference-code-load-artifacts)
+ [컨테이너의 추론 요청 응답 방법](#your-algorithms-inference-code-container-response)
+ [컨테이너의 상태 확인(핑) 요청 응답 방법](#your-algorithms-inference-algo-ping-requests)
+ [양방향 스트리밍 기능을 지원하는 컨테이너 계약](#your-algorithms-inference-algo-bidi)
+ [실시간 추론 컨테이너에 대한 프라이빗 Docker 레지스트리 사용](your-algorithms-containers-inference-private.md)

## SageMaker AI가 추론 이미지를 실행하는 방법
<a name="your-algorithms-inference-code-run-image"></a>

컨테이너를 실행 파일로 실행하도록 구성하려면 Dockerfile에서 `ENTRYPOINT` 지침을 사용합니다. 다음 사항에 유의하세요.
+ 모델 추론의 경우 SageMaker AI는 다음과 같이 컨테이너를 실행합니다.

  ```
  docker run image serve
  ```

  SageMaker AI는 이미지 이름 뒤에 `serve` 인수를 지정함으로써 컨테이너에 있는 기본 `CMD` 문을 재정의합니다. `serve` 인수는 또한 Dockerfile에서 `CMD` 명령을 사용하여 입력한 인수 또한 재정의합니다.

   
+ SageMaker AI는 모든 컨테이너가 루트 사용자와 함께 실행될 것을 기대합니다. 루트 사용자만 사용하도록 컨테이너를 생성하세요. SageMaker AI가 컨테이너를 실행할 때 루트 수준 액세스 권한이 없는 사용자는 권한 문제를 일으킬 수 있습니다.

   
+ `exec` 지침의 `ENTRYPOINT` 양식을 사용하는 것이 좋습니다.

  ```
  ENTRYPOINT ["executable", "param1", "param2"]
  ```

  예제:

  ```
  ENTRYPOINT ["python", "k_means_inference.py"]
  ```

  `exec` 형식의 `ENTRYPOINT` 명령은, `/bin/sh`의 하위로서가 아니라, 실행 파일을 직접 시작합니다. 이를 통해 SageMaker API로부터 `SIGTERM` 및 `SIGKILL`과 같은 신호를 수신할 수 있으며, 이는 필수 사항입니다.

   

  예를 들어, [https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateEndpoint.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateEndpoint.html) API를 사용하여 엔드포인트를 생성할 때 SageMaker AI는 사용자가 요청에 지정한 대로 엔드포인트 구성에 필요한 개수의 ML 컴퓨팅 인스턴스를 프로비저닝합니다. SageMaker AI는 해당 인스턴스에서 Docker 컨테이너를 실행합니다.

   

  ([https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_UpdateEndpointWeightsAndCapacities.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_UpdateEndpointWeightsAndCapacities.html) API를 직접적으로 호출하여) 엔드포인트를 지원하는 인스턴스의 수를 줄이는 경우 SageMaker AI가 명령을 실행하여 종료 중인 인스턴스의 Docker 컨테이너를 중지합니다. 명령은 `SIGTERM` 신호를 전송한 다음 30초 후에 `SIGKILL` 신호를 전송합니다.

   

  ([https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_UpdateEndpoint.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_UpdateEndpoint.html) API를 직접적으로 호출하여) 엔드포인트를 업데이트하는 경우 SageMaker AI는 다른 ML 컴퓨팅 인스턴스 세트를 시작하고 여기에 추론 코드가 포함된 Docker 컨테이너를 실행합니다. 그런 다음 명령을 실행하여 이전 Docker 컨테이너를 중지합니다. Docker 컨테이너를 중지하려면 명령은 `SIGTERM` 신호를 전송한 다음 30초 후에 `SIGKILL` 신호를 전송합니다.

   
+ SageMaker AI는 사용자가 사용자의 [https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateModel.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateModel.html) 요청에 제공한 컨테이너 정의를 사용하여 다음과 같이 컨테이너에 대한 환경 변수 및 DNS 호스트 이름을 설정합니다.

   
  + `ContainerDefinition.Environment` 문자열 간 맵을 사용하여 환경 변수를 설정합니다.
  + `ContainerDefinition.ContainerHostname`을 사용하여 DNS 호스트 이름을 설정합니다.

     
+ (`CreateEndpointConfig` 요청에 GPU 기반 ML 컴퓨팅 인스턴스를 지정하여) 모델 추론에 GPU 디바이스를 사용하려는 경우 컨테이너가 `nvidia-docker`와 호환 가능한지 확인해야 합니다. 이미지가 포함된 NVIDIA 드라이버를 번들화하지 마세요. `nvidia-docker`에 대한 자세한 정보는 [NVIDIA/nvidia-docker](https://github.com/NVIDIA/nvidia-docker)를 참조하세요.

   
+ SageMaker AI 컨테이너의 진입점으로 `tini` 이니셜라이저를 사용할 수 없습니다. `train` 및 `serve` 인수로 인해 혼동되기 때문입니다.

  

## SageMaker AI가 모델 아티팩트를 로드하는 방법
<a name="your-algorithms-inference-code-load-artifacts"></a>

[https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateModel.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateModel.html) API 요청에서 사용자는 `ModelDataUrl` 또는 `S3DataSource` 파라미터를 사용하여 모델 아티팩트가 저장되는 S3 위치를 식별할 수 있습니다. SageMaker AI는 추론 코드로 사용하기 위해 모델 아티팩트를 S3 위치에서 `/opt/ml/model` 디렉터리로 복사합니다. 컨테이너에 `/opt/ml/model`에 대한 읽기 전용 액세스 권한이 있습니다. 이 디렉터리에는 쓰지 마세요.

`ModelDataUrl`은 tar.gz 파일을 가리켜야 합니다. 그렇지 않으면 SageMaker AI가 해당 파일을 다운로드하지 못합니다.

SageMaker AI에서 모델을 훈련한 경우 모델 아티팩트는 Amazon S3에 압축된 단일 tar 파일로 저장됩니다. SageMaker AI 외부에서 모델을 훈련시킨 경우, 이 단일 압축 tar 파일을 생성하여 S3 위치에 저장해야 합니다. SageMaker AI는 컨테이너가 시작되기 전에 이 tar 파일을 /opt/ml/model 디렉터리로 압축 해제합니다.

대형 모델을 배포하는 경우 [압축되지 않은 모델 배포하기](large-model-inference-uncompressed.md)을 수행하는 것을 권장합니다.

## 컨테이너의 추론 요청 응답 방법
<a name="your-algorithms-inference-code-container-response"></a>

추론을 얻으려면 클라이언트 애플리케이션이 SageMaker AI 엔드포인트로 POST 요청을 전송합니다. SageMaker AI가 요청을 컨테이너에 전달하고 추론 결과를 컨테이너에서 클라이언트로 반환합니다.

컨테이너가 받게 될 추론 요청에 대한 자세한 내용은 *Amazon SageMaker AI API 참조*의 다음과 같은 작업을 참조하세요.
+ [ InvokeEndpoint](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_runtime_InvokeEndpoint.html)
+ [ InvokeEndpointAsync](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_runtime_InvokeEndpointAsync.html)
+ [ InvokeEndpointWithResponseStream](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_runtime_InvokeEndpointWithResponseStream.html)
+ [ InvokeEndpointWithResponseStream](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_runtime_InvokeEndpointWithBidirectionalStream.html)

**추론 컨테이너 요구 사항**

추론 요청에 응답하려면 컨테이너가 다음 요구 사항을 충족해야 합니다.
+ SageMaker AI는 `InvokeEndpoint`에서 지원하는 것을 제외한 모든 `POST` 헤더를 제거합니다. SageMaker AI는 헤더를 더 추가할 수 있습니다. 추론 컨테이너는 이러한 추가 헤더를 안전하게 무시할 수 있어야 합니다.
+ 추론 요청을 수신하려면 컨테이너에 포트 8080에서 수신하는 웹 서버가 있어야 하고, `/invocations` 및 `/ping` 엔드포인트에 대한 `POST` 요청을 수락해야 합니다.
+ 고객의 모델 컨테이너는 250ms 이내에 소켓 연결 요청을 수락해야 합니다.
+ 고객의 모델 컨테이너는 60초 안에 요청에 응답해야 합니다. 모델 자체가 `/invocations`에 응답하는 데 최대 처리 시간이 60초까지 걸릴 수 있기 때문입니다. 모델에서 처리하는 데 50\$160초가량 걸린다면 SDK 소켓 시간제한을 70초로 설정해야 합니다.
+ 양방향 스트리밍을 지원하는 고객의 모델 컨테이너는 다음과 같아야 합니다.
  + 는 기본적으로 포트 8080에서 /invocations-bidirectional-stream에 대한 WebSockets 연결을 지원합니다.
  + 에는 포트 8080에서 수신하는 웹 서버가 있으며 /ping 엔드포인트에 대한 POST 요청을 수락해야 합니다.
  + HTTP를 통한 컨테이너 상태 확인 외에도 전송된 WebSocket Ping Frame에 대해 컨테이너는 ([RFC6455](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.3))당 Pong Frame으로 응답해야 합니다.

**Example 호출 함수**  
다음 예제에서는 컨테이너의 코드가 추론 요청을 처리하는 방법을 보여 줍니다. 이 예제는 InvokeEndpoint 작업을 사용하여 클라이언트 애플리케이션이 보내는 요청을 처리합니다.  
FastAPI는 Python으로 API를 빌드하기 위한 웹 프레임워크입니다.  

```
from fastapi import FastAPI, status, Request, Response
. . .
app = FastAPI()
. . .
@app.post('/invocations')
async def invocations(request: Request):
    # model() is a hypothetical function that gets the inference output:
    model_resp = await model(Request)

    response = Response(
        content=model_resp,
        status_code=status.HTTP_200_OK,
        media_type="text/plain",
    )
    return response
. . .
```
이 예시에서 `invocations` 함수는 SageMaker AI가 `/invocations` 엔드포인트로 보내는 추론 요청을 처리합니다.
Flask는 Python으로 웹 애플리케이션을 개발하기 위한 프레임워크입니다.  

```
import flask
. . .
app = flask.Flask(__name__)
. . .
@app.route('/invocations', methods=["POST"])
def invoke(request):
    # model() is a hypothetical function that gets the inference output:
    resp_body = model(request)
    return flask.Response(resp_body, mimetype='text/plain')
```
이 예시에서 `invoke` 함수는 SageMaker AI가 `/invocations` 엔드포인트로 보내는 추론 요청을 처리합니다.

**Example 스트리밍 요청을 위한 호출 함수**  
다음 예제에서는 추론 컨테이너의 코드가 스트리밍 추론 요청을 처리하는 방법을 보여 줍니다. 이 예제는 InvokeEndpointWithResponseStream 작업을 사용하여 클라이언트 애플리케이션이 보내는 요청을 처리합니다.  
컨테이너가 스트리밍 추론 요청을 처리할 때, 컨테이너는 모델의 추론을 모델이 생성함에 따라 점진적으로 일련의 부분으로 반환합니다. 클라이언트 애플리케이션은 응답이 제공되는 즉시 응답을 받기 시작합니다. 모델이 전체 응답을 생성할 때까지 기다릴 필요가 없습니다. 사용자는 스트리밍을 구현하여 챗봇, 가상 어시스턴트, 음악 생성기와 같은 빠른 대화형 환경을 지원할 수 있습니다.  
FastAPI는 Python으로 API를 빌드하기 위한 웹 프레임워크입니다.  

```
from starlette.responses import StreamingResponse
from fastapi import FastAPI, status, Request
. . .
app = FastAPI()
. . .
@app.post('/invocations')
async def invocations(request: Request):
    # Streams inference response using HTTP chunked encoding
    async def generate():
        # model() is a hypothetical function that gets the inference output:
        yield await model(Request)
        yield "\n"

    response = StreamingResponse(
        content=generate(),
        status_code=status.HTTP_200_OK,
        media_type="text/plain",
    )
    return response
. . .
```
이 예시에서 `invocations` 함수는 SageMaker AI가 `/invocations` 엔드포인트로 보내는 추론 요청을 처리합니다. 응답을 스트리밍하기 위해 예제에서는 Starlette 프레임워크의 `StreamingResponse` 클래스를 사용합니다.
Flask는 Python으로 웹 애플리케이션을 개발하기 위한 프레임워크입니다.  

```
import flask
. . .
app = flask.Flask(__name__)
. . .
@app.route('/invocations', methods=["POST"])
def invocations(request):
    # Streams inference response using HTTP chunked encoding

    def generate():
        # model() is a hypothetical function that gets the inference output:
        yield model(request)
        yield "\n"
    return flask.Response(
        flask.stream_with_context(generate()), mimetype='text/plain')
. . .
```
이 예시에서 `invocations` 함수는 SageMaker AI가 `/invocations` 엔드포인트로 보내는 추론 요청을 처리합니다. 응답을 스트리밍하기 위해 예제에서는 Flask 프레임워크의 `flask.stream_with_context` 함수를 사용합니다.

**Example 양방향 스트리밍을 위한 호출 함수 예제**  
다음 예제에서는 컨테이너의 코드가 스트리밍 추론 요청 및 응답을 처리하는 방법을 보여줍니다. 이 예제에서는 InvokeEndpointWithBidirectionalStream 작업을 사용하여 클라이언트 애플리케이션이 보내는 스트리밍 요청을 처리합니다.  
양방향 스트리밍 기능이 있는 컨테이너는 파트가 클라이언트에서 점진적으로 생성되어 컨테이너로 스트리밍되는 스트리밍 추론 요청을 처리합니다. 모델이 생성할 때 모델의 추론을 일련의 부분으로 클라이언트에 다시 반환합니다. 클라이언트 애플리케이션은 응답이 제공되는 즉시 응답을 받기 시작합니다. 클라이언트에서 완전히 생성된에 대한 요청이나 모델이 전체 응답을 생성할 때까지 기다릴 필요가 없습니다. 양방향 스트리밍을 구현하여 챗봇, 대화형 음성 AI 어시스턴트, 실시간 번역과 같은 빠른 대화형 경험을 지원하여 보다 실시간 경험을 제공할 수 있습니다.  
FastAPI는 Python으로 API를 빌드하기 위한 웹 프레임워크입니다.  

```
import sys
import asyncio
import json
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import JSONResponse
import uvicorn

app = FastAPI()
...
@app.websocket("/invocations-bidirectional-stream")
async def websocket_invoke(websocket: WebSocket):
    """
    WebSocket endpoint with RFC 6455 ping/pong and fragmentation support
    
    Handles:
    - Text messages (JSON) - including fragmented frames
    - Binary messages - including fragmented frames
    - Ping frames (automatically responds with pong)
    - Pong frames (logs receipt)
    - Fragmented frames per RFC 6455 Section 5.4
    """
    await manager.connect(websocket)
    
    # Fragment reassembly buffers per RFC 6455 Section 5.4
    text_fragments = []
    binary_fragments = []
    
    while True:
        # Use receive() to handle all WebSocket frame types
        message = await websocket.receive()
        print(f"Received message: {message}")
        if message["type"] == "websocket.receive":
            if "text" in message:
                # Handle text frames (including fragments)
                text_data = message["text"]
                more_body = message.get("more_body", False)
                
                if more_body:
                    # This is a fragment, accumulate it
                    text_fragments.append(text_data)
                    print(f"Received text fragment: {len(text_data)} chars (more coming)")
                else:
                    # This is the final frame or a complete message
                    if text_fragments:
                        # Reassemble fragmented message
                        text_fragments.append(text_data)
                        complete_text = "".join(text_fragments)
                        text_fragments.clear()
                        print(f"Reassembled fragmented text message: {len(complete_text)} chars total")
                        await handle_text_message(websocket, complete_text)
                    else:
                        # Complete message in single frame
                        await handle_text_message(websocket, text_data)
                
            elif "bytes" in message:
                # Handle binary frames (including fragments)
                binary_data = message["bytes"]
                more_body = message.get("more_body", False)
                
                if more_body:
                    # This is a fragment, accumulate it
                    binary_fragments.append(binary_data)
                    print(f"Received binary fragment: {len(binary_data)} bytes (more coming)")
                else:
                    # This is the final frame or a complete message
                    if binary_fragments:
                        # Reassemble fragmented message
                        binary_fragments.append(binary_data)
                        complete_binary = b"".join(binary_fragments)
                        binary_fragments.clear()
                        print(f"Reassembled fragmented binary message: {len(complete_binary)} bytes total")
                        await handle_binary_message(websocket, complete_binary)
                    else:
                        # Complete message in single frame
                        await handle_binary_message(websocket, binary_data)
                
        elif message["type"] == "websocket.ping":
            # Handle ping frames - RFC 6455 Section 5.5.2
            ping_data = message.get("bytes", b"")
            print(f"Received PING frame with payload: {ping_data}")
            # FastAPI automatically sends pong response
            
        elif message["type"] == "websocket.pong":
            # Handle pong frames
            pong_data = message.get("bytes", b"")
            print(f"Received PONG frame with payload: {pong_data}")
            
        elif message["type"] == "websocket.close":
            # Handle close frames - RFC 6455 Section 5.5.1
            close_code = message.get("code", 1000)
            close_reason = message.get("reason", "")
            print(f"Received CLOSE frame - Code: {close_code}, Reason: '{close_reason}'")
            
            # Send close frame response if not already closing
            try:
                await websocket.close(code=close_code, reason=close_reason)
                print(f"Sent CLOSE frame response - Code: {close_code}")
            except Exception as e:
                print(f"Error sending close frame: {e}")
            break
            
        elif message["type"] == "websocket.disconnect":
            print("Client initiated disconnect")
            break

        else:
            print(f"Received unknown message type: {message['type']}")
            break

                        
async def handle_binary_message(websocket: WebSocket, binary_data: bytes):
    """Handle incoming binary messages (complete or reassembled from fragments)"""
    print(f"Processing complete binary message: {len(binary_data)} bytes")
    
    try:
        # Echo back the binary data
        await websocket.send_bytes(binary_data)
    except Exception as e:
        print(f"Error handling binary message: {e}")

async def handle_text_message(websocket: WebSocket, data: str):
    """Handle incoming text messages"""
    try:
        # Send response back to the same client
        await manager.send_personal_message(data, websocket)
    except Exception as e:
        print(f"Error handling text message: {e}")

def main():
    if len(sys.argv) > 1 and sys.argv[1] == "serve":
        print("Starting server on port 8080...")
        uvicorn.run(app, host="0.0.0.0", port=8080)
    else:
        print("Usage: python app.py serve")
        sys.exit(1)

if __name__ == "__main__":
    main()
```
이 예시에서 `websocket_invoke` 함수는 SageMaker AI가 `/invocations-bidirectional-stream` 엔드포인트로 보내는 추론 요청을 처리합니다. 스트림 요청을 처리하고 응답을 클라이언트로 다시 스트리밍하는 방법을 보여줍니다.

## 컨테이너의 상태 확인(핑) 요청 응답 방법
<a name="your-algorithms-inference-algo-ping-requests"></a>

SageMaker AI는 다음과 같은 상황에서 새 추론 컨테이너를 시작합니다.
+ `CreateEndpoint`, `UpdateEndpoint`, `UpdateEndpointWeightsAndCapacities` API 직접 호출에 대한 응답
+ 보안 패치
+ 비정상 인스턴스 대체

컨테이너 시작 이후 SageMaker AI는 주기적으로 `/ping` 엔드포인트로 GET 요청을 전송하기 시작합니다.

컨테이너에 대한 가장 간단한 요구 사항은 HTTP 200 상태 코드 및 비어 있는 본문을 포함하여 응답하는 것입니다. 이는 SageMaker AI에 컨테이너가 `/invocations` 엔드포인트에서 추론 요청을 수락할 준비가 되었는지 표시합니다.

시작 후 8분 동안 지속적으로 200초로 응답하여 컨테이너가 상태 확인을 통과하지 못하면 새 인스턴스 시작이 실패합니다. 이는 `CreateEndpoint`에 장애가 발생하여 엔드포인트가 실패 상태가 되는 원인이 됩니다. `UpdateEndpoint`에서 요청한 업데이트가 완료되지 않고, 보안 패치가 적용되지 않으며, 비정상 인스턴스가 교체되지 않게 됩니다.

최소 기준이 컨테이너가 정적 200을 반환하는 반면 컨테이너 개발자는 이 기능을 사용하여 더욱 자세한 확인을 수행할 수 있습니다. `/ping` 시도의 요청 제한 시간은 2초입니다.

또한 양방향 스트리밍 요청을 처리할 수 있는 컨테이너는 Ping 프레임에 Pong 프레임(WebSocket 프로토콜 [RFC6455](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.3)에 따라)으로 응답해야 합니다. 5회 연속 Ping에 대해 Pong Frame이 수신되지 않으면 SageMaker AI 플랫폼에서 컨테이너에 대한 연결을 닫습니다. SageMaker AI 플랫폼은 Pong Frames를 사용하여 모델 컨테이너의 Ping Frames에도 응답합니다.

## 양방향 스트리밍 기능을 지원하는 컨테이너 계약
<a name="your-algorithms-inference-algo-bidi"></a>

모델 컨테이너를 양방향 스트리밍 기능을 지원하는 SageMaker AI 엔드포인트로 호스팅하려면 모델 컨테이너가 아래 계약을 지원해야 합니다.

**1: 양방향 Docker 레이블 **

모델 컨테이너에는 SageMaker AI 플랫폼에이 컨테이너에서 양방향 스트리밍 기능이 지원됨을 나타내는 Docker 레이블이 있어야 합니다.

```
com.amazonaws.sagemaker.capabilities.bidirectional-streaming=true
```

**2. 호출을 위한 WebSocket 연결 지원**

양방향 스트리밍을 지원하는 고객의 모델 컨테이너는 `/invocations-bidirectional-stream` 기본적으로 포트 8080에서 로의 WebSockets 연결을 지원해야 합니다.

InvokeEndpointWithBidirectionalStream API를 호출할 때 X-Amzn-SageMaker-Model-Invocation-Path 헤더를 전달하여이 경로를 재정의할 수 있습니다. 또한 사용자는 InvokeEndpointWithBidirectionalStream API를 호출할 때 X-Amzn-SageMaker-Model-Query-String 헤더를 전달하여이 경로에 추가할 쿼리 문자열을 지정할 수 있습니다.

**3. 요청 스트림 처리**

InvokeEndpointWithBidirectionalStream API 입력 페이로드는 이진 청크(“바이트”: ***<Blob>***)의 래퍼인 일련의 PayloadParts로 스트리밍됩니다.

```
{
   "PayloadPart": { 
      "Bytes": <Blob>,
      "DataType": <String: UTF8 | BINARY>,
      "CompletionState": <String: PARTIAL | COMPLETE>
      "P": <String>
   }
}
```

**3.1. 데이터 프레임**

SageMaker AI는 입력 PayloadParts를 모델 컨테이너에 WebSocket 데이터 프레임으로 전달합니다([RFC6455-Section-5.6](https://datatracker.ietf.org/doc/html/rfc6455#section-5.6)).

1. SageMaker AI는 바이너리 청크를 검사하지 않습니다.

1. 입력 PayloadPart 수신 시
   + SageMaker AI는에서 정확히 하나의 WebSocket 데이터 프레임을 생성한 `PayloadPart.Bytes`다음 모델 컨테이너에 전달합니다.
   + `PayloadPart.DataType = UTF8`인 경우 SageMaker AI는 텍스트 데이터 프레임을 생성합니다.
   + `PayloadPart.DataType`에 또는이 없는 경우 `PayloadPart.DataType = BINARY` SageMaker AI는 바이너리 데이터 프레임을 생성합니다.

1. 를 사용하는 PayloadParts 시퀀스`PayloadPart.CompletionState = PARTIAL`에서를 사용하는 PayloadParts로 종료되는 경우 `PayloadPart.CompletionState = COMPLETE` SageMaker AI는 이를 WebSocket 조각화된 메시지 [RFC6455-Section-5.4: 조각화](https://datatracker.ietf.org/doc/html/rfc6455#section-5.4):
   + 를 사용하는 초기 PayloadPart`PayloadPart.CompletionState = PARTIAL`는 FIN 비트가 지워진 WebSocket 데이터 프레임으로 변환됩니다.
   + 를 사용하는 후속 PayloadParts`PayloadPart.CompletionState = PARTIAL`는 FIN 비트가 지워진 WebSocket 연속 프레임으로 변환됩니다.
   + 를 사용하는 최종 PayloadPart`PayloadPart.CompletionState = COMPLETE`는 FIN 비트가 설정된 WebSocket 연속 프레임으로 변환됩니다.

1. SageMaker AI는 입력 PayloadPart에서 바이너리 청크를 인코딩하거나 디코딩하지 않으며, 바이트는 모델 컨테이너에 있는 그대로 전달됩니다.

1. SageMaker AI는 여러 입력 PayloadParts를 하나의 BinaryDataFrame으로 결합하지 않습니다.

1. SageMaker AI는 하나의 입력 PayloadPart를 여러 BinaryDataFrames로 청크하지 않습니다.

**예: 조각화된 메시지 흐름**

```
Client sends:
PayloadPart 1: {Bytes: "Hello ", DataType: "UTF8", CompletionState: "PARTIAL"}
PayloadPart 2: {Bytes: "World", DataType: "UTF8", CompletionState: "COMPLETE"}

Container receives:
Frame 1: Text Data Frame with "Hello " (FIN=0)
Frame 2: Continuation Frame with "World" (FIN=1)
```

**3.2. 프레임 제어**

SageMaker AI는 데이터 프레임 외에도 제어 프레임을 모델 컨테이너로 전송합니다([RFC6455-Section-5.5](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5)).

1. 닫기 프레임: SageMaker AI는 어떤 이유로든 연결이 닫힐 경우 닫기 프레임([RFC6455-Section-5.5.1](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.1))을 모델 컨테이너로 전송할 수 있습니다.

1. Ping Frame: SageMaker AI는 [60초마다 한 번씩 Ping Frame(RFC6455-Section-5.5.2](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.2))을 전송합니다. 모델 컨테이너는 Pong Frame으로 응답해야 합니다. 5개의 연속 Ping에 대해 Pong Frame([RFC6455-Section-5.5.3](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.3))이 수신되지 않으면 SageMaker AI에 의해 연결이 종료됩니다.

1. Pong Frame: SageMaker AI는 Pong Frames를 사용하여 모델 컨테이너의 Ping Frames에 응답합니다.

**4. 응답 스트림 처리**

출력은 일련의 PayloadParts, ModelStreamErrors 또는 InternalStreamFailures.

```
{   
   "PayloadPart": { 
      "Bytes": <Blob>,
      "DataType": <String: UTF8 | BINARY>,
      "CompletionState": <String: PARTIAL | COMPLETE>,
   },
   "ModelStreamError": {
      "ErrorCode": <String>,
      "Message": <String>
   },
   "InternalStreamFailure": {
      "Message": <String>
   }
}
```

**4.1. 데이터 프레임**

SageMaker AI는 모델 컨테이너에서 수신한 데이터 프레임을 출력 PayloadParts.

1. 모델 컨테이너에서 WebSocket 텍스트 데이터 프레임을 수신하면 SageMaker AI는 텍스트 데이터 프레임에서 원시 바이트를 가져와서 PayloadPart 응답으로 래핑합니다`PayloadPart.DataType = UTF8`.

1. 모델 컨테이너에서 WebSocket 바이너리 데이터 프레임을 수신하면 SageMaker AI는 데이터 프레임의 바이트를 PayloadPart 응답으로 직접 래핑하는 동시에를 설정합니다`PayloadPart.DataType = BINARY`.

1. [RFC6455-Section-5.4: Fragmentation](https://datatracker.ietf.org/doc/html/rfc6455#section-5.4)에 정의된 조각화된 메시지의 경우:
   + FIN 비트가 지워진 초기 데이터 프레임은가 있는 PayloadPart로 변환됩니다`PayloadPart.CompletionState = PARTIAL`.
   + FIN 비트가 지워진 후속 연속 프레임은를 사용하여 PayloadParts로 변환됩니다`PayloadPart.CompletionState = PARTIAL`.
   + FIN 비트가 설정된 최종 연속 프레임은를 사용하여 PayloadPart로 변환됩니다`PayloadPart.CompletionState = COMPLETE`.

1. SageMaker AI는 모델 컨테이너에서 수신한 바이트를 인코딩하거나 디코딩하지 않으며, 바이트는 모델 컨테이너에 있는 그대로 전달됩니다.

1. SageMaker AI는 모델 컨테이너에서 수신한 여러 데이터 프레임을 하나의 응답 PayloadPart로 결합하지 않습니다.

1. SageMaker AI는 모델 컨테이너에서 수신한 데이터 프레임을 여러 응답 PayloadParts로 청크하지 않습니다.

**예: 스트리밍 응답 흐름**

```
Container sends:
Frame 1: Text Data Frame with "Generating" (FIN=0)
Frame 2: Continuation Frame with " response..." (FIN=1)

Client receives:
PayloadPart 1: {Bytes: "Generating", DataType: "UTF8", CompletionState: "PARTIAL"}
PayloadPart 2: {Bytes: " response...", DataType: "UTF8", CompletionState: "COMPLETE"}
```

**4.2. 프레임 제어**

SageMaker AI는 모델 컨테이너에서 다음 제어 프레임에 응답합니다.

1. 모델 컨테이너에서 닫기 프레임([RFC6455-Section-5.5.1](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.1))을 수신하면 SageMaker AI는 상태 코드([RFC6455-Section-7.4](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4))와 실패 메시지를 ModelStreamError로 래핑하고 최종 사용자에게 다시 스트리밍합니다.

1. 모델 컨테이너에서 Ping 프레임([RFC6455-Section-5.5.2](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.2))을 수신하면 SageMaker AI는 Pong Frame으로 응답합니다.

1. Pong Frame([RFC6455-Section-5.5.3](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.3)): 5회 연속 Ping에 대해 Pong Frame이 수신되지 않으면 SageMaker AI에 의해 연결이 종료됩니다.

# 실시간 추론 컨테이너에 대한 프라이빗 Docker 레지스트리 사용
<a name="your-algorithms-containers-inference-private"></a>

Amazon SageMaker AI 호스팅을 이용하면 Amazon ECR에 저장된 이미지를 사용하여 실시간 추론용 컨테이너를 기본적으로 빌드할 수 있습니다. 사용자는 프라이빗 Docker 레지스트리에 있는 이미지를 통해 실시간 추론용 컨테이너를 선택적으로 빌드할 수 있습니다. 프라이빗 레지스트리는 사용자 계정의 Amazon VPC에서 액세스할 수 있어야 합니다. 프라이빗 Docker 레지스트리에 저장된 이미지를 기준으로 생성하는 모델은 프라이빗 Docker 레지스트리에 액세스할 수 있는 동일한 VPC에 연결되도록 구성해야 합니다. 모델을 VPC에 연결하는 방법에 대한 자세한 내용은 [SageMaker AI에서 호스팅된 엔드포인트에 Amazon VPC의 리소스에 대한 액세스 권한 부여](host-vpc.md)을(를) 참조하세요.

Docker 레지스트리는 알려진 퍼블릭 인증 기관(CA)의 TLS 인증서로 보호해야 합니다.

**참고**  
프라이빗 Docker 레지스트리는 SageMaker AI 호스팅이 레지스트리에서 모델 이미지를 가져올 수 있도록 모델의 VPC 구성에 지정된 보안 그룹의 인바운드 트래픽을 허용해야 합니다.  
VPC 내부의 개방형 인터넷에 접속할 수 있는 경로가 있는 경우, SageMaker AI가 DockerHub로부터 모델 이미지를 가져올 수 있습니다.

**Topics**
+ [Amazon Elastic 컨테이너 레지스트리를 제외한 프라이빗 Docker 레지스트리에 이미지를 저장하세요.](#your-algorithms-containers-inference-private-registry)
+ [실시간 추론을 위해 프라이빗 Docker 레지스트리의 이미지를 사용하세요.](#your-algorithms-containers-inference-private-use)
+ [SageMaker AI가 프라이빗 Docker 레지스트리에 인증하도록 허용](#inference-private-docker-authenticate)
+ [Lambda 함수 생성](#inference-private-docker-lambda)
+ [Lambda에 대한 실행 역할 권한 부여](#inference-private-docker-perms)
+ [Lambda용 인터페이스 VPC 엔드포인트 생성](#inference-private-docker-vpc-interface)

## Amazon Elastic 컨테이너 레지스트리를 제외한 프라이빗 Docker 레지스트리에 이미지를 저장하세요.
<a name="your-algorithms-containers-inference-private-registry"></a>

프라이빗 Docker 레지스트리를 사용하여 SageMaker AI 실시간 추론에 필요한 이미지를 저장하려면 Amazon VPC에서 액세스할 수 있는 프라이빗 레지스트리를 생성하세요. Docker 레지스트리 생성 방법에 대한 자세한 내용은 Docker 설명서의 [레지스트리 서버 배포](https://docs.docker.com/registry/deploying/)를 참조하세요. Docker 레지스트리는 다음 사항을 준수해야 합니다.
+ 이 레지스트리는 [Docker 레지스트리 HTTP API V2](https://docs.docker.com/registry/spec/api/) 레지스트리여야 합니다.
+ Docker 레지스트리는 모델 생성 시 지정된 `VpcConfig` 파라미터에 지정한 것과 동일한 VPC에서 액세스할 수 있어야 합니다.

## 실시간 추론을 위해 프라이빗 Docker 레지스트리의 이미지를 사용하세요.
<a name="your-algorithms-containers-inference-private-use"></a>

모델을 생성하여 SageMaker AI 호스팅에 배포할 경우, 사용자는 해당 모델이 프라이빗 Docker 레지스트리의 이미지를 사용하여 추론 컨테이너를 빌드하도록 지정할 수 있습니다. 이를 [create\$1model](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.create_model) 함수 호출에 전달하는 `PrimaryContainer` 파라미터의 `ImageConfig` 객체에 지정하세요.

**프라이빗 Docker 레지스트리에 저장된 이미지를 추론 컨테이너에 사용하려면**

1. 이미지 구성 객체를 생성하고 `RepositoryAccessMode` 필드의 값을 `Vpc`(으)로 지정하세요.

   ```
   image_config = {
                       'RepositoryAccessMode': 'Vpc'
                  }
   ```

1. 프라이빗 Docker 레지스트리에 인증이 필요한 경우 이미지 구성 객체에 `RepositoryAuthConfig` 객체를 추가하세요. `RepositoryAuthConfig` 객체의 `RepositoryCredentialsProviderArn` 필드에 SageMaker AI가 프라이빗 Docker 레지스트리에 인증할 수 있는 자격 증명을 제공하는 AWS Lambda 함수의 Amazon 리소스 이름(ARN)을 지정합니다. 인증을 제공하는 Lambda 함수를 생성하는 방법에 대한 자세한 내용은 [SageMaker AI가 프라이빗 Docker 레지스트리에 인증하도록 허용](#inference-private-docker-authenticate)을(를) 참조하세요.

   ```
   image_config = {
                       'RepositoryAccessMode': 'Vpc',
                       'RepositoryAuthConfig': {
                          'RepositoryCredentialsProviderArn': 'arn:aws:lambda:Region:Acct:function:FunctionName'
                        }
                  }
   ```

1. 이전 단계에서 생성한 이미지 구성 객체를 사용하여 `create_model`에 전달할 기본 컨테이너 객체를 생성하세요.

   이미지를 [다이제스트](https://docs.docker.com/engine/reference/commandline/pull/#pull-an-image-by-digest-immutable-identifier) 양식으로 제공하세요. `:latest` 태그를 사용하여 이미지를 제공할 경우, SageMaker AI가 의도된 것보다 새로운 버전의 이미지를 가져올 위험이 있습니다. 다이제스트 양식을 사용하면 SageMaker AI가 의도된 이미지 버전을 가져오게 됩니다.

   ```
   primary_container = {
       'ContainerHostname': 'ModelContainer',
       'Image': 'myteam.myorg.com/docker-local/my-inference-image:<IMAGE-TAG>',
       'ImageConfig': image_config
   }
   ```

1. `create_model`에 전달할 모델 이름과 실행 역할을 지정하세요.

   ```
   model_name = 'vpc-model'
   execution_role_arn = 'arn:aws:iam::123456789012:role/SageMakerExecutionRole'
   ```

1. 모델의 VPC 구성에 사용할 보안 그룹과 서브넷을 하나 이상 지정하세요. 프라이빗 Docker 레지스트리는 지정된 보안 그룹의 인바운드 트래픽을 허용해야 합니다. 지정된 서브넷은 프라이빗 Docker 레지스트리와 동일한 VPC에 있어야 합니다.

   ```
   vpc_config = {
       'SecurityGroupIds': ['sg-0123456789abcdef0'],
       'Subnets': ['subnet-0123456789abcdef0','subnet-0123456789abcdef1']
   }
   ```

1. Boto3 SageMaker AI 클라이언트를 확보하세요.

   ```
   import boto3
   sm = boto3.client('sagemaker')
   ```

1. `PrimaryContainer` 및 `VpcConfig` 파라미터에 대해 이전 단계에서 지정한 값을 이용해 `create_model`을(를) 호출하여 모델을 생성하세요.

   ```
   try:
       resp = sm.create_model(
           ModelName=model_name,
           PrimaryContainer=primary_container,
           ExecutionRoleArn=execution_role_arn,
           VpcConfig=vpc_config,
       )
   except Exception as e:
       print(f'error calling CreateModel operation: {e}')
   else:
       print(resp)
   ```

1. 마지막으로, 이전 단계에서 [생성한 모델을 이용하여 create\$1endpoint\$1config](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.create_endpoint_config) 및 [create\$1endpoint](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.create_endpoint)를 호출하여 호스팅 엔드포인트를 생성하세요.

   ```
   endpoint_config_name = 'my-endpoint-config'
   sm.create_endpoint_config(
       EndpointConfigName=endpoint_config_name,
       ProductionVariants=[
           {
               'VariantName': 'MyVariant',
               'ModelName': model_name,
               'InitialInstanceCount': 1,
               'InstanceType': 'ml.t2.medium'
           },
       ],
   )
   
   endpoint_name = 'my-endpoint'
   sm.create_endpoint(
       EndpointName=endpoint_name,
       EndpointConfigName=endpoint_config_name,
   )
   
   sm.describe_endpoint(EndpointName=endpoint_name)
   ```

## SageMaker AI가 프라이빗 Docker 레지스트리에 인증하도록 허용
<a name="inference-private-docker-authenticate"></a>

인증이 필요한 프라이빗 Docker 레지스트리에서 추론 이미지를 가져오려면 자격 증명을 제공하는 AWS Lambda 함수를 생성하고 [create\$1model](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.create_model)을 호출할 때 Lambda 함수의 Amazon 리소스 이름(ARN)을 제공합니다. SageMaker AI가 실행하는 `create_model`은 지정한 Lambda 함수를 직접적으로 호출하여 Docker 레지스트리 인증을 위한 자격 증명을 가져옵니다.

## Lambda 함수 생성
<a name="inference-private-docker-lambda"></a>

다음 형식으로 응답을 반환하는 AWS Lambda 함수를 생성합니다.

```
def handler(event, context):
   response = {
      "Credentials": {"Username": "username", "Password": "password"}
   }
   return response
```

프라이빗 Docker 레지스트리에 대한 인증을 설정하는 방법에 따라, Lambda 함수가 반환하는 자격 증명의 의미가 다음 중 하나가 될 수 있습니다.
+ 기본 인증을 사용하도록 프라이빗 Docker 레지스트리를 설정할 경우 레지스트리 인증에 필요한 로그인 자격 증명을 제공하세요.
+ 베어러 토큰 인증을 사용하도록 프라이빗 Docker 레지스트리를 설정하면 로그인 자격 증명이 인증 서버로 전송됩니다. 이 인증 서버는 베어러 토큰을 반환하는데, 이 토큰은 프라이빗 Docker 레지스트리 인증에 사용할 수 있습니다.

## Lambda에 대한 실행 역할 권한 부여
<a name="inference-private-docker-perms"></a>

호출에 사용하는 실행 역할에는 AWS Lambda 함수를 호출할 수 있는 권한이 `create_model` 있어야 합니다. 실행 역할의 권한 정책에 다음 사항을 추가하세요.

```
{
    "Effect": "Allow",
    "Action": [
        "lambda:InvokeFunction"
    ],
    "Resource": [
        "arn:aws:lambda:*:*:function:*myLambdaFunction*"
    ]
}
```

여기서 *myLambdaFunction*은 Lambda 함수의 이름입니다. 역할 권한 정책을 편집하는 방법에 대한 자세한 내용은 *AWS Identity and Access Management 사용 설명서*의 [역할 권한 정책(콘솔) 수정](https://docs.aws.amazon.com/IAM/latest/UserGuide/roles-managingrole-editing-console.html#roles-modify_permissions-policy)을 참조하세요.

**참고**  
`AmazonSageMakerFullAccess` 관리형 정책과 연결된 실행 역할에는 그 이름으로 **SageMaker**를 이용해 Lambda 함수를 호출할 권한이 있습니다.

## Lambda용 인터페이스 VPC 엔드포인트 생성
<a name="inference-private-docker-vpc-interface"></a>

Amazon VPC가 인터넷을 통해 트래픽을 전송하지 않고도 AWS Lambda 함수와 통신할 수 있도록 인터페이스 엔드포인트를 생성하세요. 이를 수행하는 방법에 대한 자세한 내용은 *AWS Lambda 개발자 안내서*의 [Lambda용 인터페이스 VPC 엔드포인트 구성](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc-endpoints.html)을 참조하세요.

SageMaker AI 호스팅은 VPC를 통해 요청을 `lambda.region.amazonaws.com`으로 전송하여 Lambda 함수를 직접적으로 호출합니다. 인터페이스 엔드포인트 생성 시 프라이빗 DNS 이름을 선택하면 Amazon Route 53이 Lambda 인터페이스 엔드포인트로 호출을 라우팅합니다. 다른 DNS 공급자를 사용할 경우에는 Lambda 인터페이스 엔드포인트에 `lambda.region.amazonaws.com`을(를) 매핑해야 합니다.

# 배치 변환을 사용한 사용자 지정 추론 코드
<a name="your-algorithms-batch-code"></a>

이 섹션에서는 배치 작업을 위한 자체 추론 코드를 실행하는 Docker 컨테이너와 Amazon SageMaker AI가 상호 작용하는 방법을 설명합니다. 이 정보를 사용하여 추론 코드를 작성하고 Docker 이미지를 생성합니다.

**Topics**
+ [SageMaker AI가 추론 이미지를 실행하는 방법](#your-algorithms-batch-code-run-image)
+ [SageMaker AI가 모델 아티팩트를 로드하는 방법](#your-algorithms-batch-code-load-artifacts)
+ [컨테이너의 요청 처리 방법](#your-algorithms-batch-code-how-containe-serves-requests)
+ [컨테이너의 추론 요청 응답 방법](#your-algorithms-batch-code-how-containers-should-respond-to-inferences)
+ [컨테이너의 상태 확인(핑) 요청 응답 방법](#your-algorithms-batch-algo-ping-requests)

## SageMaker AI가 추론 이미지를 실행하는 방법
<a name="your-algorithms-batch-code-run-image"></a>

컨테이너를 실행 파일로 실행하도록 구성하려면 Dockerfile에서 `ENTRYPOINT` 지침을 사용합니다. 다음 사항에 유의하세요.
+ 배치 변환의 경우 SageMaker AI는 사용자를 대신하여 모델을 간접적으로 호출합니다. SageMaker AI는 컨테이너를 다음과 같이 실행합니다.

  ```
  docker run image serve
  ```

  일괄 변환에 대한 입력은 작은 파일로 분할하여 병렬로 처리할 수 있는 형식이어야 합니다. 이러한 형식에는 CSV, [JSON](https://www.json.org/json-en.html), [JSON Lines](https://jsonlines.org/), [TFRecord](https://www.tensorflow.org/tutorials/load_data/tfrecord), [RecordIO](https://mesos.apache.org/documentation/latest/recordio/)가 포함됩니다.

  SageMaker AI는 이미지 이름 뒤에 `serve` 인수를 지정함으로써 컨테이너에 있는 기본 `CMD` 문을 재정의합니다. `serve` 인수는 또한 Dockerfile에서 `CMD` 명령을 사용하여 입력한 인수 또한 재정의합니다.

   
+ `exec` 지침의 `ENTRYPOINT` 양식을 사용하는 것이 좋습니다.

  ```
  ENTRYPOINT ["executable", "param1", "param2"]
  ```

  예제:

  ```
  ENTRYPOINT ["python", "k_means_inference.py"]
  ```

   
+ SageMaker AI는 컨테이너의 [https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateModel.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateModel.html) 및 [https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateTransformJob.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateTransformJob.html)에 지정된 환경 변수를 설정합니다. 또한 다음 환경 변수가 채워집니다.
  + `SAGEMAKER_BATCH`는 배치 변환에서 컨테이너가 실행될 때 `true`로 설정됩니다.
  + `SAGEMAKER_MAX_PAYLOAD_IN_MB`는 HTTP를 통해 컨테이너로 전송될 크기가 가장 큰 페이로드로 설정됩니다.
  + `SAGEMAKER_BATCH_STRATEGY`는 컨테이너가 호출당 단일 레코드를 받을 때는 `SINGLE_RECORD`로, 컨테이너가 페이로드에 맞는 대로 많은 수의 레코드를 받을 때는 `MULTI_RECORD`로 설정됩니다.
  + `SAGEMAKER_MAX_CONCURRENT_TRANSFORMS`는 동시에 열 수 있는 최대 `/invocations` 요청 수로 설정됩니다.
**참고**  
마지막 환경 변수 3개는 사용자가 생성한 API 직접 호출에서 가져옵니다. 사용자가 이러한 환경 변수의 값을 설정하지 않은 경우에는 해당 환경 변수가 전달되지 않습니다. 이러한 경우 기본값 또는 (`/execution-parameters`에 대한 응답으로) 알고리즘에서 요청한 값이 사용됩니다.
+ (`CreateTransformJob` 요청에 GPU 기반 ML 컴퓨팅 인스턴스를 지정하여) 모델 추론에 GPU 디바이스를 사용하려는 경우 컨테이너가 nvidia-docker와 호환 가능한지 확인해야 합니다. 이미지가 포함된 NVIDIA 드라이버를 번들화하지 마세요. nvidia-docker에 대한 추가 정보는 [NVIDIA/nvidia-docker](https://github.com/NVIDIA/nvidia-docker)를 참조하세요.

   
+ SageMaker AI 컨테이너의 진입점으로 `init` 이니셜라이저를 사용할 수 없습니다. 훈련 및 서비스 인수로 인해 혼동되기 때문입니다.

  

## SageMaker AI가 모델 아티팩트를 로드하는 방법
<a name="your-algorithms-batch-code-load-artifacts"></a>

[https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateModel.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateModel.html) 요청에서 컨테이너 정의는 `ModelDataUrl` 파라미터를 포함하며, 이 파라미터는 모델 아티팩트가 저장되는 Amazon S3의 위치를 식별합니다. SageMaker AI를 사용하여 추론을 실행할 경우 이 정보를 사용하여 모델 아티팩트를 복사해 오는 위치가 결정됩니다. 결과물은 추론 코드에서 사용할 Docker 컨테이너의 `/opt/ml/model` 디렉터리에 복사됩니다.

`ModelDataUrl` 파라미터는 tar.gz 파일을 가리켜야 합니다. 그렇지 않으면 SageMaker AI가 해당 파일을 다운로드할 수 없습니다. SageMaker AI에서 모델을 훈련할 경우 아티팩트는 하나의 tar 파일로 Amazon S3에 저장됩니다. 다른 프레임워크에서 모델을 훈련시키는 경우 Amazon S3에 모델 아티팩트를 압축된 tar 파일로 저장해야 합니다. SageMaker AI는 배치 변환 작업이 시작되기 전에 이 tar 파일의 압축을 풀고 컨테이너의 `/opt/ml/model` 디렉터리에 저장합니다.

## 컨테이너의 요청 처리 방법
<a name="your-algorithms-batch-code-how-containe-serves-requests"></a>

컨테이너는 포트 8080에서 호출 및 ping 요청에 응답하는 웹 서버를 구현해야 합니다. 배치 변환의 경우, execution-parameters 요청을 구현하는 알고리즘을 설정하여 SageMaker AI에 동적 런타임 구성을 제공할 수 있습니다. SageMaker AI는 다음과 같은 엔드포인트를 사용합니다.
+ `ping`-컨테이너의 상태를 주기적으로 확인하는 데 사용됩니다. SageMaker AI는 간접 호출 요청을 보내기 전에 성공적인 ping 요청을 위한 HTTP `200` 상태 코드와 빈 본문을 기다립니다. 호출 요청을 보낼 때 ping 요청을 사용하여 모델을 메모리에 로드함으로써 추론을 생성할 수도 있습니다.
+ (선택 사항) `execution-parameters`-런타임 중 알고리즘이 작업에 대한 최적의 튜닝 파라미터를 제공하도록 허용합니다. 알고리즘은 컨테이너에 사용 가능한 메모리 및 CPU를 기반으로 작업에 적합한 `MaxConcurrentTransforms`, `BatchStrategy`, `MaxPayloadInMB` 값을 선택합니다.

간접 호출 요청을 요구하기 전에 SageMaker AI는 execution-parameters 요청을 불러오기 위해 시도합니다. 일괄 변환 작업을 생성할 때 `MaxConcurrentTransforms`, `BatchStrategy`, `MaxPayloadInMB` 사용자는 파라미터의 값을 제공할 수 있습니다. SageMaker AI는 다음과 같은 우선 순위를 사용하여 이러한 파라미터의 값을 결정합니다.

1. `CreateTransformJob` 요청을 생성할 때 제공한 파라미터 값.

1. SageMaker AI가 execution-parameters 엔드포인트를 간접적으로 호출할 때 모델 컨테이너가 반환하는 값>

1. 기본 파라미터 값(다음 표 참조).    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/sagemaker/latest/dg/your-algorithms-batch-code.html)

`GET` execution-parameters 요청에 대한 응답은 JSON 객체와 `MaxConcurrentTransforms`, `BatchStrategy`, `MaxPayloadInMB` 파라미터에 대한 키입니다. 다음은 유효한 응답의 예입니다.

```
{
“MaxConcurrentTransforms”: 8,
“BatchStrategy": "MULTI_RECORD",
"MaxPayloadInMB": 6
}
```

## 컨테이너의 추론 요청 응답 방법
<a name="your-algorithms-batch-code-how-containers-should-respond-to-inferences"></a>

추론을 얻기 위해 Amazon SageMaker AI는 추론 컨테이너에 POST 요청을 보냅니다. POST 요청 본문에는 Amazon S3의 데이터가 포함되어 있습니다. Amazon SageMaker AI는 요청을 컨테이너에 전달하고 컨테이너에서 추론 결과를 반환하여 응답의 데이터를 Amazon S3에 저장합니다.

추론 요청을 수신하려면 컨테이너에 포트 8080에서 수신하는 웹 서버가 있어야 하고 `/invocations` 엔드포인트에 대한 POST 요청을 수락해야 합니다. `[ModelClientConfig](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_ModelClientConfig.html)`를 통해 추론 요청 제한 시간 및 최대 재시도 횟수를 구성할 수 있습니다.

## 컨테이너의 상태 확인(핑) 요청 응답 방법
<a name="your-algorithms-batch-algo-ping-requests"></a>

컨테이너에 대한 가장 간단한 요구 사항은 HTTP 200 상태 코드 및 비어 있는 본문을 포함하여 응답하는 것입니다. 이는 SageMaker AI에 컨테이너가 `/invocations` 엔드포인트에서 추론 요청을 수락할 준비가 되었는지 표시합니다.

최소 기준이 컨테이너가 정적 200을 반환하는 반면 컨테이너 개발자는 이 기능을 사용하여 더욱 자세한 확인을 수행할 수 있습니다. `/ping` 시도의 요청 제한 시간은 2초입니다.