15진행자·운영자 Isaac Sim · EKS/예상 약 45분, 별도 일정

실제 RTX 카메라와 PhysX 시뮬레이션

이미지를 검증하고 실제 GPU 프레임·접촉·놓기 결과를 확인합니다.

진행자·운영자 Isaac Sim · EKS · 별도 트랙아직 읽지 않음

진행자·운영자 선택 트랙, 예상 약 45분입니다. 이미지 보강·검사·GPU 확보 대기는 별도입니다. 14장의 전용 클러스터와 운영자 도움 함수가 준비되어 있어야 합니다.

이번 구현은 CPU PhysX TGS 240 Hz + RTX GPU 카메라 480×360 + pose 기록 20 Hz입니다. GPU 배치 RL, 학습된 운동 정책, 카메라 인식 또는 WebRTC 라이브스트림으로 설명하지 않습니다.

1. 5.1.0 이미지와 드라이버 경계

Auto Mode의 관리형 580 계열 드라이버와 검증 범위에 맞춰 Isaac Sim 5.1.0을 고정합니다. 제공된 L40S probe의 드라이버는 580.178.04입니다. 최신 Isaac 버전으로 바꾸거나 호스트 드라이버를 직접 설치하는 방식으로 문제를 해결하지 않습니다.

원본 amd64 이미지의 고정 digest는 infra/isaac/images.py의 BASE_DIGEST가 기준입니다. 진행자가 NVIDIA 사용 조건을 확인한 이미지만 준비합니다. 먼저 소유 ECR에 그 digest가 있는지 조회합니다.

터미널bash
VSCode Server 터미널에서 실행
set -euo pipefail
cd "$ISAAC_REPO"
"$ISAAC_PYTHON" - <<'PY'
import json
from infra.isaac import deployment as d, images
cfg = d.config()
aws = d.session(cfg)
repo = images.repository(aws, cfg, "isaac-sim")
rows = aws.client("ecr").describe_images(
    repositoryName=repo["repositoryName"],
    imageIds=[{"imageDigest": images.BASE_DIGEST}])["imageDetails"]
assert len(rows) == 1 and rows[0]["imageDigest"] == images.BASE_DIGEST
print(json.dumps({"repository": repo["repositoryName"], "digest": rows[0]["imageDigest"],
                  "imageBytes": rows[0]["imageSizeInBytes"]}, indent=2))
PY

원본 미러가 없다면 보강 빌드의 선행 조건이 빠진 것입니다. 다음은 운영자가 소유 ECR만 확인한 후 고정 원본을 복사하는 절차입니다. 이미 준비된 경우 반복할 필요가 없습니다. crane과 NVIDIA registry 접근은 사전에 준비합니다.

터미널bash
VSCode Server 터미널에서 실행
"$ISAAC_PYTHON" - <<'PY'
import subprocess
from infra.isaac import deployment as d, images
cfg = d.config()
aws = d.session(cfg)
repo = images.repository(aws, cfg, "isaac-sim")["repositoryUri"]
source = "nvcr.io/nvidia/isaac-sim@" + images.BASE_DIGEST
target = repo + ":base-5.1.0-amd64"
with images.login(aws, cfg) as env:
    subprocess.run([images.CRANE, "copy", source, target], env=env, check=True)
    digest = subprocess.check_output([images.CRANE, "digest", target], env=env, text=True).strip()
assert digest == images.BASE_DIGEST, "Registry copy changed the pinned manifest"
print("Pinned amd64 base is available in the owned ECR repository.")
PY

이 복사는 ARM64 관리 호스트에서 Isaac을 실행하는 것이 아닙니다. 실제 보강은 다음 AMD64 CodeBuild에서, 실제 GPU 실행은 EKS에서 수행합니다.

2. userspace 보강 상태 확인

보안 문서는 isaac/README-security.md입니다. Ubuntu/Python 번들을 보강하며 NVIDIA·CUDA API 계열을 무조건 갱신하지 않습니다. 호환성을 위해 남는 CVE가 문서화되어 있습니다.

기존 빌드 기록이 있으면 먼저 조회합니다. 진행 중인 빌드 위에 새 요청을 반복하지 않습니다.

