> ## 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.

# 볼륨

> 샌드박스에 쓰기 가능한 스크래치 공간을 제공하거나, 여러 샌드박스가 공유하는 등록된 볼륨을 마운트하세요.

볼륨은 사용자가 선택한 경로에 샌드박스가 마운트하는 저장소입니다. 샌드박스는 두 가지 종류의 볼륨을 지원합니다. **스크래치 볼륨**은 단일 샌드박스에 속하며 샌드박스와 함께 사라집니다. **등록된 볼륨**은 조직이 한 번 등록하는 볼륨으로, 이후 여러 샌드박스가 마운트할 수 있습니다.

이 페이지는 컨테이너 파일 시스템보다 더 많은 데이터를 기록해야 하거나, 여러 샌드박스가 동일한 데이터셋을 읽고자 하는 개발자를 위한 것입니다. 이 가이드를 마치면 두 종류의 볼륨을 모두 attach하고 등록된 볼륨의 라이프사이클을 관리할 수 있습니다.

<h2 id="choose-a-volume-type">
  볼륨 유형 선택
</h2>

| | 스크래치 볼륨 | 등록된 볼륨 |
| - | - | - |
| 선언 방법 | 샌드박스 생성 시 `ScratchVolumeOptions` | `Volume.create()` 호출 후 샌드박스 생성 시 `RegisteredVolumeOptions` |
| 수명 | 샌드박스의 수명과 동일 | 샌드박스와 무관하게 유지 |
| 샌드박스 간 공유 | 아니요 | 예 |
| 백킹 저장소 | 로컬 디스크 또는 메모리 | 클러스터에 있는 기존 PersistentVolumeClaim (PVC) |
| 샌드박스 삭제 후 유지 | [파일 시스템 스냅샷](/ko/products/sandboxes/file-system-snapshots)을 통해서만 가능 | 예 |

단일 run의 작업 공간으로는 스크래치 볼륨을 사용하세요. 샌드박스 삭제 후에도 유지해야 하거나 여러 샌드박스가 동시에 읽는 데이터(예: 공유 데이터셋 또는 모델 가중치)에는 등록된 볼륨을 사용하세요.

<h2 id="scratch-volumes">
  스크래치 볼륨
</h2>

