# Jetson 배포

> NVIDIA Jetson 장치(Orin, Xavier, 레거시 TX2 플릿)에 X-Edge AI를 빌드, 번들링, 설치합니다.

X-Edge AI는 x86 박스와 동일한 3개 서비스 스택(프런트엔드, 백엔드, Python 추론 서비스)으로
NVIDIA Jetson 모듈(arm64 / L4T)에서 실행됩니다. Jetson에서 달라지는 것은 **추론 이미지**입니다.
이 이미지는 JetPack이 제공하는 CUDA/TensorRT 라이브러리에 맞춰, 사용 중인 JetPack 버전과
일치하는 ONNX Runtime 휠로 빌드해야 합니다.

Jetson 배포는 전용 **`Jetson-device`** 릴리스 라인에서 제공됩니다. 업데이트는 메인 제품
라인에서 이 라인으로 단방향으로만 흐르므로, Jetson 빌드는 설계상 항상 최신 x86 릴리스보다
뒤처집니다.

## 지원 프로필

| 프로필 | 장치 / JetPack | 베이스 이미지 | ONNX Runtime | 실행 공급자 |
|---|---|---|---|---|
| `jetson` | Orin / Xavier / Nano, JetPack 5+ (L4T r35+) | `l4t-base:r35.4.1` | JetPack 휠(장치별) | TensorRT → CUDA → CPU |
| `jetson-gpu` | TX2, JetPack 4.5 (L4T r32.5) | `l4t-base:r32.5.0` | `onnxruntime-gpu 1.10.0` (cp36 휠) | CUDA (JetPack 4.5에서는 TensorRT EP 미지원) |
| `jetson-cpu` | 임의의 arm64 Jetson | `python:3.11-slim` (arm64) | `onnxruntime` (CPU) | CPU |

시작 전에 알아두어야 할 TX2 GPU 프로필의 두 가지 함의:

- **ONNX opset 상한.** ONNX Runtime 1.10은 **opset 15**까지 지원합니다. TX2 대상 모델은
  `--opset 15`로 내보내세요(번들은 이 때문에 opset-15 모델을 시드로 제공합니다). 최신 JetPack
  휠을 사용하는 신형 Jetson은 opset 17을 허용합니다.
- **고정된 Python 3.6 의존성 집합.** JetPack 4.5는 Python 3.6에 고정되어 있으므로,
  `jetson-gpu` 이미지는 핀 고정된 레거시 의존성 포크를 사용합니다. 신규 플릿에는 `jetson`
  (Orin/JetPack 5)을 권장합니다.

## 사전 요구사항 (Jetson 장치에서)

이미지는 **장치에서 네이티브로** 빌드됩니다. QEMU를 사용해 L4T 이미지를 크로스 빌드하는
방식은 불안정하며 지원되지 않습니다.

```bash
docker version              # >= 20.10
docker compose version      # Compose v2 plugin required
sudo apt-get install -y zstd openssl
df -h ~                     # keep a few GB free (TX2 eMMC is small)
docker info | grep -i nvidia   # GPU profiles: NVIDIA container runtime must be wired in
```

