참고 자료

참가자 준비 도구 · 집필용 CLI 계약

운영 Robot Atlas 저장소의 루트에서 실행합니다. lab.py의 모든 명령은 AWS 자원을 생성·수정·삭제하지 않습니다. discover와 doctor --aws만 기존 계정·네트워크·인증서를 읽습니다. 참가자 설정은 비밀 값이 없는 JSON이며, 계정 ID를 반드시 직접 지정합니다.

기본 과정: 로컬 앱

터미널bash
VSCode Server 터미널에서 실행
python3 workshop/scripts/lab.py init \
  --participant team01 \
  --account-id 123456789012 \
  --config workshop/.local/team01.json

python3 workshop/scripts/lab.py doctor --config workshop/.local/team01.json
python3 workshop/scripts/lab.py prepare --config workshop/.local/team01.json
python3 workshop/scripts/lab.py info --config workshop/.local/team01.json

init는 오프라인으로 설정 파일 하나를 생성합니다. 선택적으로 --profile my-existing-profile, --api-port 14000을 지정할 수 있습니다. 기존 설정을 덮어쓰지 않습니다. 참가자 ID는 3–10자의 소문자 영문·숫자입니다. 운영·참조·공유 용도로 예약한 이름은 거부합니다.

prepare는 workshop/.local/labs/team01/app에 로컬 사본을 생성합니다. network: {} 상태에서도 실행할 수 있습니다. 이 단계에는 infra/, scripts/deploy.py, scripts/cleanup.py가 없습니다. 기존 앱을 덮어쓰는 --force 옵션은 없으므로 참가자의 수정 내용이 보존됩니다.

info의 표준 출력은 JSON 객체 하나입니다. 핵심 필드는 다음과 같습니다.

필드 의미
workspace 참가자 앱의 절대 경로
ports.api API 및 빌드된 화면 포트
ports.simulation API 포트 + 1
ports.vite API 포트 + 2
names.project robot-lab-team01
names.stackPrefix RobotLabTeam01
names.stacks foundation, edge, agentcore, app 스택 이름
names.cookieName robot_lab_team01_session
names.repositoryUri 지정한 계정의 참가자 전용 ECR 경로
names.dataBucket, names.assetsBucket 참가자·계정·리전이 포함된 버킷 이름
prepared, cloudPrepared 로컬/클라우드 파일 준비 여부. 배포 성공 여부가 아님
urls.api, urls.vite 해당 참가자의 로컬 주소
modelId 기본값 global.openai.gpt-5.6-sol
defaultLocalPlanner rules. 모델 설정만으로 실제 모델 접근을 검증하지 않음
dnsManagement, awsMutations 각각 manual, false

기본 포트는 참가자 ID로부터 14000–16999 범위에서 결정합니다. 같은 저장소의 다른 참가자 설정과 겹치면 --api-port로 다른 연속 포트 세 개를 선택합니다. 포트 범위를 직접 지정할 때 API는 14000–19997이어야 합니다.

터미널bash
VSCode Server 터미널에서 실행
cd workshop/.local/labs/team01/app
nvm use
npm ci
uv venv --python 3.11 .venv
uv pip install --python .venv/bin/python -r simulation/requirements.txt
npm test
npm run build

별도 터미널에서 각각 npm run simulation, npm run server를 실행합니다. Vite를 사용할 때는 npm run dev를 추가합니다. 포트는 고정값을 교재에 복사하지 않고 info 결과를 사용합니다.

.env는 검토된 예제에서 새로 만들며 기본 계획기는 규칙 모드입니다. 직접 Bedrock 실습은 참가자 앱의 .env에서 MODEL_ID를 명시적으로 선택합니다. 교재처럼 ROBOT_LAB이 현재 앱과 일치하고 MODEL_ID="$ROBOT_MODEL_ID"가 함께 지정된 환경도 지원합니다. MODEL_ID=""로 실행하면 다시 규칙 모드가 됩니다. 로컬 실행기는 모델 사용 전에 AWS CLI의 읽기 전용 STS 호출로 계정을 확인합니다. 자격 증명은 기존 AWS 프로필이나 정상적인 자격 증명 체인을 사용하며 설정 JSON에 저장하지 않습니다.

HTTPS 포트 미리보기는 같은 참가자 환경에서 PUBLIC_ORIGIN="$ROBOT_BROWSER_ORIGIN"으로 명시하거나 앱의 .env에 직접 지정합니다. 스킴·호스트·포트만 허용하며 경로·쿼리·인증 정보와 운영 도메인은 거부합니다. 계정·네임스페이스·API/시뮬레이터 포트·로컬 저장소 경계는 이 설정으로 바뀌지 않습니다.

복사된 build 명령은 다음으로 고정합니다.

