INNORIX
전송 빌더전송 파인더개발자리소스고객사
무료 시작하기
INNORIX

LET FILES
MOVE THEMSELVES

INNORIX는 모든 시스템과 환경에서 파일 이동과 자동화를 제공하는 엔터프라이즈 파일 인프라 기업입니다.
5,000개 이상의 기업 및 공공기관에서 사용하고 있습니다.

시작하기

  • 필요한 전송 만들기
  • 필요한 전송 찾기

주요 전송

  • 팀 업무 폴더 동기화
  • 고객에게 대용량 파일 전송
  • 여러 시스템 파일 탐색
  • FTP·SFTP·SCP·rsync 전환
  • 앱에 파일 전송 추가
  • 웹 업로드·다운로드 적용
  • AI·데이터 워크플로 구축
  • 모든 전송 둘러보기→

개발자

  • 개발자 센터
  • 구현 예제
  • API 빠른 시작
  • 개발자 가이드
  • API 레퍼런스
  • GitHub

리소스

  • 리소스 센터
  • 제품 가이드
  • 외부 서비스 연동
  • 배포 및 관리
  • 도움말 센터

고객사

  • 정부
  • 공공부문
  • 제조
  • 엔지니어링
  • 금융
  • 유통
  • IT/통신
  • 미디어
  • 의료
  • 교육

플랜

  • 가격 및 플랜

회사

INNORIX 소개

Exabyter를 찾고 계신가요?

이제 INNORIX Platform에 통합되었습니다

기타 INNORIX 제품

Al.bert — 스마트 교통 AI

글로벌 오피스

  • 미국 뉴욕
  • 대한민국 서울
  • 베트남 호찌민
  • 오피스 위치 보기→

(C)2026 INNORIX. All rights reserved.

  • 보안
  • 상태
  • 이용약관
  • 개인정보 처리방침
  • 쿠키 정책
  1. 가이드
  2. AI 모델 파일을 여러 엣지 장비에 배포하기

AI 모델 파일을 여러 엣지 장비에 배포하기

모델과 설정 파일을 엣지 장비에 배포하고 장비별 성공 여부를 확인합니다.

IT 엔지니어개발자
  • AI 학습 데이터와 모델 파일의 전체 흐름 자동화하기
  • AI 모델 파일을 여러 엣지 장비에 배포하기
  • 폐쇄망·망분리 환경에서 파일을 승인 반입·반출하기
  • 승인된 파일을 여러 지점에 동시에 배포하기
  • Azure Blob에서 사내 서버로 파일 전달하기
  • 데이터베이스 덤프, 백업, 아카이브 파일을 원격 보관처로 자동 전달하기
  • 지점·공장·엣지 장비의 파일을 중앙으로 수집하기
  • CI/CD 빌드 결과물을 여러 서버에 배포하기
  • 서로 다른 클라우드 스토리지 사이에서 파일 이동하기
  • 서로 다른 AWS 계정의 S3 버킷 사이에 파일 전송하기
  • 고객별 파일 작업 공간 제공하기
  • 고객에게 만료 조건이 있는 대용량 다운로드 링크 제공하기
  • 고객이 브라우저에서 대용량 파일을 업로드하게 하기
  • 고객 작업 공간으로 대용량 파일 직접 보내기
  • 데이터베이스 백업 파일을 오브젝트 스토리지에 보관하기
  • Datadog으로 파일 전송 실패와 복구 알림 받기
  • 웹, 앱, 업무 시스템에 파일 전송 기능 추가하기
  • 파일 도착 후 검증·변환·후속 작업 실행하기
  • NAS, 파일 서버의 대량 파일을 클라우드로 이전하기
  • FTP 배치 작업을 관리형 파일 흐름으로 전환하기
  • Google Cloud Storage에서 Amazon S3로 직접 전송하기
  • Grafana에서 파일 전송 상태 대시보드 만들기
  • 전송된 파일의 해시값으로 무결성 자동 검증하기
  • 새 파일이 생기면 지정한 곳으로 자동 전송하기
  • Kubernetes에서 오브젝트 스토리지로 결과 파일 보내기
  • Git 밖의 대용량 파일과 빌드 결과물 자동 전달하기
  • Git으로 관리하기 어려운 파일을 자동 전달하기
  • 분산 서버의 로그·진단 파일을 중앙으로 모으기
  • 미디어 원본과 처리 결과를 단계별로 자동 전달하기
  • 수신 파일을 Microsoft Defender로 검사하고 후속 처리하기
  • 여러 단계의 파일 전송을 하나의 흐름으로 자동화하기
  • 승인된 파일을 여러 팀·지점에 자동 배포하기
  • 협력사 파일을 업무 시스템으로 자동 분류하기
  • 협력사·공급망과 정기적으로 파일 교환하기
  • 매일·매주 반복되는 파일 전송 자동화하기
  • 네트워크 중단 후 파일 전송을 자동으로 재개하기
  • rsync 작업을 관리형 파일 흐름으로 전환하기
  • 정해진 시간에 반복 파일 전송 예약하기
  • 소프트웨어·펌웨어를 여러 장비에 배포하고 결과 확인하기
  • 소프트웨어 패키지를 여러 서버·지점에 배포하기
  • 팀 폴더의 변경 파일을 여러 장비에 자동 반영하기
  • 팀 업무 폴더를 여러 PC에 자동 반영하기
  • 여러 장비의 파일을 한곳에서 찾고 직접 전송하기
  • 웹사이트에 대용량 파일 업로드·다운로드 기능 추가하기
  • 채널을 구독해 새 파일을 자동으로 받기
  • Amazon S3에서 Azure Blob으로 직접 전송하기
  • Amazon S3에서 Cloudflare R2로 파일 이전하기
  • Amazon S3 파일을 Linux 서버로 자동 내려받기
  • SCP 셸 스크립트를 CLI 기반 전송으로 전환하기
  • SFTP 계정과 배치 전송을 중앙에서 관리하기
  • Slack·Teams에서 파일 전송을 실행하고 상태 알림 받기
  • Windows 폴더의 파일을 Amazon S3로 자동 업로드하기
  • Windows와 Linux 서버 사이에 파일을 직접 전송하기