GPU 프로필의 경우, [Jetson Zoo](https://elinux.org/Jetson_Zoo#ONNX_Runtime)에서 사용 중인
JetPack 버전과 일치하는 ONNX Runtime 휠을 선택하세요. x86용 `onnxruntime-gpu` pip 휠은
Jetson에서 동작하지 **않습니다**(x86 CUDA 라이브러리를 링크하므로, 시작 시 "missing library"가
전형적인 증상입니다).

## 빌드 → 번들 → 설치

```mermaid
flowchart LR
  A["build-release-images.sh\n(build + tag 3 images)"] --> B["build-release-bundle.sh\n(docker save → dist/&lt;profile&gt;-&lt;version&gt;/)"]
  B --> C["install.sh on the target\n(load images → compose up → seed admin)"]
  A -. "build host: Jetson, internet once" .-> B
  C -. "target host: air-gapped OK" .-> C
```

1. **이미지를 빌드합니다** (빌드용 Jetson에서, 최초 1회 인터넷 필요):

   ```bash
   # GPU profile — pass the JetPack-matched ONNX Runtime wheel
   ORT_WHEEL_URL="https://<jetson-zoo-wheel-for-your-jetpack>.whl" \
     ./scripts/build-release-images.sh <version> --profile jetson-gpu

   # CPU profile — no wheel needed
   ./scripts/build-release-images.sh <version> --profile jetson-cpu
   ```

   첫 GPU 빌드 전에, 프로브 스크립트로 휠과 GPU 접근을 사전 검증하세요.
   `./scripts/spike-jetson-gpu.sh` (GO/NO-GO 확인).

2. **오프라인 번들을 패키징합니다:**

   ```bash
   ./scripts/build-release-bundle.sh --profile jetson-gpu --version v<version>
   ```

   출력 `dist/jetson-gpu-v<version>/`에는 무결성 매니페스트가 포함된 압축 이미지 아카이브,
   Tegra에 맞는 compose 파일, 시드 모델, 그리고 `install.sh` / `update.sh` / `uninstall.sh`
   런북 스크립트가 들어 있습니다. 이는
   [오프라인 번들 설치](/ko/install-deploy/offline-bundle-install/)에서 설명한 x86 번들과
   동일한 레이아웃입니다.

3. **대상 장치에 설치합니다** (번들 디렉터리를 USB/scp로 복사):

   ```bash
   cd dist/jetson-gpu-v<version>
   sudo ./install.sh                    # auto-detects arm64 and accepts jetson-* bundles
   # sudo ./install.sh --with-systemd   # optional: start on boot
   ```

   설치 프로그램은 아카이브 체크섬을 검증하고, 이미지를 로드하며, 고유한 JWT 시크릿과 관리자
   비밀번호를 생성하고, 스택을 시작하며, 헬스를 기다린 뒤, 대시보드 URL과 관리자 비밀번호를
   **한 번만** 출력합니다. 즉시 저장하세요.

4. **GPU 추론이 실제로 동작하는지 검증합니다:**

   ```bash
   docker compose -f compose/docker-compose.release.yml ps                   # 3 services healthy
   docker inspect aiboard-inference-real --format '{{.HostConfig.Runtime}}'  # expect: nvidia
   docker logs aiboard-inference-real 2>&1 | grep -iE "CUDA EP|provider"     # CUDA/TensorRT EP active
   curl -s http://localhost:5000/api/system/metrics | grep -oE '"gpu"[^}]*}' # real GPU metrics
   ```

## Tegra 특유의 동작

Jetson 번들 compose는 의도적으로 x86과 다릅니다:

- **`runtime: nvidia`** 및 추론 컨테이너 내부의 root — Tegra에서 GPU 장치 접근을 위해
  필요합니다.
- **`/sys` 마운트** — GPU 부하와 온도는 Tegra sysfs에서 가져옵니다(Jetson에는 `nvidia-smi`가
  없습니다). 대시보드의 GPU 패널에 공급됩니다.
- **`OPENBLAS_CORETYPE`** 핀 — Tegra 코어에서 OpenBLAS 잘못된 명령어(illegal-instruction)
  크래시를 방지합니다.
- **필드별 N/A 메트릭** — Jetson이 보고할 수 없는 대시보드 헬스 필드는 가짜 0 대신 **N/A**로
  표시됩니다.

실행 공급자 선택은 x86과 동일하게 동작합니다. `EXECUTION_MODE=auto`는 TensorRT → CUDA → CPU
순으로 시도하고 성능이 저하되면 경고를 로깅합니다. 박스가 조용히 CPU로 폴백하지 않는다는
확실한 보장을 원하면, `EXECUTION_MODE=cuda`(또는 `tensorrt`)와 `STRICT_EP=1`을 설정하세요.
그러면 서비스는 성능을 저하시키는 대신 시작을 거부합니다.
[실행 공급자가 CPU로 폴백함](/ko/troubleshooting/execution-provider-fallback/)을 참조하세요.

`jetson-gpu` / `jetson-cpu` 번들은 빌드 및 랩 검증이 완료되었습니다. 깨끗한 TX2에서 에어갭
설치의 최종 엔드투엔드 검증은 아직 진행 중입니다. 첫 온디바이스 설치 중에는 시리얼/SSH 콘솔을
사용할 수 있도록 유지하세요.

## Jetson 라인의 버전 관리

Jetson 릴리스는 `VERSION` 파일로만 버전이 매겨집니다. Jetson 라인은 제품 `v*` 태그를 결코
생성하지 않습니다. 대시보드의 About 패널과 번들 사이에 버전 차이가 보이면, Git 태그가 아니라
번들 매니페스트와 비교하세요. [버전 및 업데이트](/ko/operate/versioning/)를 참조하세요.

## 문제가 발생하면

| 증상 | 해결 |
|---|---|
| `unknown shorthand flag: 'f' in -f` | Compose v2 플러그인 누락 — `sudo apt-get install -y docker-compose-plugin` |
| 빌드 중 `Cannot autolaunch D-Bus` | 헤드리스 크리덴셜 헬퍼 문제 — 빌드 스크립트가 자동으로 격리합니다. 임시 `docker` 명령에는 비어 있는 `DOCKER_CONFIG` 디렉터리를 사용하세요 |
| GPU 컨테이너: `no CUDA-capable device` | 호스트에 NVIDIA container runtime이 없거나, compose에 `runtime: nvidia`가 없습니다(번들 compose에는 이미 설정되어 있습니다) |
| 추론이 missing-library 오류로 종료됨 | JetPack에 맞지 않는 ONNX Runtime 휠 — Jetson Zoo에서 일치하는 휠을 선택해 재빌드하세요 |
| `install.sh`: "profile does not match bundle" | `--profile jetson-gpu`(또는 `jetson-cpu`)를 명시적으로 전달하세요 — 둘 다 arm64에서 유효합니다 |
| 업로드 시 모델 거부됨 (TX2) | opset > 15로 내보낸 모델 — ONNX Runtime 1.10을 위해 `--opset 15`로 다시 내보내세요 |

## 다음 단계

  - [오프라인 번들 설치](/ko/install-deploy/offline-bundle-install/) — 모든 프로필이 공유하는 전체 에어갭 설치 런북.
  - [하드웨어 설정](/ko/install-deploy/hardware-setup/) — 실행 공급자 모드와 네트워크 사전 요구사항.
  - [modelctl로 모델 준비하기](/ko/configure/prepare-models/) — 장치에 맞는 opset으로 ONNX 모델을 내보냅니다.
  - [GPU / CUDA 오류](/ko/troubleshooting/gpu-cuda-error-500/) — GPU 가시성과 CUDA 실패를 문제 해결합니다.
