첫 번째 샌드박스 만들기
첫 번째 샌드박스 만들기
키트에서 샌드박스를 만들고 그 안에서 명령을 실행해 봐요. 키트는 도구나 에이전트를 위한 이미지와 구성을 묶어 줘요. shell 키트는 인사말 명령에 모델 제공자 자격 증명이 필요 없어서 첫 선택으로 유용해요.
출처: 문서
본문
먼저 SDK를 설치하고 Docker에 인증하세요. 인증된 클라이언트를 키트 이름과 명령과 함께 이 예시에 전달하세요.
키트 실행과 명령 실행
키트 이름으로 shell을 선택하고 명령으로 ['echo', 'Hello from Docker Sandboxes']를 전달하세요. 예시는 2 CPU와 4096 MiB 메모리를 요청해요. 다른 워크로드의 크기를 정할 때는 compute sizes와 계정 제한 문서를 참고하세요.
예시는 키트를 실행하고, 샌드박스가 실행될 때까지 기다리고, 샌드박스의 프로세스 컬렉션을 통해 명령을 실행해요. SDK가 연결과 샌드박스 범위의 자격 증명을 처리해요.
성공적인 인사말은 stdout에서 Hello from Docker Sandboxes와 종료 코드 0을 반환해요. 인자 배열, 셸 구문, 명령 결과 해석은 첫 명령 실행 문서를 참고하세요.
반환된 샌드박스 이름을 보관하세요. 이 예시는 다음 가이드를 위해 샌드박스를 사용 가능한 상태로 남겨 둬요. 작업이 끝나면 삭제하세요. SDK 클라이언트를 닫아도 샌드박스는 삭제되지 않아요. 생성이 수락된 후 대기가 타임아웃되면 샌드박스가 여전히 존재할 수 있어요.
핵심 코드:
const created = await client.kits.launch(
kitName,
{ resources: { cpus: 2, memoryMib: 4096 } },
{ timeoutMs, signal },
);
const sandbox = await created.waitUntilRunning({ timeoutMs, signal });
const result = await sandbox.processes.run(
{ args },
{ timeoutMs, signal },
);
return { sandbox, result };
완전한 TypeScript 예시: quickstart/run.ts
import type { Sandboxes } from '@docker/sandboxes';
export async function createAndRun(
client: Sandboxes,
kitName: string,
args: string[],
timeoutMs = 300_000,
) {
const signal = AbortSignal.timeout(timeoutMs);
const created = await client.kits.launch(
kitName,
{ resources: { cpus: 2, memoryMib: 4096 } },
{ timeoutMs, signal },
);
const sandbox = await created.waitUntilRunning({ timeoutMs, signal });
const result = await sandbox.processes.run(
{ args },
{ timeoutMs, signal },
);
return { sandbox, result };
}
임시 샌드박스를 자동으로 정리
단일 작업에서는 범위 지정 샌드박스 헬퍼(scoped sandbox helper)가 샌드박스를 만들고, 콜백을 실행하고, 콜백이 실패할 때를 포함해 이후 삭제를 시도해요. 이 예시는 헬퍼가 삭제를 시도하기 전에 샌드박스를 명시적으로 중지하고 그 전환이 끝날 때까지 기다려요. 작업에 맞는 명령 인자와 생성 옵션을 제공하세요. 게시된 이미지라면 그 참조와 리소스를 설정하세요.
정리에는 자체 마감이 있어요. 실패하면 워크플로 오류와 보존된 샌드박스 정체성을 검사해 정리를 마무리하세요. 클라이언트 타임아웃을 샌드박스가 삭제되었다는 확인으로 여기지 마세요.
다음으로 에이전트 키트를 선택하거나 프로세스로 작업하세요.
핵심 코드:
return client.withSandbox(options, async (sandbox) => {
const outcome = await sandbox.processes
.run({ args }, { timeoutMs: 300_000 })
.then(
(value) => ({ value }),
(error: unknown) => ({ error }),
);
try {
const cleanup = { signal: AbortSignal.timeout(30_000) };
const current = await client.get(sandbox.name, cleanup);
if (current.uid !== sandbox.uid)
throw new Error(
'Sandbox identity changed; refusing to stop a replacement',
);
const stopped = await current.stop(cleanup);
await stopped.waitUntilStopped(cleanup);
} catch (error) {
if ('error' in outcome)
throw new AggregateError(
[outcome.error, error],
'Command and stop both failed',
);
throw error;
}
if ('error' in outcome) throw outcome.error;
return outcome.value;
});
완전한 TypeScript 예시: quickstart/scoped.ts
import type { ClientCreateOptions, Sandboxes } from '@docker/sandboxes';
export async function runTemporary(
client: Sandboxes,
options: ClientCreateOptions,
args: string[],
) {
return client.withSandbox(options, async (sandbox) => {
const outcome = await sandbox.processes
.run({ args }, { timeoutMs: 300_000 })
.then(
(value) => ({ value }),
(error: unknown) => ({ error }),
);
try {
const cleanup = { signal: AbortSignal.timeout(30_000) };
const current = await client.get(sandbox.name, cleanup);
if (current.uid !== sandbox.uid)
throw new Error(
'Sandbox identity changed; refusing to stop a replacement',
);
const stopped = await current.stop(cleanup);
await stopped.waitUntilStopped(cleanup);
} catch (error) {
if ('error' in outcome)
throw new AggregateError(
[outcome.error, error],
'Command and stop both failed',
);
throw error;
}
if ('error' in outcome) throw outcome.error;
return outcome.value;
});
}