시작하기#

기본 개념#

AI 모델을 엣지 환경에서 실행하는 경우 중앙 서버에서 학습하거나 준비한 모델 파일을 여러 엣지 장비에 배포해야 합니다.

예를 들어 새로운 이미지 분석 모델을 공장 카메라 장비에 배포하거나, 매장과 물류센터에 설치된 엣지 서버의 모델을 새로운 버전으로 교체할 수 있습니다.

이때 실제 배포 대상은 모델 파일 하나로 끝나지 않을 수 있습니다. 모델과 함께 추론 설정, 클래스 정보, 실행 설정 파일 등을 동일한 장비에 함께 반영해야 하는 경우가 있습니다.

                    Model Repository
                           │
              Model + Config + Metadata
                           │
                           ▼
                    Distribution Flow
                           │
          ┌────────────────┼────────────────┐
          ▼                ▼                ▼
      Edge Device 01   Edge Device 02   Edge Device 03
          │                │                │
          ▼                ▼                ▼
       Model Ready      Model Ready      Check Required

여러 장비에 파일을 직접 복사하면 장비별로 어떤 모델 버전이 반영되었는지, 필요한 설정 파일이 모두 전달되었는지 각각 확인해야 합니다.

Flow를 활용하면 모델 파일 준비 → 배포 대상 선택 → 여러 엣지 장비 병렬 전송 → 장비별 결과 확인까지 하나의 흐름으로 구성할 수 있습니다.

이 레시피에서는 중앙에 준비된 AI 모델과 설정 파일을 여러 엣지 장비에 배포하고, 장비별 파일 처리 결과와 성공 여부를 확인하는 방법을 구성합니다.

배포 구성#

엣지 장비의 모델 배포는 모든 장비에 동일한 모델을 전달하는 방식뿐 아니라, 장비 유형이나 설치 위치에 따라 서로 다른 모델과 설정을 전달하는 방식으로도 구성할 수 있습니다.

예를 들어 동일한 카메라 장비가 설치된 여러 공장에는 같은 모델을 배포하고, 다른 환경의 장비에는 별도의 모델과 설정 파일을 전달할 수 있습니다.

                  AI Model Package
                         │
             ┌───────────┴───────────┐
             │                       │
             ▼                       ▼
       Standard Model           Specialized Model
             │                       │
       ┌─────┼─────┐           ┌─────┴─────┐
       ▼     ▼     ▼           ▼           ▼
     Edge A Edge B Edge C    Edge D      Edge E