스크래치 볼륨 예시에서는 `auth`를 생략하고 `CWSANDBOX_API_KEY`에 설정된 CoreWeave API 액세스 토큰을 사용합니다. Forge API 키를 사용하려면 [시작하기](/ko/products/sandboxes/get-started#forge-api-key)의 안내에 따라 생성한 `AuthHeaders`를 `Sandbox.run()`에 전달하세요.

스크래치 볼륨은 샌드박스와 함께 생성되며 함께 삭제됩니다. `volumes` 목록에서 `ScratchVolumeOptions`로 하나를 선언하세요.

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

with Sandbox.run(
    container_image="ubuntu:22.04",
    volumes=[ScratchVolumeOptions(name="workspace", mount_path="/workspace", size="10Gi")],
) as sandbox:
    sandbox.exec(["sh", "-c", "echo hello > /workspace/data.txt"]).result()
```

`ScratchVolumeOptions`는 다음 필드를 허용합니다:

| Field | 설명 |
| - | - |
| `name` | 샌드박스 내 볼륨 이름입니다. 마운트와 스냅샷이 이 이름을 참조합니다. 필수입니다. |
| `mount_path` | 기본 컨테이너에 마운트할 절대 경로입니다. 마운트하지 않고 볼륨을 선언하려면 생략하세요. |
| `size` | 볼륨 크기(예: `"10Gi"`)입니다. 플랫폼 기본값을 사용하려면 생략하세요. |
| `medium` | 백킹 저장소: `StorageMedium.DISK` (기본값) 또는 `StorageMedium.MEMORY`입니다. |
| `sub_path` | 루트 대신 마운트할 볼륨 내부의 상대 경로입니다. |
| `read_only` | 볼륨을 읽기 전용으로 마운트합니다. 기본값은 `False`입니다. |
| `restore_from_snapshot_id` | 생성 시 [파일 시스템 스냅샷](/ko/products/sandboxes/file-system-snapshots)을 볼륨으로 복원합니다. |

<h3 id="choose-a-storage-medium">
  저장소 매체 선택
</h3>

`StorageMedium.DISK`는 볼륨을 로컬 디스크로 백업합니다. `StorageMedium.MEMORY`는 tmpfs로 백업하며, 이는 더 빠르지만 마운트하는 컨테이너의 메모리 요청과 정책의 메모리 상한에 영향을 줍니다.

무제한 RAM 지원 볼륨은 노드를 소진할 수 있으므로, `MEMORY` 볼륨은 `size`를 선언해야 합니다. 절대 수량으로 또는 샌드박스의 해결된 메모리 요청의 정수 백분율(예: `"50%"`)로 선언할 수 있습니다. 백분율 형식은 `MEMORY`에만 유효합니다. `DISK` 볼륨은 절대 크기를 사용해야 합니다.

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

with Sandbox.run(
    container_image="ubuntu:22.04",
    volumes=[
        ScratchVolumeOptions(
            name="fast-cache",
            mount_path="/cache",
            size="50%",
            medium=StorageMedium.MEMORY,
        )
    ],
) as sandbox:
    sandbox.exec(["sh", "-c", "df -h /cache"]).result()
```

<h3 id="mount-a-scratch-volume-on-several-containers">
  여러 컨테이너에 스크래치 볼륨 마운트하기
</h3>

`mount_path`는 기본 컨테이너에 볼륨을 마운트하는 편의 기능입니다. 여러 컨테이너로 구성된 샌드박스에서는 `mount_path`를 생략하고 대신 각 컨테이너에 마운트를 선언하여 여러 컨테이너가 같은 볼륨에 접근할 수 있도록 하세요.

```python theme={"system"}
from cwsandbox import Container, Sandbox, ScratchVolumeOptions, VolumeMount

with Sandbox.run(
    volumes=[ScratchVolumeOptions(name="shared", size="5Gi")],
    containers=[
        Container(
            name="app",
            image="ubuntu:22.04",
            primary=True,
            volume_mounts=[VolumeMount(volume="shared", mount_path="/data")],
        ),
        Container(
            name="sidecar",
            image="ubuntu:22.04",
            volume_mounts=[VolumeMount(volume="shared", mount_path="/data", read_only=True)],
        ),
    ],
) as sandbox:
    sandbox.exec(["sh", "-c", "echo shared > /data/note.txt"]).result()
```

<h2 id="registered-volumes">
  등록된 볼륨
</h2>

다음 예시에서는 CKS 클러스터의 PVC와 `CWSANDBOX_API_KEY`에 저장된 CoreWeave API 액세스 토큰을 사용합니다. PVC 기반 볼륨을 등록하거나 마운트하기 전에 먼저 [자체 컴퓨팅 사용](/ko/products/sandboxes/get-started-cks)을 완료하세요.

등록된 볼륨은 이미 클러스터 중 하나에 존재하는 PersistentVolumeClaim(PVC)을 가리킵니다. 등록하면 클러스터 자체에 대한 액세스 권한을 부여하지 않고도 샌드박스에서 클레임을 마운트할 수 있습니다. 볼륨은 메타데이터 포인터입니다. CoreWeave는 데이터를 복사하지 않으며, 볼륨을 삭제해도 클레임에 영향을 주지 않습니다.

모든 attach는 동일한 클레임의 실시간 뷰이므로, 한 샌드박스에서의 쓰기는 이를 마운트한 다른 모든 샌드박스에서 확인할 수 있습니다.

<h3 id="register-a-volume">
  볼륨 등록
</h3>

`Volume.create()`는 볼륨을 `VALIDATING` 상태로 즉시 반환합니다. 그런 다음 컨트롤 플레인이 클레임이 존재하고 사용 가능한지 확인합니다. 마운트하기 전에 `wait_until_ready()`로 폴링하세요.

```python theme={"system"}
from cwsandbox import PvcVolumeSource, Volume

volume = Volume.create(
    "team-data",
    pvc=PvcVolumeSource(
        runner_id="[RUNNER-ID]",
        namespace="[NAMESPACE]",
        claim_name="[PVC-NAME]",
    ),
    description="Shared training data",
).result()

volume.wait_until_ready(timeout=120).result()
print(volume.state, volume.capacity, volume.access_modes)
```

볼륨 ID는 직접 선택합니다. 조직 내에서 고유해야 하며, 생성 후에는 immutable입니다.

<Note>
  source와 `read_only` 플래그도 생성 후에는 immutable입니다. `description`만 나중에 변경할 수 있습니다.
</Note>

`PvcVolumeSource`는 다음 필드를 사용합니다:

| Field | 설명 |
| - | - |
| `runner_id` | 클레임을 보유한 러너의 클러스터입니다. 이 설정은 볼륨을 마운트하는 샌드박스가 예약되는 위치도 고정합니다. 필수입니다. |
| `namespace` | 클레임의 Kubernetes namespace입니다. 필수입니다. |
| `claim_name` | PersistentVolumeClaim의 이름입니다. 필수입니다. |
| `sub_path` | 클레임 내부에서 볼륨의 루트로 취급할 선택 경로입니다. |

`Volume.create()`에서 `read_only=True`를 설정하여 볼륨 자체의 속성으로 읽기 전용을 만듭니다. 이 설정은 기본값이 아니라 최소값입니다: 쓰기 가능한 볼륨에서는 마운트가 읽기 전용일 수 있지만, 읽기 전용 볼륨에는 어떤 마운트도 쓸 수 없습니다.

<h3 id="mount-a-registered-volume">
  등록된 볼륨 마운트
</h3>

`RegisteredVolumeOptions`를 사용하여 ID로 볼륨을 마운트하세요. 시작 시 볼륨이 `READY` 상태여야 하며, 그렇지 않으면 샌드박스가 `CWSANDBOX_VOLUME_NOT_READY` 오류와 함께 실패합니다.

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

with Sandbox.run(
    container_image="ubuntu:22.04",
    volumes=[
        RegisteredVolumeOptions(
            name="data",
            volume_id="team-data",
            mount_path="/data",
            read_only=True,
        )
    ],
) as sandbox:
    listing = sandbox.exec(["ls", "/data"]).result()
    print(listing.stdout)
    print(sandbox.attached_volume_ids)
```

`RegisteredVolumeOptions`는 `name`, `volume_id` 및 `/`가 아닌 절대 `mount_path`를 요구합니다. 또한 `sub_path`를 허용하며, 이는 등록 시 설정된 `sub_path`와 결합되고, `read_only`도 허용합니다.

샌드박스는 마운트한 볼륨을 `attached_volume_ids`에 반영합니다.

<h3 id="locality-and-placement">
  지역성과 배치
</h3>

볼륨의 `locality`는 배치를 제한하는지 여부를 보고합니다:

* `cluster_local`: 볼륨은 하나의 클러스터에 존재하므로, 이를 마운트하는 샌드박스는 해당 클러스터의 러너에 스케줄링됩니다. PVC-backed 볼륨은 클러스터-local입니다.
* `global`: 볼륨은 모든 클러스터에서 접근 가능하며 배치를 제한하지 않습니다.

서로 다른 클러스터의 클러스터-local 볼륨 두 개를 하나의 샌드박스에 마운트하는 것은 불가능하며, 시작이 `CWSANDBOX_VOLUME_PLACEMENT_CONFLICT` 오류와 함께 실패합니다.

<h3 id="manage-registered-volumes">
  등록된 볼륨 관리
</h3>

조직의 볼륨 목록을 조회하고, 볼륨을 검사, 업데이트 및 등록 해제하는 데 다음 오퍼레이션을 사용하세요.

```python theme={"system"}
from cwsandbox import Volume, VolumeState

# 조직의 Volume을 목록으로 조회합니다. 선택적으로 필터링할 수 있습니다.
volumes = Volume.list(states=[VolumeState.READY]).result()

# Volume을 하나 조회합니다.
volume = Volume.get("team-data").result()
print(volume.state, volume.attached_sandbox_count)

# 설명을 업데이트합니다. 변경 가능한 유일한 필드입니다.
volume.update(description="Shared training data, 2026 refresh").result()

# 필요 시 backing claim을 다시 확인합니다.
volume.validate().result()

# Volume을 등록 해제합니다. backing PVC는 변경되지 않습니다.
volume.delete(allow_missing=True).result()
```

`Volume.list()`는 페이지네이션을 자동으로 처리하며 `states`와 `runner_ids` 필터를 지원합니다. `delete()`에 `allow_missing=True`를 지정하면 이미 삭제된 볼륨을 삭제해도 예외가 발생하지 않고 성공으로 처리됩니다.

종료 상태가 아닌 샌드박스에서 여전히 마운트 중인 볼륨을 삭제하면 `CWSANDBOX_VOLUME_IN_USE` 오류로 실패하며, Python 클라이언트는 이를 `VolumeInUseError` 예외로 발생시킵니다. 먼저 연결된 샌드박스를 중지하세요.

<h3 id="volume-states">
  볼륨 상태
</h3>

등록된 볼륨은 라이프사이클 동안 다음 상태를 거칩니다:

| 상태 | 의미 |
| - | - |
| `VALIDATING` | 볼륨이 수락되었으며 컨트롤 플레인이 기반 클레임을 확인하고 있습니다. |
| `READY` | 검증에 성공했습니다. 볼륨을 마운트할 수 있습니다. |
| `ERROR` | 검증에 실패했습니다. 원인을 확인하려면 `state_reason`을 조회하세요. |
| `DELETING` | 볼륨 등록이 해제되고 있으며 더 이상 마운트할 수 없습니다. |

`wait_until_ready()`는 `READY` 상태가 될 때까지 반복해서 확인합니다. 볼륨이 `ERROR` 또는 `DELETING` 상태에 도달하면 `VolumeError`를 발생시키고, timeout이 먼저 경과하면 `VolumeWaitTimeoutError`를 발생시킵니다.

<h2 id="failure-reasons">
  실패 원인
</h2>

이 table을 사용하여 샌드박스 및 볼륨 오퍼레이션이 반환할 수 있는 실패 원인을 확인하세요.

| 원인 | 의미 | 조치 |
| - | - | - |
| `CWSANDBOX_VOLUME_NOT_FOUND` | 조직에 해당 ID의 볼륨이 없습니다. | ID와 조직을 확인하세요. |
| `CWSANDBOX_VOLUME_NOT_READY` | 샌드박스 시작 시 `READY` 상태가 아닌 볼륨을 참조했습니다. | 볼륨이 `READY` 상태가 될 때까지 주기적으로 확인한 다음 시작을 재시도하세요. |
| `CWSANDBOX_VOLUME_IN_USE` | 샌드박스가 아직 연결되어 있어 삭제가 차단되었습니다. | 연결된 샌드박스를 중지한 다음 볼륨을 삭제하세요. |
| `CWSANDBOX_VOLUME_BACKEND_NOT_FOUND` | 기반이 되는 클레임이 없거나 더 이상 읽을 수 없습니다. | namespace에 클레임이 여전히 존재하는지 확인한 다음 `validate()`를 호출하세요. |
| `CWSANDBOX_VOLUME_PLACEMENT_CONFLICT` | 연결된 볼륨이 서로 호환되지 않는 러너를 고정합니다. | 동일한 클러스터에 있는 볼륨을 마운트하세요. |
| `CWSANDBOX_VOLUME_QUOTA_EXCEEDED` | 조직이 볼륨 한도에 도달했습니다. | 사용하지 않는 볼륨을 삭제하거나 할당량 증가를 요청하세요. |

<h2 id="related-resources">
  관련 리소스
</h2>

관련 샌드박스 기능에 대한 자세한 내용은 다음 리소스를 참조하세요:

* [파일 시스템 스냅샷](/ko/products/sandboxes/file-system-snapshots): 샌드박스의 파일 시스템을 유지하고 복원합니다.
* [샌드박스에 AI Object Storage 액세스 권한 부여](/ko/products/sandboxes/operations/object-storage-access): 샌드박스 내부에서 버킷을 읽고 씁니다.
* [샌드박스 설정](/ko/products/sandboxes/client/guides/sandbox-configuration): 샌드박스 생성 옵션의 나머지 부분
* [분산 파일 저장소](/products/storage/distributed-file-storage/create-volumes): 등록된 볼륨이 가리키는 PersistentVolumeClaim을 생성합니다.