참고 내용text
tsc --noEmit && vite build && tsc -p tsconfig.server.json

복사한 npm 명령은 교재 디렉터리에 의존하지 않습니다. 원본 화면에 워크숍 링크가 있다면 게시된 운영 교재의 절대 주소로 연결합니다. 폰트·로봇 모델의 라이선스와 시뮬레이션 코드는 보존합니다. Dockerfile.web에서도 교재 전용 Python 설치와 두 COPY 입력을 제거합니다. 참가자 앱의 Docker 빌드에는 교재 파일이 필요하지 않습니다.

심화 과정: 기존 네트워크와 인증서

터미널bash
VSCode Server 터미널에서 실행
python3 workshop/scripts/lab.py doctor --config workshop/.local/team01.json --aws

python3 workshop/scripts/lab.py discover \
  --config workshop/.local/team01.json \
  --vpc-id vpc-11111111111111111

python3 workshop/scripts/lab.py configure-domain \
  --config workshop/.local/team01.json \
  --domain robot-lab-team01.example.com \
  --viewer-certificate arn:aws:acm:us-east-1:123456789012:certificate/11111111-1111-4111-8111-111111111111 \
  --origin-certificate arn:aws:acm:ap-northeast-2:123456789012:certificate/22222222-2222-4222-8222-222222222222

python3 workshop/scripts/lab.py prepare-cloud --config workshop/.local/team01.json

위 계정·VPC·인증서 ID는 모두 예시입니다. 실제 참가자 계정의 기존 자원을 직접 선택해야 합니다. 사용 가능한 VPC가 정확히 하나라면 discover의 --vpc-id를 생략할 수 있습니다. 이 명령은 두 AZ의 public/private subnet 네 개, 기존 public NAT 경로와 AWS 관리형 CloudFront origin-facing prefix list를 검사하고 선택 결과를 참가자 JSON에 저장합니다.

configure-domain은 로컬 설정만 바꿉니다. 호스트의 첫 레이블은 정확히 robot-lab-<participant>여야 합니다. Viewer 인증서는 같은 계정의 us-east-1, ALB 원본 인증서는 같은 계정의 ap-northeast-2 자원이어야 하며 둘 다 해당 공개 호스트 이름을 포함해야 합니다. 인증서 발급·DNS 검증·공개 CNAME 등록·정리는 모두 운영자가 수동으로 수행합니다.

prepare-cloud는 오프라인 파일 생성입니다. AWS 접근이나 리소스 존재를 증명하지 않습니다. PyYAML이 필요하고, 실제 AWS 검사에는 boto3가 필요합니다. 생성 후 계정·리전·네트워크·인증서·호스트·네임스페이스는 사본의 바인딩에 고정됩니다. 설정을 다른 참가자나 운영 자원으로 바꾸면 명령이 거부됩니다.

생성된 앱의 배포 명령

참가자 앱으로 이동한 뒤 실행합니다. 운영 루트의 배포 스크립트를 실행하지 않습니다. lab.py는 아래 명령을 대신 실행하지 않습니다.

터미널bash
VSCode Server 터미널에서 실행
cd workshop/.local/labs/team01/app
python3 scripts/deploy.py config
python3 scripts/deploy.py dry-plan
python3 scripts/deploy.py lint
python3 scripts/deploy.py discover
python3 scripts/deploy.py status
명령 동작
config, dry-plan, lint 오프라인 설정·템플릿·격리 검사
build --release lab01 로컬 ARM64 이미지 빌드
plan foundation / plan edge AWS 변경 집합 생성. 이 명령부터 AWS 쓰기 발생
apply foundation / apply edge 저장된 변경 집합의 무결성·소유권을 확인한 뒤 실행
publish --artifacts infra/.state/releases/lab01.json 소유 ECR에 명시적으로 게시
scan --artifacts infra/.state/releases/lab01.json 읽기 전용 이미지 검사 결과 조회
plan agentcore --artifacts … / apply agentcore 참가자 플래너 변경 집합 검토·실행
plan app --artifacts … / apply app 참가자 앱 변경 집합 검토·실행
assets --artifacts … 소유 웹 이미지의 정적 파일을 소유 버킷에 게시
invalidate 소유 CloudFront 배포의 캐시 무효화
configure-logs 소유 AgentCore 로그의 보존 기간 설정
python3 scripts/cleanup.py 읽기 전용 정리 계획
python3 scripts/cleanup.py --execute 소유권을 다시 검사한 뒤 참가자 스택만 삭제

전역 옵션은 하위 명령 앞에 둡니다. 예: python3 scripts/deploy.py --config infra/config.json status. --profile은 초기 참가자 설정에 기록한 프로필과 일치해야 합니다.