배포 방식 활용 방법
동일 배포 동일한 모델과 설정을 여러 장비에 전달
그룹 배포 장비 유형 또는 지역별 그룹에 배포
버전별 배포 장비별로 지정된 모델 버전 적용
단계 배포 일부 장비에 먼저 배포한 뒤 대상 확대
병렬 배포 여러 엣지 장비에 동시에 파일 전달

장비 수가 많아질수록 파일을 장비별로 개별 관리하기보다 배포 기준과 대상 장비를 함께 구성하는 것이 중요합니다.

파일 구성#

AI 모델을 배포할 때는 실제 모델 파일 외에도 추론에 필요한 설정과 부가 파일이 함께 사용될 수 있습니다.

예를 들어 다음과 같은 파일 구조로 모델 패키지를 구성할 수 있습니다.

model-release/
│
├── model/
│   └── inference-model.bin
│
├── config/
│   └── inference.yaml
│
├── labels/
│   └── classes.json
│
└── metadata/
    └── version.json

각 파일은 엣지 장비에서 서로 다른 용도로 사용됩니다.

파일 유형 활용 방식
모델 파일 실제 AI 추론에 사용
설정 파일 모델 실행 조건 구성
클래스 정보 분석 결과 분류에 사용
메타데이터 모델 버전과 배포 정보 확인
임시 파일 배포 대상에서 제외

이처럼 모델 패키지를 하나의 배포 단위로 구성하면 여러 파일을 각각 전송하는 대신, 실제 장비에서 필요한 파일 구성을 함께 전달할 수 있습니다.

IT 엔지니어#

장비 연결#

먼저 AI 모델이 준비된 시스템을 Source로 연결하고, 모델을 실행할 엣지 장비를 각각 Target으로 구성합니다.

엣지 장비는 동일한 네트워크에 있는 장비뿐 아니라 지점, 공장이나 원격 환경에 설치된 서버일 수도 있습니다.

                   Model Source
                 /release/model-v2
                         │
                         ▼
                    Deployment
                         │
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
       Edge-01         Edge-02        Edge-03
     /opt/model       /opt/model     /opt/model

각 Target에서는 모델 파일을 저장할 위치를 지정합니다.

장비마다 동일한 디렉터리 구조를 사용한다면 공통 경로를 적용할 수 있고, 운영 환경이 다른 경우에는 장비별 저장 위치를 다르게 구성할 수 있습니다.

구성 항목 설정 내용
Source 모델 파일이 저장된 시스템
Source Path 배포할 모델 패키지 경로
Target 모델을 실행할 엣지 장비
Target Path 장비별 모델 저장 위치
장비 그룹 동일한 모델을 받을 대상
접근 범위 파일 읽기와 저장에 필요한 권한

이를 통해 어떤 모델을 어느 장비에 배포할지 명확하게 구성할 수 있습니다.

대상 구분#

모든 엣지 장비가 동일한 역할을 수행하지 않는 경우에는 장비를 역할이나 설치 환경에 따라 구분해 배포할 수 있습니다.

예를 들어 공장 내부의 검사 장비와 외부 매장의 분석 장비가 서로 다른 모델을 사용하는 경우 각각 다른 배포 대상을 구성할 수 있습니다.

                    Deployment Flow
                           │
             ┌─────────────┼─────────────┐
             ▼             ▼             ▼
        Factory Group   Store Group   Test Group
             │             │             │
             ▼             ▼             ▼
        Model-A v2      Model-B v4   Model-A v3

이 경우 하나의 모델을 모든 장비에 일괄 배포하는 대신 장비 그룹과 모델 버전을 기준으로 대상 범위를 나눌 수 있습니다.

구분 기준 활용 방식
설치 위치 공장, 매장, 물류센터별 배포
장비 유형 동일한 하드웨어 환경별 그룹 구성
모델 종류 분석 목적에 따라 다른 모델 전달
모델 버전 버전별 대상 장비 구분
운영 단계 테스트와 운영 장비를 분리

이렇게 구성하면 새로운 모델을 배포할 때 실제 적용 대상만 선택해 필요한 장비로 전달할 수 있습니다.

배포 실행#

모델 파일과 대상 장비를 구성한 뒤에는 파일을 여러 Target으로 병렬 배포합니다.