터미널bash
VSCode Server 터미널에서 실행
if [ -s .local/isaac/hardening-build.json ]; then
  isaac hardening-status > "$ISAAC_EVIDENCE/hardening-status.json"
  jq '{id,buildStatus,currentPhase,image}' "$ISAAC_EVIDENCE/hardening-status.json"
else
  isaac start-hardening > "$ISAAC_EVIDENCE/hardening-start.json"
  jq '{buildId,tag,sourceSha256,sourceVersion}' "$ISAAC_EVIDENCE/hardening-start.json"
fi

빌드가 끝날 때까지 조회하고 SUCCEEDED와 base digest를 확인합니다.

터미널bash
VSCode Server 터미널에서 실행
isaac hardening-status > "$ISAAC_EVIDENCE/hardening-status.json"
jq -e '.buildStatus == "SUCCEEDED" and (.image | contains("@sha256:"))' \
  "$ISAAC_EVIDENCE/hardening-status.json"
jq '{image,status,sourceFiles}' .local/isaac/hardened-base.json
isaac scan --component base
jq '{image,status,completedAt,counts}' .local/isaac/base-scan.json

SUCCEEDED는 이미지 빌드 성공입니다. GPU 호환성, RTX 실행, 취약점 0건을 뜻하지 않습니다. 현재 scan은 결과를 기록하는 조회 명령이며 발견된 CVE만으로 실패 종료하지 않습니다. 완료 시각·상태·전체 findings와 보강 명세를 별도로 검토합니다. ACTIVE만 있고 완료 시각이 없다면 아직 완료 근거가 없습니다.

/app-security의 CPU smoke·버전 비교 결과도 ECR 재검사를 대신하지 않습니다. 원본의 과거 finding 수나 예상 잔여 항목 수를 최종 worker의 현재 검사 총계로 복사하지 않습니다.

3. 컨트롤러·worker 이미지와 namespace

소스 편집을 마친 뒤 빌드합니다. build-controller는 로컬 ARM64 빌드와 ECR 게시를, build-worker는 보강된 amd64 base에 실행 코드를 추가하고 게시하는 작업을 수행합니다.

터미널bash
VSCode Server 터미널에서 실행
isaac build-controller
isaac build-worker
jq '{image,sourceFiles}' .local/isaac/controller-image.json
jq '{image,base,sourceFiles}' .local/isaac/worker-image.json
isaac scan --component controller
isaac scan --component worker
jq '{image,status,completedAt,counts}' .local/isaac/controller-scan.json
jq '{image,status,completedAt,counts}' .local/isaac/worker-scan.json

사용할 digest와 실제 잔여 위험을 기록한 뒤 진행합니다. 오래된 digest를 몰래 대체하거나 검사 메타데이터를 삭제하지 않습니다.

터미널bash
VSCode Server 터미널에서 실행
isaac workloads
ik -n robot-atlas-isaac rollout status deployment/isaac-controller --timeout=300s
ik -n robot-atlas-isaac get resourcequota,pdb,networkpolicy,serviceaccounts

workloads는 먼저 server dry-run을 하고 실제 적용합니다. source hash가 이미지 기록과 다르면 거부되므로 해당 이미지를 다시 빌드합니다. 컨트롤러 Ready는 작업 등록을 처리할 준비이며 GPU 엔진 Ready와 다릅니다.

worker는 GPU 1개, CPU 6개, 메모리 요청 40 GiB/한도 48 GiB를 사용합니다. UID/GID 1234, 전용 Pod Identity, 임시 work/cache 볼륨을 사용하며 hostPath나 공개 GPU 서비스는 없습니다.

4. 빨간 상자 한 개를 실제 실행

이 명령은 실제 GPU 작업을 생성합니다. 운영 CLI의 검증 계획은 provider: rules이며 Bedrock 호출이 아닙니다.

터미널bash
VSCode Server 터미널에서 실행
isaac submit --scenario transfer --seed 42 --order red \
  > "$ISAAC_EVIDENCE/red-submit.json"
