> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 샌드박스 설정

> 샌드박스 리소스, 이미지, 네트워킹, timeout, 저장소를 설정합니다.

이 예시에서는 `CWSANDBOX_API_KEY`에 설정된 CoreWeave API 액세스 토큰을 사용합니다. Forge API 키 인증은 [시작하기](/ko/products/sandboxes/get-started)를 참조하세요. CKS 요구 사항은 [배치 모드](/ko/products/sandboxes/placement)를 참조하세요.

이 가이드는 리소스, 마운트된 파일, 포트, 어노테이션, timeout을 포함한 샌드박스 설정 옵션을 다룹니다. 워크로드의 요구 사항에 맞게 샌드박스의 런타임 환경을 조정해야 할 때(예: GPU 용량 예약, 서비스 노출, 오퍼레이션 timeout 설정) 레퍼런스로 사용하세요.

이 페이지는 `cwsandbox` Python SDK를 사용하여 샌드박스를 시작하고 관리하는 개발자를 위한 것입니다.

<h2 id="overview">
  개요
</h2>

샌드박스 설정은 세 곳에서 지정할 수 있으며, 범위가 가장 넓은 것부터 가장 구체적인 것 순으로 나열하면 다음과 같습니다.

* **SandboxDefaults**: 세션 내 모든 샌드박스에 공통으로 적용되는 기본값입니다.
* **Sandbox.run() kwargs**: 샌드박스별로 기본값을 재정의합니다.
* **@session.function() kwargs**: 함수별 설정입니다.

```python theme={"system"}
from cwsandbox import ResourceOptions, Sandbox, SandboxDefaults, Session

# SandboxDefaults를 통해
defaults = SandboxDefaults(
    container_image="python:3.11",
    max_lifetime_seconds=3600,
    resources=ResourceOptions(
        requests={"cpu": "2", "memory": "2Gi"},
        limits={"cpu": "2", "memory": "2Gi"},
    ),
)

# Sandbox.run() kwargs를 통해
sandbox = Sandbox.run(
    defaults=defaults,
    resources=ResourceOptions(
        requests={"cpu": "4", "memory": "4Gi"},
        limits={"cpu": "4", "memory": "4Gi"},
    ),
)

# @session.function() kwargs를 통해
with Session(defaults) as session:
    @session.function(resources={"cpu": "1", "memory": "1Gi"})
    def compute(x: int) -> int:
        return x * 2
```

다음 섹션에서는 각 설정 영역을 상세히 설명합니다.

<h2 id="resources">
  리소스
</h2>