병렬 배포를 사용하면 하나의 장비에 대한 파일 전송이 완료된 뒤 다음 장비로 순차적으로 전달하는 대신, 여러 엣지 장비를 대상으로 동시에 배포 작업을 진행할 수 있습니다.

                     Model Package
                           │
                           ▼
                     Deployment Flow
                           │
           ┌───────────────┼───────────────┐
           │               │               │
           ▼               ▼               ▼
        Edge-01          Edge-02          Edge-03
           │               │               │
           ▼               ▼               ▼
       Transferring    Completed        Transferring

장비별 배포는 각각 독립적으로 진행되므로 특정 장비의 연결 상태를 다른 대상과 구분해 확인할 수 있습니다.

예를 들어 일부 장비의 모델 배포가 완료된 상태에서 특정 장비의 연결을 추가로 확인해야 하는 경우 해당 Target의 결과를 별도로 확인할 수 있습니다.

실행 조건#

모델 배포는 새로운 파일이 준비되는 즉시 실행할 수도 있고, 운영자가 모델을 확인한 뒤 지정한 시점에 실행하도록 구성할 수도 있습니다.

특히 여러 엣지 장비에서 운영 중인 모델을 교체하는 경우에는 배포 시점과 이전 작업의 완료 상태를 함께 고려할 수 있습니다.

Model Update
     │
     ▼
┌───────────────┐
│ Release Check │
└───────┬───────┘
        │
   ┌────┼─────────┐
   ▼    ▼         ▼
Manual  Schedule  Previous
Run              Job Complete
   │    │         │
   └────┴────┬────┘
             ▼
        Deployment
실행 조건 활용 방식
Manual Run 모델 확인 후 직접 배포
Date/Time 지정된 시간에 배포
File Ready 새로운 모델 파일 준비 후 실행
After Transfer 이전 파일 준비 작업 완료 후 실행
URL Request 외부 배포 요청에 따라 실행

이를 통해 모델 파일이 아직 준비되지 않았거나 이전 작업이 완료되지 않은 상태에서 배포가 시작되는 상황을 줄일 수 있습니다.

배포 흐름#

엣지 장비의 모델 배포는 단순한 파일 전송으로 끝나지 않고, 실제 장비에 필요한 파일이 모두 반영되었는지 확인하는 과정까지 연결할 수 있습니다.

Model Package Ready
        │
        ▼
Target Selection
        │
        ▼
Parallel Distribution
        │
        ├──── Edge-01 ────┐
        ├──── Edge-02 ────┤
        └──── Edge-03 ────┘
                           │
                           ▼
                    Result Review
                           │
             ┌─────────────┴─────────────┐
             ▼                           ▼
        All Completed              Check Required
             │                           │
             ▼                           ▼
       Next Operation                Retry Target

필요한 경우 모델 배포가 완료된 이후 별도의 검증 작업이나 운영 확인 작업을 연결할 수도 있습니다.

예를 들어 모든 대상 장비에 모델 파일이 정상적으로 반영된 경우 다음 작업을 실행하고, 특정 장비에서 추가 확인이 필요한 경우 해당 장비의 상태를 확인하도록 구성할 수 있습니다.

결과 확인#

배포 작업이 실행되면 Runs에서 전체 배포 상태와 장비별 처리 결과를 확인합니다.

여러 엣지 장비에 동일한 모델을 배포하더라도 각 Target의 결과를 구분해 어느 장비까지 정상적으로 파일이 반영되었는지 확인할 수 있습니다.

실행 결과에서는 다음 항목을 확인할 수 있습니다.

확인 항목 확인 내용
Source 배포한 모델과 원본 경로
Target 모델을 전달한 엣지 장비
Model Files 배포 대상 모델과 설정 파일
Total Size 전체 배포 파일 크기
Progress 현재 장비별 진행률
Status 배포 성공과 진행 상태
Started 작업 시작 시간
Completed 작업 완료 시간

이렇게 하면 여러 장비의 파일 배포 결과를 각각의 장비에서 확인하지 않고 하나의 실행 화면에서 비교할 수 있습니다.

실패 대응#

여러 엣지 장비 중 일부에서 모델 파일이 정상적으로 반영되지 않은 경우에는 해당 Run의 상세 정보를 확인해 문제가 발생한 장비와 파일 처리 상태를 확인합니다.

예를 들어 원격 장비의 연결이 중단되었거나 지정된 모델 경로에 파일을 저장할 수 없는 경우에는 Target 연결과 경로, 접근 권한을 확인할 수 있습니다.