export ISAAC_RUN_ID="$(jq -er '.id | select(test("^isaac-[0-9a-f-]{36}$"))' "$ISAAC_EVIDENCE/red-submit.json")"
jq '{id,owner,state,createdAt,updatedAt,plan}' "$ISAAC_EVIDENCE/red-submit.json"
isaac_wait_run "$ISAAC_RUN_ID" 1800

queued/starting에는 GPU 확보·이미지·캐시·엔진 준비가 포함될 수 있습니다. 실패하면 같은 ID의 상태와 로그를 확인합니다. 화면이나 파일에 성공 문구를 만들어 넣지 않습니다.

성공한 실제 결과를 내려받습니다.

터미널bash
VSCode Server 터미널에서 실행
isaac run --id "$ISAAC_RUN_ID" > "$ISAAC_EVIDENCE/$ISAAC_RUN_ID-final.json"
isaac artifact --id "$ISAAC_RUN_ID" --kind replay \
  > "$ISAAC_EVIDENCE/$ISAAC_RUN_ID-replay-file.json"
isaac artifact --id "$ISAAC_RUN_ID" --kind preview \
  > "$ISAAC_EVIDENCE/$ISAAC_RUN_ID-preview-file.json"
isaac artifact --id "$ISAAC_RUN_ID" --kind checkpoint \
  > "$ISAAC_EVIDENCE/$ISAAC_RUN_ID-checkpoint-file.json"
export ISAAC_REPLAY="$(jq -er '.path' "$ISAAC_EVIDENCE/$ISAAC_RUN_ID-replay-file.json")"
export ISAAC_PREVIEW="$(jq -er '.path' "$ISAAC_EVIDENCE/$ISAAC_RUN_ID-preview-file.json")"
export ISAAC_CHECKPOINT="$(jq -er '.path' "$ISAAC_EVIDENCE/$ISAAC_RUN_ID-checkpoint-file.json")"

아래 검사는 실제 파일을 읽습니다. 아직 실행 결과가 없으면 통과할 수 없습니다.

터미널bash
VSCode Server 터미널에서 실행
"$ISAAC_PYTHON" - <<'PY'
import hashlib, json, math, os, struct
from pathlib import Path
run_id = os.environ["ISAAC_RUN_ID"]
row = json.loads((Path(os.environ["ISAAC_EVIDENCE"]) / f"{run_id}-final.json").read_text())
r = json.loads(Path(os.environ["ISAAC_REPLAY"]).read_text())
cp = json.loads(Path(os.environ["ISAAC_CHECKPOINT"]).read_text())
png = Path(os.environ["ISAAC_PREVIEW"]).read_bytes()
ready = row["readyEvidence"]
assert row["id"] == r["id"] == run_id
assert row["state"] == r["status"] == "succeeded"
assert r["engine"] == "Isaac Sim" and r["physicsHz"] == 240 and r["fps"] == 20
assert r["provenance"]["physicsBackend"] == "PhysX"
assert r["provenance"]["physicsDevice"] == "cpu"
assert r["provenance"]["isaacSimVersion"] == "5.1.0"
assert r["provenance"]["learning"] == "none"
assert ready["scenePhysicsReady"] is True and ready["actualRgbRendered"] is True
assert ready["preview"]["renderedFrames"] > 0
assert ready["runId"] == cp["runId"]
assert ready["requestHash"] == cp["requestHash"] == r["provenance"]["requestHash"]
assert r["metrics"]["success"] and r["metrics"]["placed"] == r["metrics"]["total"] == 1
assert r["checks"] and all(c["passed"] for c in r["checks"])
assert [s["objectId"] for s in r["steps"]] == ["red"]
assert png[:8] == b"\x89PNG\r\n\x1a\n" and struct.unpack(">II", png[16:24]) == (480, 360)
assert hashlib.sha256(png).hexdigest() == r["provenance"]["preview"]["sha256"]
first, last = r["frames"][0]["bodies"], r["frames"][-1]["bodies"]
for name in ("blue", "orange"):
    assert math.dist(first[name]["position"], last[name]["position"]) < 0.008, name
assert cp["completedActions"] == 1
assert all(o["released"] and o["supported"] and o["stable"]
           for o in cp["boundary"]["objects"].values())
