App Deploy (OTA)
App Deploy는 Deplite가 배포 서버(OTA) 역할을 하도록 해주는 기능이에요.
아티팩트를 조직 스토리지에 보관하고, 기기는 온라인이 될 때 스스로 최신 릴리스로 수렴해요.
키오스크나 현장 단말처럼 항상 켜져 있지 않은 기기에 적합해요.
왜 필요한가요
기존 배포는 push 방식이에요.
트리거가 발화하면 Deplite가 Agent에게 deploy 이벤트를 밀고, 그 순간 Agent가 오프라인이면 job이 즉시 rejected로 끝나요.
항상 온라인인 서버에는 문제가 없지만, 꺼져 있을 수 있는 기기에는 맞지 않아요.
App Deploy는 반대 방향으로 동작해요.
발화 시점에 기기 상태를 신경 쓰지 않고, 릴리스를 게시해 두면 각 기기가 온라인이 되는 순간 알아서 최신으로 따라와요.
보안 원칙은 그대로예요
적용(설치·재시작) 로직은 여전히 고객 workflow yaml에만 있어요.
Deplite가 아는 것은 두 가지뿐이에요.
- 실행할 로컬 workflow 이름 (
Application.updateWorkflowName, 예:app-update) - 배포할 아티팩트 (스토리지에 보관된 파일)
OTA 적용은 결국 “이 아티팩트를 파라미터로 넣어 기기의 로컬 app-update.yaml을 실행한다”라는 뜻이에요.
어떻게 설치하고 재시작하는지는 전부 고객 워크플로우 안에만 있어요.
별도의 실행 엔진이 새로 생기지 않고, 기존 Job·로그·결과 인프라를 그대로 사용해요.
Deplite는 아티팩트의 내용이나 설치 절차를 해석하지 않아요.
“어떤 아티팩트를 어떤 워크플로우로 넘길지”만 결정하고, 실제 적용 방식은 워크플로우에 위임해요.
데이터 모델
App Deploy는 세 가지 개념으로 이루어져 있어요.
Application
배포 대상 앱 하나를 표현해요.
적용에 쓸 workflow 이름(updateWorkflowName), 기본 채널(defaultChannel, 기본값 stable), 조직 내에서 유일한 slug를 가져요.
Release — 게시 후 불변
하나의 배포 단위예요.
게시(publish)하고 나면 내용이 바뀌지 않아요.
| 필드 | 의미 |
|---|---|
sequence | app 범위에서 단조 증가하는 정수. 순서의 진실원본 (max+1) |
version | 사람이 읽는 라벨. 표시 전용 |
channel | stable / beta 또는 임의 채널 |
fileId | 배포할 아티팩트 참조 |
checksumSha256 | 업로드 시 제공. Agent가 다운로드 후 검증 |
updatePolicy | optional 또는 mandatory |
status | draft → published → yanked |
AppDevice
앱과 Agent를 묶고, 그 기기의 현재 상태를 담아요.
구독 중인 channel, 관측된 현재 릴리스(currentReleaseId 등), 희망 릴리스(targetReleaseId), state(idle·pending·updating·failed), 그리고 기기당 in-flight job을 1개로 보장하는 activeJobId를 가져요.
순서는 sequence로 판단해요
릴리스의 순서는 전부 sequence로 결정해요.
sequence는 앱 범위에서 단조 증가하는 정수라서, 어느 릴리스가 더 최신인지 항상 명확하게 비교돼요.
version은 사람이 읽기 위한 표시용 라벨이에요.
Deplite는 version 문자열을 semver로 파싱하거나 비교하지 않아요.
그래서 표시 라벨을 자유롭게 붙여도 배포 순서에는 영향을 주지 않아요.
롤아웃 모델 — 채널 최신 자동
각 기기는 자기 채널을 구독하고, 그 채널의 최신 published 릴리스로 항상 수렴해요.
desired = 채널에서 sequence가 가장 큰 published 릴리스새 릴리스를 게시하면 해당 채널을 구독하는 기기들의 desired가 갱신되고, 온라인이 되는 순간부터 그쪽으로 따라와요.
강제성은 2단계예요
업데이트의 급함 정도는 릴리스의 updatePolicy로 표현해요.
| 정책 | 의미 | 기기 동작 |
|---|---|---|
mandatory | 브레이킹 체인지. 최소 버전 마커 | 이보다 낮은 기기는 강제 업데이트 (defer 불가) |
optional | 기능 개선 | 최신으로 수렴하되 여유 있을 때 미룰 수 있음 |
강제 여부는 채널의 최소 버전 마커를 기준으로 판단해요.
minSequence = 채널에서 published + mandatory 중 sequence 최대
forced = currentSequence == null || currentSequence < minSequence강제 여부의 판단은 Deplite 서버가 하고, 강제의 집행(앱 차단 등)은 Agent가 해요.
서버는 “이 기기는 지금 반드시 올라와야 한다”라고 알려주고, 실제로 어떻게 막을지는 워크플로우와 Agent가 정해요.
오프라인 내구성
App Deploy의 핵심은 job이 오프라인을 견딘다는 점이에요.
Job에는 deliveryMode가 있어요.
| 값 | 오프라인일 때 |
|---|---|
push (기본) | 즉시 rejected — 기존 트리거 배포 동작 그대로 |
durable (OTA) | queued 상태를 유지하고, Agent 재접속 시 재전송 |
durable job은 params를 저장해 두지 않아요.
재전송할 때마다 Release에서 params를 다시 만들어요.
덕분에 다운로드용 presigned URL이 언제 재전송되어도 항상 신선한 상태로 전달돼요.
아티팩트 규칙
릴리스에 쓰는 아티팩트는 반드시 cleanupRule='persistent'로 업로드해야 해요.
그래야 릴리스 생성이 통과하고, 스토리지 정리 작업이 그 파일을 회수하지 않아요.
참조 중인 아티팩트는 삭제가 막혀 있어요.
draft나 published 릴리스가 가리키는 파일을 지우려고 하면 409로 차단돼요.
지워야 한다면 먼저 릴리스를 yank한 다음 파일을 삭제해주세요.
아티팩트를 임시(정리 대상) 규칙으로 업로드하면 릴리스 생성이 통과하지 못해요.
App Deploy용 파일은 항상 persistent로 올려주세요.
운영 노트
- durable queued 만료 — durable job은 오프라인이라고 reject되지 않지만, 30일을 넘기면
rejected(durable_expired)로 정리돼요. 그보다 오래 꺼져 있던 기기는 다시 켜졌을 때 최신 릴리스로 새로 수렴해요. - yank = 롤백 — 릴리스를 yank하면
desired가 직전 published 릴리스로 내려가고, 기기들이 그쪽으로 수렴해요(다운그레이드). 이때 로컬 워크플로우가 다운그레이드를 감당할 수 있어야 해요. - OTA job은 목록에 안 떠요 — OTA job은
triggerId가 없어서 트리거 기준 job 목록에는 나타나지 않아요. 대시보드에서는AppDevice.activeJobId로 해당 job에 접근해 로그·상태·취소를 확인할 수 있어요.
Agent가 수렴하는 방식
각 기기는 서명된 매니페스트를 받아 desired 릴리스를 확인해요.
매니페스트에는 현재/희망 릴리스, 강제 여부(forced), 다운로드 정보가 담겨 있어요.
Agent는 등록 시 받은 serverPublicKey로 서명을 검증하고, 아티팩트를 받은 뒤 checksumSha256으로 무결성을 확인해요.
서명된 매니페스트는 push된 durable job을 보완하는 pull 폴백이자 Agent의 자가 점검 수단이에요.
어느 경로로 받든 결과는 같아요 — 기기가 채널 최신으로 수렴해요.
자세한 요청·응답 형식과 엔드포인트는 엔드포인트 문서를 참고해주세요.