Deployment Run
       │
       ▼
Device Status
       │
 ┌─────┼─────────────┐
 ▼     ▼             ▼
Edge-01 Edge-02    Edge-03
  ✓       ✓           !
                      │
                      ▼
                 View Details
                      │
           ┌──────────┼──────────┐
           ▼          ▼          ▼
       Connection    Path    Permission
           │          │          │
           └──────────┼──────────┘
                      ▼
                    Adjust
                      │
                      ▼
                     Retry
                      │
                      ▼
                  New Result

실패가 발생한 경우에는 다음 항목을 함께 확인할 수 있습니다.

확인 항목 확인 내용 후속 작업
장비 연결 엣지 장비의 연결 상태 Target 연결 확인
저장 경로 모델 파일 반영 위치 경로 조정
접근 권한 파일 저장 가능 여부 권한 설정 확인
파일 상태 모델과 설정 파일 처리 결과 파일별 상태 확인
실행 기록 Run 상세 정보와 실행 이력 필요한 대상 재실행

문제가 해결된 뒤에는 모든 장비의 배포 작업을 다시 구성하는 대신 추가 확인이 필요한 Target을 중심으로 필요한 작업을 다시 실행할 수 있습니다.

재실행 후에는 새로운 Run을 통해 모델과 설정 파일이 해당 엣지 장비에 정상적으로 반영되었는지 확인합니다.

이 과정을 통해 모델 파일 준비 → 배포 대상 구성 → 장비 그룹 구분 → 병렬 배포 → 장비별 파일 반영 → 결과 확인 → 실패 대상 대응까지 이어지는 AI 모델 배포 흐름을 구성할 수 있습니다.

여러 엣지 장비에 모델과 설정 파일을 배포하고 장비별 성공 여부를 함께 관리하면, 새로운 모델을 실제 운영 환경에 반영하는 과정을 개별 장비 작업이 아닌 하나의 관리형 Flow로 운영할 수 있습니다.

개발자#

모델과 설정 파일을 여러 엣지 장비에 배포하고 장비별 성공 여부를 확인하기

소스와 대상 엣지 장비들을 장비로 등록한 뒤, 장비별 전송을 만들어 함께 대기하고 성공 여부를 집계합니다. 시작 전에 다음 항목을 준비합니다.

준비물 내용
INNORIX 인증 INNORIX_ACCESS_TOKEN (Authorization: Bearer)
소스 장비 모델 원본의 device ID와 경로 (예: /registry/model/v3)
대상 엣지 장비 각 엣지 장비의 device ID와 저장 경로 (예: /opt/models)
런타임 Python 3 + requests · Java 17+ · Node.js 18+ · .NET 8+

Python·Node.js는 REST를 직접 호출하는 최소 api() 헬퍼와 상태 상수(STATUS_COMPLETE·TERMINAL)를 API 호출 레시피의 것을 재사용합니다. Java·C#은 번들 소스의 InnorixClient(상수 포함)와 Json(C#은 J) 헬퍼를 사용합니다. 장비 식별자와 경로는 실제 값으로 바꿔 넣습니다.

여러 엣지 장비에 모델 배포#

대상마다 전송을 만들어 monitorId를 먼저 모은 뒤 전체를 대기합니다. 모델 파일이 원본과 동일하게 전달됐는지 확인하기 위해 checkIntegrity를 켭니다. 전송 생성 자체가 실패한 장비(오프라인 등)는 전송 중 실패와 구분해 따로 수집합니다.

import time


def deploy_model(source, source_path, targets, target_path, action="overwrite"):
    monitors, start_failed = {}, []
    for device in targets:
        try:
            transfer = api("POST", "/api/transfers/manual", {
                "sourceDevice": source,
                "targetDevice": device,
                "targetPath": target_path,
                "sourcePaths": [source_path],
                "sendAllFolder": True,
                "checkIntegrity": True,   # verify model file integrity after transfer
                "transferOptions": {"target-action": action},
            })
            monitors[device] = transfer["monitorId"]
        except Exception:
            start_failed.append(device)   # device whose transfer creation itself failed (e.g. offline)

    results = {}
    for device, monitor_id in monitors.items():
        detail = wait_transfer(monitor_id)
        results[device] = detail.get("status") == STATUS_COMPLETE
    # report devices that never started separately from in-transfer failures
    return {"results": results, "start_failed": start_failed}