`ResourceOptions` dataclass 또는 plain dict를 사용하여 CPU, 메모리, GPU 리소스를 설정하세요. Serverless는 기본 배치 모드이며 동일한 requests와 limits를 사용합니다. requests와 limits가 다른 경우, 이를 허용하는 policy를 가진 러너와 함께 [CKS 배치](#burstable-qos)를 사용하세요.

다음 예시에서는 동일한 requests와 limits를 사용합니다:

```python theme={"system"}
from cwsandbox import ResourceOptions, Sandbox

# ResourceOptions 사용
sandbox = Sandbox.run(
    resources=ResourceOptions(
        requests={"cpu": "2", "memory": "2Gi"},
        limits={"cpu": "2", "memory": "2Gi"},
    ),
)

# dict 사용
sandbox = Sandbox.run(
    resources={
        "requests": {"cpu": "2", "memory": "2Gi"},
        "limits": {"cpu": "2", "memory": "2Gi"},
    },
)
```

두 형식은 동일합니다: SDK는 내부적으로 dict를 `ResourceOptions`로 자동 변환합니다.

`ResourceOptions`는 리소스 요청과 limits를 분리합니다. 요청은 스케줄러에게 샌드박스가 필요한 것을 알려줍니다. limits는 사용할 수 있는 최대치를 설정합니다. Kubernetes가 요청과 limits를 사용하여 [Quality of Service classes](https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/)를 부여하는 방법에 대한 배경 지식은 Kubernetes 문서를 참조하세요.

<h3 id="resourceoptions-fields">
  ResourceOptions 필드
</h3>

| 필드 | 유형 | 설명 |
| - | - | - |
| `requests` | `dict[str, str] \| None` | 스케줄링을 위한 CPU 및 메모리 요청량(예: `{"cpu": "500m", "memory": "512Mi"}`). |
| `limits` | `dict[str, str] \| None` | 샌드박스가 초과할 수 없는 CPU 및 메모리 제한(예: `{"cpu": "2", "memory": "2Gi"}`). |
| `gpu` | `dict[str, Any] \| None` | GPU 설정(예: `{"count": 1, "type": "H100"}`). |

클라이언트에서는 모든 필드가 선택이며 기본값은 `None`입니다. 최종 확정된 할당은 적용되는 정책을 충족해야 합니다. 리소스 할당을 생략하면 해당 정책에 정의된 완전한 양수 CPU 및 메모리 기본값이 요청량과 제한으로 모두 사용됩니다.

<h3 id="guaranteed-qos">
  Guaranteed QoS
</h3>

요청량과 제한이 같을 때, 샌드박스는 Guaranteed Quality of Service 클래스를 받습니다. 스케줄러는 할당량 전체를 예약하며, 노드 리소스가 부족해지면 Kubernetes는 Guaranteed 파드를 가장 마지막에 축출합니다. 다만 제한보다 많은 CPU를 사용하려는 샌드박스는 이 경우에도 스로틀링됩니다. 지연 시간에 민감한 워크로드에 사용하세요.

```python theme={"system"}
sandbox = Sandbox.run(
    resources=ResourceOptions(
        requests={"cpu": "2", "memory": "4Gi"},
        limits={"cpu": "2", "memory": "4Gi"},
    ),
)
```

Guaranteed QoS의 경우 평면 dict 단축 표현이 사용 가능합니다. SDK는 요청량과 제한을 모두 동일한 값으로 설정하여 평면 dict를 정규화합니다.

```python theme={"system"}
# Flat dict shorthand: requests와 limits가 동일한 값으로 설정됩니다
sandbox = Sandbox.run(
    resources={"cpu": "2", "memory": "4Gi"},
)
```

<h3 id="burstable-qos">
  Burstable QoS
</h3>

CKS 러너의 정책이 요청량과 제한을 다르게 허용하는 경우, 낮은 요청량은 샌드박스에 Burstable Quality of Service 클래스를 부여합니다. 낮은 요청량을 사용하면 스케줄러가 더 많은 샌드박스를 bin-pack할 수 있지만, 각 샌드박스는 용량이 사용 가능하다면 limit까지 burst할 수 있습니다.

[자체 컴퓨팅 사용](/ko/products/sandboxes/get-started-cks)을 완료하고 `CWSANDBOX_API_KEY`를 CoreWeave API 액세스 토큰으로 설정하세요. `[RUNNER-ID]`를 요청량과 제한을 허용하는 CKS 러너의 ID로 교체하세요:

```python theme={"system"}
from cwsandbox import AuthStrategy, ResourceOptions, Sandbox

sandbox = Sandbox.run(
    auth=AuthStrategy.COREWEAVE_API_KEY,
    placement_mode="cks",
    runner_ids=["[RUNNER-ID]"],
    resources=ResourceOptions(
        requests={"cpu": "500m", "memory": "512Mi"},
        limits={"cpu": "4", "memory": "4Gi"},
    ),
)
```

<h3 id="cpu-values">
  CPU 값
</h3>

CPU를 밀리코어 또는 전체 코어 단위로 지정하세요. 자세한 내용은 [Kubernetes의 리소스 단위](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes)를 참조하세요.

| 값 | 의미 |
| - | - |
| `"100m"` | 100 밀리코어 (0.1 CPU) |
| `"500m"` | 500 밀리코어 (0.5 CPU) |
| `"1000m"` 또는 `"1"` | 1 전체 CPU 코어 |
| `"2000m"` 또는 `"2"` | 2 CPU 코어 |

<h3 id="memory-values">
  메모리 값
</h3>

메모리는 표준 [Kubernetes 메모리 단위](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-memory)를 사용합니다:

| 값 | 의미 |
| - | - |
| `"128Mi"` | 128 mebibytes |
| `"512Mi"` | 512 mebibytes |
| `"1Gi"` | 1 gibibyte |
| `"4Gi"` | 4 gibibytes |

<h3 id="gpu">
  GPU
</h3>

CPU 및 메모리와 함께 GPU 리소스를 요청하세요. GPU 요청은 GPU만 예약하므로 CPU와 메모리를 명시적으로 설정하세요.

```python theme={"system"}
sandbox = Sandbox.run(
    resources=ResourceOptions(
        requests={"cpu": "4", "memory": "16Gi"},
        limits={"cpu": "4", "memory": "16Gi"},
        gpu={"count": 1},
    ),
)
```

GPU 설정 키:

| 키 | 유형 | 설명 |
| - | - | - |
| `count` | `int` | 요청할 GPU 수입니다. |
| `type` | `str` | GPU 유형으로, 러너가 [discovery](/ko/products/sandboxes/client/guides/discovery)에서 광고하는 유형과 정확히 일치해야 합니다. serverless capacity에서는 설정을 비워 두세요. GPU 유형을 자동으로 부여합니다. [GPU 샌드박스 실행](/ko/products/sandboxes/gpu-sandboxes)을 참조하세요. |
| `memory_gb` | `int` | 최소 GPU 메모리(GB)입니다. 러너에서 이 메모리 이상을 가진 GPU 유형을 선택합니다. 두 개 이상의 유형이 조건에 맞을 경우 어떤 유형을 받을지는 정의되지 않습니다. |

`type`과 `memory_gb`는 대안입니다. 둘 중 하나만 설정하세요.

<h3 id="inspect-confirmed-resources">
  Inspect confirmed resources
</h3>

샌드박스가 시작된 후, 확인된 리소스 할당을 검사하세요. 이 예제는 CKS에서 불균등한 requests와 limits를 사용합니다. CKS 설정을 완료하고 `CWSANDBOX_API_KEY`를 CoreWeave API access token으로 설정하세요. `[RUNNER-ID]`를 GPU 용량이 있고 이러한 리소스를 허용하는 정책이 있는 CKS 러너의 ID로 교체하세요:

```python theme={"system"}
from cwsandbox import AuthStrategy, ResourceOptions, Sandbox

with Sandbox.run(
    auth=AuthStrategy.COREWEAVE_API_KEY,
    placement_mode="cks",
    runner_ids=["[RUNNER-ID]"],
    resources=ResourceOptions(
        requests={"cpu": "500m", "memory": "512Mi"},
        limits={"cpu": "2", "memory": "2Gi"},
        gpu={"count": 1},
    ),
) as sb:
    print(sb.resource_requests)  # {"cpu": "500m", "memory": "512Mi"}
    print(sb.resource_limits)    # {"cpu": "2", "memory": "2Gi"}
    print(sb.resource_gpu)       # {"count": 1}
```

<h3 id="configuration-library-interop">
  설정 라이브러리 상호 운용성
</h3>

모든 설정 유형(`NetworkOptions`, `Secret`, `ResourceOptions`)은 dataclass 또는 plain dict를 허용합니다. 이는 설정을 dict 또는 dict-like 객체로 해결하는 ML 설정 라이브러리가 수동 변환 없이 SDK에 값을 직접 전달할 수 있음을 의미합니다.

`SandboxDefaults.from_dict()`는 plain dict 또는 OmegaConf `DictConfig`를 허용하며 중첩된 필드를 자동으로 강제 변환합니다. dict는 필요에 따라 `NetworkOptions`, `Secret` 또는 `ResourceOptions`가 되고, 목록은 튜플이 됩니다.

```yaml theme={"system"}
# sandbox.yaml
container_image: "pytorch/pytorch:2.4.0-cuda12.4-cudnn9-runtime"
max_lifetime_seconds: 3600
tags:
  - training
  - experiment-42
resources:
  requests:
    cpu: "4"
    memory: "8Gi"
  limits:
    cpu: "4"
    memory: "8Gi"
  gpu:
    count: 1
network:
  egress_mode: "internet"
environment_variables:
  LOG_LEVEL: "info"
```

```python theme={"system"}
from omegaconf import OmegaConf
from cwsandbox import Sandbox, SandboxDefaults

cfg = OmegaConf.load("sandbox.yaml")
defaults = SandboxDefaults.from_dict(cfg)

with Sandbox.run(defaults=defaults) as sb:
    result = sb.exec(["python", "train.py"]).result()
```

개별 필드는 `Sandbox.run()` 또는 `session.sandbox()`에 직접 전달할 때 dict도 허용합니다. 리소스에 대한 중첩 dict 형식은 `ResourceOptions` 필드에 매핑됩니다. 평면 dict 형식(`{"cpu": "1", "memory": "1Gi"}`)도 허용되며 Guaranteed QoS로 처리됩니다.

<h2 id="mounted-files">
  마운트된 파일
</h2>

마운트된 파일을 사용하면 시작 시 샌드박스에 설정 파일, 스크립트 또는 기타 읽기 전용 에셋을 제공할 수 있으며, 이를 컨테이너 이미지에 포함하지 않아도 됩니다.

```python theme={"system"}
sandbox = Sandbox.run(
    mounted_files=[
        {
            "path": "/app/config.json",
            "content": '{"debug": true}',
        },
        {
            "path": "/app/script.py",
            "content": "print('hello')",
        },
    ],
)

# 파일은 즉시 사용 가능합니다
result = sandbox.exec(["python", "/app/script.py"]).result()
```

<h3 id="mount-options">
  마운트 옵션
</h3>

| 필드 | 유형 | 설명 |
| - | - | - |
| `path` | `str` | 샌드박스 내 절대 경로입니다. |
| `content` | `str` | 파일 내용(텍스트)입니다. |

마운트된 파일은 읽기 전용입니다. 수정이 필요한 파일에는 `write_file()`을 사용하세요.

<h2 id="ports">
  포트
</h2>

샌드박스 내부의 프로세스가 외부 클라이언트에 트래픽을 서빙할 수 있도록 포트를 노출하세요:

```python theme={"system"}
sandbox = Sandbox.run(
    "python", "-m", "http.server", "8080",
    ports=[
        {"container_port": 8080},
    ],
)
```

<h3 id="port-configuration">
  포트 설정
</h3>

| 필드 | 유형 | 설명 |
| - | - | - |
| `container_port` | `int` | 샌드박스 내부의 포트입니다. |

플랫폼 TLS 또는 TLS 패스스루를 사용하여 포트에 인터넷에서 접근 가능한 주소를 부여하려면 [공개 엔드포인트](/ko/products/sandboxes/public-endpoints)를 참조하세요.

<h2 id="network">
  네트워크
</h2>

네트워크 옵션을 `NetworkOptions` dataclass 또는 plain dict를 사용하여 설정하세요:

```python theme={"system"}
from cwsandbox import NetworkOptions, Sandbox

# NetworkOptions 사용
sandbox = Sandbox.run(
    network=NetworkOptions(
        ingress_mode="public",
        exposed_ports=(8080,),
    ),
)

# dict 사용
sandbox = Sandbox.run(
    network={"ingress_mode": "public", "exposed_ports": [8080]},
)
```

두 형식은 동일합니다: SDK는 내부적으로 dict를 `NetworkOptions`로 자동 변환합니다.

<h3 id="networkoptions-fields">
  NetworkOptions 필드
</h3>

| 필드 | 유형 | 설명 |
| - | - | - |
| `ingress_mode` | `str \| None` | `"public"`(인터넷에서 액세스 가능) 또는 `"internal"`(클러스터 내부 전용)과 같이 인바운드 트래픽을 제어합니다. |
| `exposed_ports` | `tuple[int, ...] \| None` | 노출할 포트입니다(`ingress_mode` 사용 시 필수). 튜플 `(8080,)` 또는 목록 `[8080]`으로 전달하세요. |
| `egress_mode` | `str \| None` | `"internet"`(전체 액세스), `"isolated"`(외부 액세스 없음) 또는 `"org"`(조직 내부 전용)과 같이 아웃바운드 트래픽을 제어합니다. |

모든 필드는 선택 사항이며 기본값은 `None`으로, backend 기본값을 사용합니다.

<h3 id="set-network-in-sandboxdefaults">
  SandboxDefaults에서 네트워크 설정
</h3>

모든 샌드박스에 대한 기본 네트워크 설정을 설정하세요:

```python theme={"system"}
from cwsandbox import NetworkOptions, SandboxDefaults, Session

defaults = SandboxDefaults(
    network=NetworkOptions(egress_mode="internet"),
)

with Session(defaults) as session:
    # 모든 샌드박스는 네트워크 설정을 상속합니다
    sb1 = session.sandbox()  # egress_mode="internet"을 사용합니다
    sb2 = session.sandbox()  # egress_mode="internet"을 사용합니다

    # 특정 샌드박스의 설정을 재정의합니다
    sb3 = session.sandbox(network=NetworkOptions(egress_mode="user"))
```

<h2 id="annotations">
  어노테이션
</h2>

샌드박스에 Kubernetes 파드 어노테이션을 추가하세요. 어노테이션은 기본 파드에 연결된 키-값 문자열 쌍으로, 스케줄러, 비용 할당 도구 또는 외부 자동화와 같이 파드 메타데이터를 조회하는 인테그레이션에 유용합니다.

```python theme={"system"}
sandbox = Sandbox.run(
    annotations={
        "team": "ml-infra",
        "experiment": "training-run-42",
    },
)
```

<h3 id="session-level-defaults">
  세션 수준 기본값
</h3>

세션의 모든 샌드박스에 대한 기본 어노테이션을 설정하세요:

```python theme={"system"}
defaults = SandboxDefaults(
    annotations={
        "team": "ml-infra",
        "managed-by": "sandbox-sdk",
    },
)

with Session(defaults) as session:
    # 기본 어노테이션을 상속합니다
    sb1 = session.sandbox()

    # 병합: 키 충돌 시 명시적 어노테이션이 기본값을 재정의합니다
    sb2 = session.sandbox(
        annotations={"experiment": "run-42", "team": "ml-research"},
    )
    # sb2 receives: team=ml-research, managed-by=sandbox-sdk, experiment=run-42
```

<h3 id="merge-behavior">
  병합 동작
</h3>

`SandboxDefaults.annotations`와 샌드박스별 `annotations`를 모두 제공하면 SDK가 이를 병합합니다. 키 충돌 시 명시적인 샌드박스별 값이 우선하며, 이는 `environment_variables`와 동일한 의미 체계를 따릅니다.

<h3 id="sunk-integration">
  SUNK 인테그레이션
</h3>

SUNK 인테그레이션을 위해 Slurm 컨텍스트를 파드 어노테이션으로 전달하려면 [SUNK Pod Scheduler 인테그레이션 가이드](/ko/products/sandboxes/profiles/sunk-integration#step-4-control-placement-with-slurm-annotations)를 참조하세요.

<h3 id="validation">
  검증
</h3>

SDK는 어노테이션 키나 값을 검증하지 않습니다. 서버는 예약된 키 접두사, 값 형식, 최대 엔트리 수에 대한 검증을 처리합니다.

<h2 id="secrets">
  시크릿
</h2>

Forge 팀 시크릿 주입, 인증 요구 사항 및 Python과 TypeScript 예시에 대해서는 [Forge 시크릿 사용](/ko/products/sandboxes/secrets)을 참조하세요.

<h2 id="timeouts">
  timeout
</h2>

샌드박스와 그 오퍼레이션이 실행되는 시간을 제어하는 네 가지 설정이 있습니다. 이름이 비슷하므로 다음 table은 각 설정이 무엇을 제한하는지 매핑합니다.

| 설정 | 제한 대상 | 강제 적용 주체 | 기본값 |
| - | - | - | - |
| `max_lifetime_seconds` | 자동 종료 전 샌드박스 수명 총 시간 | 서버 | 러너 정책 기본값(설정되지 않은 경우 10 minutes) |
| `timeout_seconds` | 단일 `exec()`, `read_file()`, 또는 `write_file()` call | 클라이언트 | `request_timeout_seconds`로 대체 |
| `max_timeout_seconds` | 시도가 실패하기 전에 서버가 샌드박스를 배치하기 위해 대기하는 시간 | 서버 | 30 seconds |
| `request_timeout_seconds` | 대부분의 원격 프로시저 호출(RPC)에 대한 클라이언트 측 HTTP timeout | 클라이언트 | 300 seconds |

`max_lifetime_seconds`만 샌드박스를 종료합니다. 나머지 세 가지는 개별 요청을 제한하고 샌드박스는 계속 실행되도록 둡니다.

<h3 id="max_lifetime_seconds">
  max\_lifetime\_seconds
</h3>

`max_lifetime_seconds`는 샌드박스의 전체 wall-clock 수명을 설정합니다. 샌드박스가 이 나이에 도달하면, 작업이 진행 중이더라도 플랫폼이 샌드박스를 종료합니다.

`max_lifetime_seconds`를 설정하지 않으면 러너 정책의 기본값이 적용됩니다. 정책 기본값에 양수 수명이 지정되어 있지 않으면 플랫폼은 10분을 사용합니다. 오래 실행되는 작업에는 값을 명시적으로 설정하세요:

```python theme={"system"}
from cwsandbox import Sandbox

with Sandbox.run(max_lifetime_seconds=7200) as sandbox:  # 2시간
    sandbox.exec(["python", "train.py"], timeout_seconds=7000).result()
```

세션이 생성하는 모든 샌드박스에 동일한 수명을 적용하려면 `SandboxDefaults`에서 설정하세요:

```python theme={"system"}
from cwsandbox import Sandbox, SandboxDefaults

defaults = SandboxDefaults(
    container_image="python:3.11",
    max_lifetime_seconds=3600,  # 1시간
)

with Sandbox.run(defaults=defaults) as sandbox:
    sandbox.exec(["python", "-c", "print('working')"]).result()
```

`Sandbox.run()`의 명시적인 `max_lifetime_seconds` 인수는 `defaults`의 값보다 우선합니다. 인수의 기본값이 `None`이므로, `defaults`에 이미 설정된 수명을 제거하는 데 이 인수를 사용할 수 없습니다.

요청할 수 있는 수명은 서버리스 배치와 CKS 배치 모두 30일(2,592,000초)입니다. 플랫폼은 이보다 긴 요청을 거부합니다.

<Warning>
  샌드박스가 시작된 후에는 `max_lifetime_seconds`를 변경할 수 없습니다. 실행 중인 샌드박스의 수명을 연장하는 API는 없으므로, 생성할 때 값을 선택하세요. 제한 시간을 넘어서도 작업을 계속하려면 필요한 내용을 캡처하고 수명을 30일 이내로 설정한 새 샌드박스를 시작하세요.
</Warning>

생성 예시와 CKS 러너 정책 기본값은 [장기 실행 샌드박스 실행](/ko/products/sandboxes/long-running-sandboxes)을 참조하세요.

<h4 id="behavior-when-the-lifetime-expires">
  최대 실행 시간이 만료될 때의 동작
</h4>

플랫폼은 샌드박스의 기본 Kubernetes 작업을 종료하여 최대 실행 시간을 강제 적용하므로, 종료는 즉각적이며 우아하지 않습니다. 실제로 중요한 두 가지 결과가 있습니다:

* 샌드박스 내부의 프로세스는 [`stop()`](/ko/products/sandboxes/client/guides/sandbox-lifecycle)에서 제공하는 유예 기간을 받지 못합니다. 이미 기록되지 않은 모든 것은 손실됩니다.
* 클라이언트는 종료에 대한 distinct 오류 또는 이유를 받지 못합니다. SDK는 `Sandbox`에서 종료 이유를 보고하지 않으므로, 최대 실행 시간 만료를 다른 실패와 프로그래밍 방식으로 구분할 수 없습니다. 장기 실행 샌드박스의 수명을 직접 추적하세요.

예상하는 작업을 충분히 초과하는 최대 실행 시간을 설정하고, 만료에 의존하기보다는 작업을 종료할 때 명시적으로 샌드박스를 종료하세요.

<h3 id="timeout_seconds">
  timeout\_seconds
</h3>

`timeout_seconds`는 실행 중인 샌드박스에서 단일 오퍼레이션의 시간 제한을 설정합니다:

```python theme={"system"}
result = sandbox.exec(
    ["python", "long_script.py"],
    timeout_seconds=300,  # 5분
).result()
```

클라이언트가 응답을 기다리는 시간을 제어합니다. 대기 시간이 timeout을 초과하면 SDK는 `SandboxTimeoutError` 예외를 발생시킵니다. 샌드박스는 계속 실행됩니다. 시간 측정은 샌드박스가 `RUNNING` 상태에 도달한 후에만 시작되므로 시작 시간은 포함되지 않습니다.

`timeout_seconds`를 샌드박스의 `max_lifetime_seconds`보다 낮게 설정하세요. timeout이 샌드박스의 남은 최대 실행 시간을 초과하는 명령은 샌드박스가 종료될 때 중지됩니다.

<h3 id="max_timeout_seconds">
  max\_timeout\_seconds
</h3>

`max_timeout_seconds`는 시도가 실패하기 전까지 서버가 샌드박스를 러너에 배치하기 위해 기다리는 시간을 제한합니다. 이는 서버 측 배치 시간 한도이며 클라이언트의 읽기 timeout이 아닙니다. 또한 이후 샌드박스가 실행되는 시간에는 영향을 주지 않습니다:

```python theme={"system"}
sandbox = Sandbox.run(max_timeout_seconds=120)
```

서버는 1\~300초의 값을 허용하며 기본값은 30입니다. 서버는 300을 초과하는 값을 300으로 제한합니다. 클러스터 부하가 높아 샌드박스가 시작되지 않으면 값을 높이세요. `max_timeout_seconds`는 `Sandbox.run()`과 `session.sandbox()`에서 사용 가능하지만, `SandboxDefaults`에서는 사용할 수 없습니다.

<h3 id="request_timeout_seconds">
  request\_timeout\_seconds
</h3>

`request_timeout_seconds`는 대부분의 RPC에 적용되는 클라이언트 측 HTTP timeout이며, 호출에 자체 `timeout_seconds`가 전달되지 않으면 이 값이 대신 사용됩니다. `SandboxDefaults`에서 설정하세요.

```python theme={"system"}
defaults = SandboxDefaults(request_timeout_seconds=600.0)
```

반면 상태 폴링에는 `poll_rpc_timeout_seconds`가 사용되므로, 응답이 멈춘 폴링은 전체 요청 timeout 동안 차단되지 않고 빠르게 실패합니다. 클라이언트 측 튜닝 옵션 전체 목록은 [SandboxDefaults 레퍼런스](/ko/products/sandboxes/client/ref/core/sandbox-defaults)를 참조하세요.

<h2 id="complete-example">
  전체 예제
</h2>

다음 예시는 기본값, 샌드박스별 재정의, 마운트된 파일, 포트를 하나의 설정으로 결합하여 프로덕션 워크로드를 시작하는 방식을 보여줍니다:

```python theme={"system"}
from cwsandbox import NetworkOptions, ResourceOptions, Sandbox, SandboxDefaults

defaults = SandboxDefaults(
    container_image="python:3.11",
    max_lifetime_seconds=1800,  # 30분
    tags=("production", "ml-pipeline"),
    resources=ResourceOptions(
        requests={"cpu": "4", "memory": "8Gi"},
        limits={"cpu": "4", "memory": "8Gi"},
    ),
    network=NetworkOptions(egress_mode="internet"),
)

with Sandbox.run(
    defaults=defaults,
    mounted_files=[
        {
            "path": "/app/config.yaml",
            "content": "model: gpt-4\nmax_tokens: 1000",
        },
    ],
    ports=[
        {"container_port": 8000},
    ],
) as sandbox:
    # 의존성 설치
    sandbox.exec(["pip", "install", "fastapi", "uvicorn"]).result()

    # 애플리케이션 실행
    result = sandbox.exec(
        ["python", "-c", "print('Server started')"],
        timeout_seconds=60,
    ).result()
    print(result.stdout)
```