print(json.dumps({"runId": run_id, "actualRtxAndPhysics": True,
                  "metrics": r["metrics"], "gpu": row["gpu"]}, indent=2))
PY

초기 Ready 이미지와 마지막 이미지는 촬영 시점이 다릅니다. 최종 PNG의 해시는 replay의 최종 preview와 비교하며, 초기 readyEvidence.preview.sha256과 같도록 편집하지 않습니다.

5. 순서와 분류 추가 검증

앞의 작업이 끝난 뒤 다음을 한 건씩 실행합니다. 새 run ID를 보관하고 각각의 replay·preview·checkpoint를 확인합니다.

터미널bash
VSCode Server 터미널에서 실행
isaac submit --scenario stack --seed 123 --order blue,red,orange \
  > "$ISAAC_EVIDENCE/stack-submit.json"
export ISAAC_STACK_ID="$(jq -er '.id' "$ISAAC_EVIDENCE/stack-submit.json")"
isaac_wait_run "$ISAAC_STACK_ID" 1800
isaac artifact --id "$ISAAC_STACK_ID" --kind replay \
  > "$ISAAC_EVIDENCE/stack-replay-file.json"
jq '{id,engine,status,metrics,order:[.steps[].objectId],checks}' \
  "$(jq -er '.path' "$ISAAC_EVIDENCE/stack-replay-file.json")"
터미널bash
VSCode Server 터미널에서 실행
isaac submit --scenario sort --seed 314 --order red,blue,orange \
  > "$ISAAC_EVIDENCE/sort-submit.json"
export ISAAC_SORT_ID="$(jq -er '.id' "$ISAAC_EVIDENCE/sort-submit.json")"
isaac_wait_run "$ISAAC_SORT_ID" 1800
isaac artifact --id "$ISAAC_SORT_ID" --kind replay \
  > "$ISAAC_EVIDENCE/sort-replay-file.json"
jq '{id,engine,status,metrics,checks}' \
  "$(jq -er '.path' "$ISAAC_EVIDENCE/sort-replay-file.json")"

쌓기는 파랑→빨강→주황의 지지 순서와 최종 높이를, 분류는 각 색상의 목적지를 확인합니다. 놓기·지지·직립·속도·드리프트 검사가 함께 통과해야 합니다. 실패한 잡기는 최종 위치만 가까워졌다고 성공으로 바꾸지 않습니다.

CPU 계약 테스트는 다음처럼 별도로 수행할 수 있지만 실제 GPU 근거를 대신하지 않습니다.

터미널bash
VSCode Server 터미널에서 실행
.venv/bin/python -m unittest discover -s tests/isaac -p 'test_physics_contract.py' -v

test_physics_gpu.py는 별도 시뮬레이터 CLI의 원본 5개 파일을 받는 검사입니다. 현재 wrapper가 외부 replay ID를 붙인 산출물을 그대로 넣어 내부 ID 검사를 우회하지 않습니다. submit에는 --grip-force 옵션이 없으며 그런 CLI 옵션을 만들어 안내하지 않습니다.

웹 개방 전 확인

운영자 CLI는 고수준 모델 호출·웹 세션 검증을 포함하지 않습니다. 실제 GPU 검증을 마친 뒤 운영자가 검토한 앱 설정과 IAM으로 웹 경로를 연결하고, /api/config의 isaac.enabled, 같은 세션의 plan ID, /api/isaac/runs, 취소·다른 세션 404를 별도로 검증합니다.

현재 설정이 비활성이라면 503 isaac_disabled가 정상입니다. 이 장은 운영 Fargate를 중지하거나 참가자별 사본을 공용 GPU 계정에 연결하는 명령을 제공하지 않습니다.

실패 시 재개