def wait_transfer(monitor_id, timeout=14400, interval=5):
    deadline = time.time() + timeout
    while time.time() < deadline:
        detail = api("GET", f"/api/transfers/{monitor_id}") or {}
        if detail.get("status") in TERMINAL:
            return detail
        time.sleep(interval)
    raise TimeoutError(monitor_id)


out = deploy_model("model-src", "/registry/model/v3",
                   ["edge-01", "edge-02", "edge-03"], "/opt/models")
results, start_failed = out["results"], out["start_failed"]
ok = [d for d, c in results.items() if c]
print(f"ok {len(ok)} / started {len(results)} / start-failed {len(start_failed)}")
for device, complete in results.items():
    if not complete:
        print("  transfer failed:", device)
for device in start_failed:
    print("  start failed (check connection):", device)
// returns: results (success after the transfer started) + startFailed (devices whose transfer creation failed)
static Map<String, Object> deployModel(InnorixClient client, String source, String sourcePath,
        List<String> targets, String targetPath, String action) throws InterruptedException {
    Map<String, String> monitors = new LinkedHashMap<>();
    List<String> startFailed = new ArrayList<>();
    for (String device : targets) {
        try {
            Map<String, Object> transfer = client.apiObj("POST", "/api/transfers/manual", Json.newObj(
                    "sourceDevice", source,
                    "targetDevice", device,
                    "targetPath", targetPath,
                    "sourcePaths", List.of(sourcePath),
                    "sendAllFolder", true,
                    "checkIntegrity", true,   // verify model file integrity after transfer
                    "transferOptions", Json.newObj("target-action", action)), null);
            monitors.put(device, Json.str(transfer, "monitorId"));
        } catch (Exception ex) {
            startFailed.add(device);   // transfer creation failed (e.g. offline)
        }
    }

    Map<String, Boolean> results = new LinkedHashMap<>();
    for (Map.Entry<String, String> e : monitors.entrySet()) {
        Map<String, Object> detail = waitTransfer(client, e.getValue(), 14400, 5);
        Integer status = Json.intOrNull(detail, "status");
        results.put(e.getKey(), status != null && status == InnorixClient.STATUS_COMPLETE);
    }
    return Json.newObj("results", results, "startFailed", startFailed);
}

static Map<String, Object> waitTransfer(InnorixClient client, String monitorId,
        long timeoutSec, long intervalSec) throws InterruptedException {
    long deadline = System.currentTimeMillis() + timeoutSec * 1000;
    while (System.currentTimeMillis() < deadline) {
        Map<String, Object> detail = client.apiObj("GET", "/api/transfers/" + monitorId, null, null);
        Integer status = Json.intOrNull(detail, "status");
        if (status != null && InnorixClient.TERMINAL.contains(status))
            return detail;
        Thread.sleep(intervalSec * 1000);
    }
    throw new RuntimeException("timeout: " + monitorId);
}
async function deployModel(source, sourcePath, targets, targetPath, action = "overwrite") {
  const monitors = {};
  const startFailed = [];
  for (const device of targets) {
    try {
      const transfer = await api("POST", "/api/transfers/manual", {
        sourceDevice: source,
        targetDevice: device,
        targetPath,
        sourcePaths: [sourcePath],
        sendAllFolder: true,
        checkIntegrity: true,   // verify model file integrity after transfer
        transferOptions: { "target-action": action },
      });
      monitors[device] = transfer.monitorId;
    } catch {
      startFailed.push(device);   // transfer creation failed (e.g. offline)
    }
  }

  const results = {};
  for (const [device, monitorId] of Object.entries(monitors)) {
    const detail = await waitTransfer(monitorId);
    results[device] = detail.status === STATUS_COMPLETE;
  }
  return { results, startFailed };
}

async function waitTransfer(monitorId, { timeout = 14400, interval = 5 } = {}) {
  const deadline = Date.now() + timeout * 1000;
  while (Date.now() < deadline) {
    const detail = (await api("GET", `/api/transfers/${monitorId}`)) || {};
    if (TERMINAL.has(detail.status)) return detail;
    await new Promise((r) => setTimeout(r, interval * 1000));
  }
  throw new Error(`timeout: ${monitorId}`);
}