권장 순서는 build → Foundation plan/apply → publish → scan → Edge plan/apply → AgentCore plan/apply → App plan/apply → assets → invalidate입니다. plan은 오프라인 명령이 아닙니다. AWS 변경 집합을 만들지 않는 검사는 반드시 dry-plan을 사용합니다.

CloudFront 원본은 실제 ALB DNS를 사용하고 공개 Host를 전달합니다. 별도 origin DNS 레코드를 만들지 않습니다. App 출력의 CloudFrontUrl과 설정한 공개 호스트를 기준으로 공개 CNAME을 수동 등록합니다. 정리 시 보존되는 S3·ECR·DynamoDB·Secret 등은 자동으로 비워지지 않으며 보존 자원의 비용과 수동 DNS 정리를 별도로 확인합니다.

범위와 검증 기록

이 도구는 00–04장 MuJoCo 로컬 과정과 05–13장 AWS 배포 과정의 참가자 준비기입니다. 14–18장 Isaac Sim/EKS는 진행자·운영자 과정입니다. 해당 과정의 gpu-cluster-01은 운영자가 지정 계정·기존 VPC에서 관리하며, 참가자 준비기로 생성하거나 연결하지 않습니다. 운영자용 infra/isaac/**, scripts/isaac.py, isaac/**, server/isaac.ts는 두 준비 단계 모두에서 제외합니다. 원본 API에 추가된 선택적 GPU import·설정·라우트도 검토된 문자열 단위로 참가자 사본에서 제거합니다. API가 GPU 기능 설정을 제공하지 않으므로 화면의 Isaac Sim 선택은 비활성화됩니다. 이 변환 지점이 바뀌면 준비를 중단합니다.

루트 .env.example에 문서화된 ISAAC_JOBS_TABLE, ISAAC_ARTIFACT_BUCKET, ISAAC_MAX_JOB_SECONDS는 생성된 참가자 .env와 .env.example에서 제외합니다. 로컬 실행기는 부모 프로세스에서 상속한 세 값도 비웁니다. 참가자가 .env에 이 필드를 추가하면 실행을 거부하며 값은 오류에 표시하지 않습니다. MODEL_ID의 명시적 Bedrock 선택 방식은 그대로 사용할 수 있습니다.

클라우드 사본의 설정에는 isaacEnabled가 없습니다. 이 필드를 추가하면 false라도 미등록 설정으로 거부합니다. 배포기의 GPU 스택 조회 분기, CFN의 두 GPU 저장소 매개변수와 Fargate의 세 GPU 환경변수를 함께 제거하므로 prepare-cloud 이후에도 생성 대상은 네 참가자 스택뿐입니다. 소스 복사는 명시적 파일 목록에 한정하며 .env, 자격 증명, .local, .state, 가상환경, node_modules, Git 데이터, 링크, 개인 실행 결과를 가져오지 않습니다. 공개 시연용으로 검토된 세 개의 물리 재생 예제는 포함합니다.

배포기 원본이 바뀌어 해시 또는 변환 지점이 맞지 않으면 prepare-cloud는 중단됩니다. 가드를 지우지 말고 준비기 변환과 테스트를 함께 검토해야 합니다.

이번 통합에서 검토한 소스 계약은 다음과 같습니다.

변경된 원본 참가자 사본에 적용한 처리
infra/deployment.py 네 스택·계정·네트워크·인증서 바인딩을 유지하고 운영자 GPU 조회 및 매개변수만 제거
infra/app.yaml GPU 설정을 제거하고 수동 DNS·ALB Host 전달을 유지. CloudFront의 교재 경로 보정은 참가자 도메인으로 치환
infra/artifacts.py 공개 자산의 MIME·캐시·체크섬 처리와 숨김 파일 차단을 유지. 존재하지 않는 교재 입력은 원본의 is_file() 검사로 건너뜀
Dockerfile.web 교재 전용 Python 설치 및 두 복사 줄을 정확히 제거. 런타임 단계는 유지
server/app.ts, server/config.ts 기존 GPU 제외 항목을 현재 코드와 대조. 허용하지 않은 GPU 코드가 남으면 준비 중단
server/http.ts 안전한 정적 파일 처리 코드를 그대로 복사. 교재가 없는 참가자 사본의 /workshop/는 404이며 화면 링크는 공개 교재로 연결
.env.example 빈 GPU 저장소 이름과 기본 시간 제한만 추가한 내용을 검토하고 예제 해시 갱신. 참가자 환경에서는 제외

cloud-sources.json은 검토한 배포 소스 세 파일의 해시만 갱신했습니다. local-exclusions.json에는 Docker 교재 빌드의 정확한 제거 항목을 추가했습니다. 복사 허용 목록은 늘리지 않았으며, 해시·변환·생성물 무결성 검사는 모두 유지합니다. 교재가 없어도 참가자 소스 지문을 계산할 수 있으며, 참가자 코드 수정은 지문을 바꾸고 로컬 비공개 상태는 포함하지 않습니다.

로컬 빌드·격리 검사·합성 계정 CFN lint는 실제 참가자 AWS 배포, 모델 접근, DNS 또는 인증서 유효성의 증거가 아닙니다.

구현 검증 · 2026-09-13 UTC

Node 24.21.0, Python 3.11.15, PyYAML 6.0.3, boto3 1.43.93, cfn-lint 1.45.0으로 다음 명령을 실행했습니다. npm 패키지는 준비된 로컬 캐시를 사용했습니다. 모든 참가자 설정·앱·실행 기록은 테스트가 생성한 /tmp/robot-lab-* 아래에 있었으며 테스트 종료 시 제거했습니다.

터미널bash
VSCode Server 터미널에서 실행
PATH=/tmp/jeju-node24/bin:$PATH \
npm_config_cache=/tmp/robot-atlas-npm-cache \
npm_config_offline=true \
UV_CACHE_DIR=/tmp/robot-workshop-uv-cache \
AWS_EC2_METADATA_DISABLED=true \
ROBOT_LAB_INTEGRATION=1 ROBOT_LAB_RUNTIME=1 \
/tmp/robot-workshop-tools-venv/bin/python -B -m unittest discover \
  -s workshop/tests -p 'test_lab*.py' -v

통합 갱신 후 결과: 38개 준비기 테스트 통과, 건너뛴 테스트 없음 (70.652초). 기존 35개 검사를 유지하고 Docker 입력, GPU 없는 CFN 매개변수, 교재 없는 소스 지문에 대한 회귀 검사 세 개를 추가했습니다. 이 실행에는 다음 검사가 포함됩니다.

  • 비밀 값·미등록 필드·예약 이름·운영 도메인·계정 불일치·포트 충돌 거부.
  • 실제 CLI의 오프라인 init → prepare → info.
  • 서로 다른 합성 계정의 team01, team02 사본과 배포 범위 검사.
  • Symlink·hardlink·FIFO·출력 덮어쓰기·소스 변환 불일치·바인딩 변조 거부.
  • 읽기 전용 AWS 테스트 대역으로 기존 subnet/NAT/prefix list 선택과 STS 계정 확인.
  • GPU 운영 코드와 API hook 제외, 알 수 없는 GPU hook 추가 시 준비 거부.
  • GPU 환경변수를 상속해도 빈 값으로 실행되며, 참가자 .env에 GPU 필드를 추가하면 값 노출 없이 거부.
  • 각 team01, team02 앱의 npm ci, npm test, npm run build: 각각 애플리케이션 테스트 47개 통과.
  • 두 참가자 앱의 python3 -B scripts/deploy.py dry-plan 및 lint. 각 lint에서 네 CFN 템플릿과 배포 가드 테스트 23개 통과.
  • agentcore, bedrock, rules 세 모드 모두 생성 매개변수와 CFN 선언 일치. AWS 테스트 대역을 통해 GPU 스택·DNS 조회가 발생하지 않는지 확인.
  • 교재 파일이 없는 사본에서 소스 지문 계산 성공, 코드 수정 감지 및 비공개 로컬 상태 제외.
  • npm run simulation, npm run server로 실제 MuJoCo와 API를 기동한 뒤, BROWSER_BASE_URL=http://127.0.0.1:18000으로 생성된 scripts/browser-check.mjs 실행: 브라우저 검증 30개 통과. 파란 상자가 아래인 released tower, red-only 옮기기, 다른 물체가 제자리에 남는 결과, 세션·계획·모바일 화면을 확인했습니다. API는 planner: rules, storage: local, GPU 기능 비활성 상태였습니다. 교재가 없는 /workshop/, /workshop/missing, /api/isaac/runs는 404를 반환했습니다. 이 리허설 앱에서도 애플리케이션 테스트 47개를 별도로 통과했으며 실제 Bedrock 호출은 하지 않았습니다.

테스트 옵션을 생략하면 다음 명령은 준비기 경계 검사만 실행하고 npm 설치·빌드, 런처 하위 프로세스, 실제 물리/브라우저 리허설 세 검사를 건너뜁니다.

터미널bash
VSCode Server 터미널에서 실행
python3 -B -m unittest discover -s workshop/tests -p 'test_lab*.py' -v

환경의 subprocess 제한 때문에 실제 Node/브라우저 검증은 승인된 로컬 실행 권한으로 수행했습니다. 운영 API·운영 배포 명령·실제 AWS 생성/삭제·실제 모델 호출·DNS 변경은 검증에 사용하지 않았습니다.