증상 확인
원본 digest 없음 NVIDIA 사용 조건·registry 접근·고정 amd64 미러
보강 빌드 실패 해당 build ID의 로그·의존성 충돌. 호스트 드라이버 교체 금지
검사 미완료·잔여 CVE 완료 시각·전체 findings·보강 문서. 0건으로 표시하지 않음
Pod Ready 이전 실패 GPU/드라이버·USD 참조 자산·캐시 권한·RTX 초기화
readyEvidence 없음 nvidia-smi만 통과한 상태와 실제 renderer 준비 구분
물리 failed 잡기·놓기·지지·직립·드리프트 검사와 simulation 로그
API에서 다른 실행 404 웹 세션 소유권. 운영자 실행은 방문자 세션에 속하지 않음

완료 체크리스트

  • 보강 base와 최종 worker digest·검사 결과·잔여 항목을 기록했습니다.
  • 실제 RGB PNG와 PhysX·240 Hz·엔진/드라이버 provenance를 확인했습니다.
  • 빨간 상자 단독 실행에서 다른 두 상자의 위치를 확인했습니다.
  • 순서·분류 검증을 성공/실패/미실행으로 구분했습니다.
  • 모델·웹 통합과 GPU 단독 검증의 경계를 기록했습니다.

AI CLI 카드: 15. 실제 Isaac 실행 · 다음: 16. 복구 시험

AI CLI 프롬프트 카드

아래 프롬프트를 복사해 실습 EC2에서 선택한 Codex, Kiro CLI, Claude Code의 대화 입력창에 붙여넣습니다. Markdown 카드 다운로드

Codex프롬프트 입력

선택한 AI CLI의 대화 입력창에 붙여넣으세요. 세 도구가 같은 프롬프트를 사용합니다.

Robot Atlas 15장 운영자 GPU 실행을 진행하세요.
ISAAC_REPO/workshop/chapters/15-isaac-simulation.md,
isaac/README-physics.md, isaac/README-security.md와 실제 isaac.py 도움말을 읽으세요.

목표:
- 관리형 580 드라이버에 맞춘 Isaac Sim 5.1.0의 고정 amd64 base를 확인합니다.
- 전용 CodeBuild 보강의 현재 상태·source hash·digest와 base/worker 스캔을 구분합니다.
- ARM64 컨트롤러와 amd64 worker 이미지를 검토한 뒤 전용 namespace에 workloads를 적용합니다.
- 운영 CLI로 빨간 상자 한 개, 파랑 우선 쌓기, 색상 분류를 각각 실제 실행합니다.
- JSON stdout에서 run ID를 읽고 실제 replay·checkpoint·480×360 PNG를 내려받아 검사합니다.

정확한 설명:
물리는 CPU PhysX TGS 240 Hz, pose 기록 20 Hz, 카메라는 RTX GPU입니다.
GPU 배치 RL, 학습된 운동 정책, 카메라 인식, 실물 로봇, WebRTC로 설명하지 마세요.
CodeBuild SUCCEEDED, CPU import, ECR 검사, 실제 RTX·물리 검증은 별개입니다.
현재 scan 명령은 조회·기록이며 CVE가 있다는 이유로 실패 종료하지 않습니다.
잔여 CVE·검사 미완료를 숨기거나 취약점 0건으로 표현하지 마세요.
submit은 provider=rules인 운영자 검증 계획이며 Bedrock을 호출하지 않습니다.

검증:
readyEvidence의 실제 씬·RGB 근거, PhysX provenance, 모든 물리 checks와
미선택 두 상자의 원위치, 최종 PNG 해시·해상도를 확인하세요.
웹용 외부 run ID와 시뮬레이터 내부 checkpoint.runId는 각각 비교하세요.
submit에 존재하지 않는 grip-force 옵션을 만들지 마세요.
실제 결과가 없으면 GPU 시험 미완료로 남기세요.

범위:
현재 계정·기존 VPC·gpu-cluster-01과 전용 스택만 사용합니다.
가드·호스트 드라이버·공유 네트워크·기존 GPU01·Jeju·Fargate를 변경하지 마세요.
일반 참가자에게는 진행자 검증 후 웹만 제공하며 임의 이미지·코드·좌표를 받지 않습니다.

이미지·보안·GPU·물리·웹/모델 검증을 나누어 실제 근거와 남은 항목을 보고하세요.

읽기 기록

읽음 표시는 이 브라우저에만 저장됩니다.
실제 실습 결과는 터미널에서 확인하세요.