const { results, startFailed } = await deployModel("model-src", "/registry/model/v3",
                                  ["edge-01", "edge-02", "edge-03"], "/opt/models");
const ok = Object.values(results).filter(Boolean).length;
console.log(`ok ${ok} / started ${Object.keys(results).length} / start-failed ${startFailed.length}`);
for (const [device, complete] of Object.entries(results))
  if (!complete) console.log("  transfer failed:", device);
for (const device of startFailed) console.log("  start failed (check connection):", device);
// returns: results (success after the transfer started) + startFailed (devices whose transfer creation failed)
static async Task<(Dictionary<string, bool> results, List<string> startFailed)> DeployModelAsync(
    InnorixClient client, string source, string sourcePath, IEnumerable<string> targets,
    string targetPath, string action = "overwrite")
{
    var monitors = new Dictionary<string, string>();
    var startFailed = new List<string>();
    foreach (string device in targets)
    {
        try
        {
            var transfer = await client.ApiObjAsync("POST", "/api/transfers/manual", new JsonObject
            {
                ["sourceDevice"] = source,
                ["targetDevice"] = device,
                ["targetPath"] = targetPath,
                ["sourcePaths"] = J.ArrOfStrings(new[] { sourcePath }),
                ["sendAllFolder"] = true,
                ["checkIntegrity"] = true,   // verify model file integrity after transfer
                ["transferOptions"] = new JsonObject { ["target-action"] = action },
            });
            monitors[device] = J.Str(transfer, "monitorId");
        }
        catch
        {
            startFailed.Add(device);   // transfer creation failed (e.g. offline)
        }
    }

    var results = new Dictionary<string, bool>();
    foreach (var kv in monitors)
    {
        JsonObject detail = await WaitTransferAsync(client, kv.Value);
        int? status = J.IntOrNull(detail, "status");
        results[kv.Key] = status != null && status == InnorixClient.StatusComplete;
    }
    return (results, startFailed);
}

static async Task<JsonObject> WaitTransferAsync(InnorixClient client, string monitorId,
    int timeoutSec = 14400, int intervalSec = 5)
{
    DateTime deadline = DateTime.UtcNow.AddSeconds(timeoutSec);
    while (DateTime.UtcNow < deadline)
    {
        JsonObject detail = await client.ApiObjAsync("GET", 
quot;/api/transfers/{monitorId}"
, null, null); int? status = J.IntOrNull(detail, "status"); if (status != null && InnorixClient.Terminal.Contains(status.Value)) return detail; await Task.Delay(intervalSec * 1000); } throw new TimeoutException(monitorId); }

무결성 검증 서버·장비가 대상인 전송에서는 checkIntegrity: true로 원본과 도착 파일의 체크섬을 비교할 수 있습니다. 자세한 검증 방법은 무결성 검증 레시피를 참고합니다.

오프라인 장비 구분 전송이 시작조차 되지 못한 장비는 실패 파일 목록이 비어 있을 수 있습니다. 이 경우 재시도 대신 장비 연결 상태를 먼저 확인하고, 연결이 복구된 뒤 다시 배포합니다.

실패 장비는 중단 후 재개 레시피의 retry_failed로 실패 파일만 다시 전송합니다.

구현 결과#

이 레시피를 적용하면 다음 흐름으로 모델을 여러 엣지 장비에 배포할 수 있습니다.

모델 레지스트리 (model-src)
&nbsp;&nbsp;&nbsp;↓  장비별 전송 생성(checkIntegrity) → monitorId 수집

edge-01 · edge-02 · edge-03 배포
&nbsp;&nbsp;&nbsp;↓  전체 대기 → 장비별 성공 여부 집계

실패 장비만 재배포

모델·설정 파일을 여러 엣지 장비에 배포하고 무결성을 검증하며, 장비별 성공 여부를 집계해 실패 장비만 다시 배포할 수 있습니다.

이전AI 학습 데이터와 모델 파일의 전체 흐름 자동화하기다음폐쇄망·망분리 환경에서 파일을 승인 반입·반출하기

이 페이지에서

  • 시작하기
  • 기본 개념
  • 배포 구성
  • 파일 구성
  • IT 엔지니어
  • 장비 연결
  • 대상 구분
  • 배포 실행
  • 실행 조건
  • 배포 흐름
  • 결과 확인
  • 실패 대응
  • 개발자
  • 여러 엣지 장비에 모델 배포
  • 구현 결과