본문으로 건너뛰기

폐쇄망 설치

인터넷이 닿지 않는 망에는 번들로 설치합니다. 인터넷이 되는 쪽에서 번들을 받아(또는 굽고) 서명을 검증한 뒤 매체로 옮기고, 폐쇄망에서 풀어 넣습니다.

아키텍처를 먼저 정하십시오

번들은 두 벌입니다 — arm64(GB10 계열) · amd64(AWS g7e 등). 대상 서버에서 uname -m 을 보고 고르십시오(aarch64 → arm64, x86_64 → amd64). 다른 아키텍처 번들은 이미지가 뜨지 않습니다. 반입 스크립트는 번들의 MANIFEST.txt 에 적힌 아키텍처와 이 호스트를 Docker 설치 전에 대조하고, 어긋나면 멈춥니다.

번들은 큽니다 — 약 25GB

vLLM 이미지가 대부분입니다. 옮길 매체와 대상 디스크 여유를 미리 확인하십시오.

1단계 — 번들 받기 (인터넷 쪽)​

배포 서버에서 본문과 사이드카 넷, 모두 다섯 파일을 받습니다.

ARCH=arm64 # 또는 amd64
B=plantpulse-ai-images-latest-$ARCH.tar.gz
for f in "$B" "$B.sha256" "$B.sha256.sig" "$B.pub" "$B.cosign.sha256"; do
curl -fL -C - --retry 10 --retry-delay 5 --retry-all-errors \
-O "https://product.kopens.io/plantpulse-ai/$f"
done
파일무엇
<번들>.tar.gz본문
.sha256본문의 체크섬
.sha256.sig그 체크섬에 대한 cosign 서명 — 서명은 수십 GB 본문이 아니라 체크섬 파일에 붙습니다
.pub검증 공개키
.cosign.sha256번들 안에 든 cosign 실행 파일의 sha256 (아래 「번들 안 cosign」)
끊기면 같은 명령을 다시 돌리십시오

-C - 가 이어받기, --retry-all-errors 가 재시도입니다. 큰 파일이 CDN 쪽 오류로 끊기는 일이 있는데, 다시 돌리면 받은 데서부터 이어갑니다.

2단계 — 서명 검증​

검증하지 않은 번들은 쓰지 않습니다. 받은 다섯 파일을 한 디렉터리에 두고 풀어서 검증합니다.

sudo -i
mkdir -p /opt/kopens && tar -xzf "$B" -C /opt/kopens
bash /opt/kopens/plantpulse-ai-images/repo/bin/verify-bundle.sh "$B"

verify-bundle.sh 가 차례로 보는 것입니다. 하나라도 어긋나면 거기서 멈춥니다.

  1. cosign 을 실행할 수 있는가 — COSIGN_BIN → PATH 의 cosign → 번들의 tools/cosign-linux-<arch> 순
  2. 사이드카(.sha256 · .sha256.sig · 공개키)가 번들 옆에 있는가. 저장소의 공개키와 받은 .pub 가 둘 다 있으면 바이트까지 같아야 합니다
  3. 서명이 체크섬 파일에 대해 유효한가
  4. 체크섬 파일에 적힌 이름이 이 번들의 이름인가
  5. 번들의 바이트가 서명된 체크섬과 맞는가
종료 코드뜻
0검증됨
1검증 실패 — 그 번들을 쓰지 마십시오
2검증하지 못함(도구나 사이드카가 없음) — 통과가 아닙니다

번들 안 cosign 과 신뢰의 한계​

폐쇄망에는 cosign 이 없으므로 번들이 버전을 고정한 tools/cosign-linux-<arch> 를 싣고 다닙니다. 그러나 번들 안 cosign 은 번들 서명으로 보증되지 않습니다 — 서명을 확인하는 도구가 바로 그것이기 때문입니다. 그래서 그 sha256 을 세 곳에 둡니다.

어디성격
번들 MANIFEST.txt 의 tools-cosign 줄우리가 만든 사본
CDN 의 <번들>.cosign.sha256우리가 만든 사본. 번들 옆에 두면 verify-bundle.sh 가 자동 대조하고, 다르면 실패합니다
상류 sigstore 의 cosign_checksums.txt유일한 독립 대조

앞의 둘은 번들과 CDN 을 함께 바꿀 수 있는 공격자에게는 무력합니다. 인터넷 쪽에서 상류 체크섬과 한 번 대조해 두고 반입하십시오. 따로 신뢰하는 cosign 이 있으면 COSIGN_BIN=/경로/cosign 으로 넘깁니다.

3단계 — 폐쇄망으로 옮기고 반입​

번들 본문과 사이드카를 함께 옮깁니다 — 반입 스크립트가 로드 전에 다시 검증합니다.

sudo -i
mkdir -p /opt/kopens && tar -xzf "$B" -C /opt/kopens
cd /opt/kopens/plantpulse-ai-images/repo/bin
BUNDLE_TARBALL="/경로/$B" ./airgap-import.sh

풀린 모양은 이렇습니다. 형제 저장소 둘이 번들 안에 함께 들어 있으므로 따로 준비할 것이 없습니다 (어느 커밋인지는 MANIFEST.txt 의 sibling 줄에 있습니다).

/opt/kopens/plantpulse-ai-images/
├── repo/ ← 설치 본체 (bin · compose)
├── plantpulse-ai-inference-server/ ← 형제 저장소
├── plantpulse-timeseries-insight-server/ ← 형제 저장소
├── images/ ← 이미지마다 docker save 한 파일 하나씩
├── pkgs/{rpm,deb}/ ← Docker CE 오프라인 설치 패키지
├── tools/cosign-linux-<arch>
└── MANIFEST.txt

airgap-import.sh 가 순서대로 처리합니다. 각 단계가 실패하면 거기서 멈춥니다.

단계하는 일
0아키텍처 대조 · 번들 서명 검증(verify-bundle.sh)
1Docker 오프라인 설치 — Docker 가 없을 때만. 이미 있으면 저장소 · 설정을 그대로 두고 재시작하지 않습니다(ALLOW_DOCKER_RECONFIGURE=1 로 허용)
2이미지 로드 — 전부 docker load 한 뒤, 번들의 이미지 참조가 전부 이름으로 풀리는지 확인합니다
3install.sh 호출 — SKIP_LOGIN=1. 레지스트리에 붙지 않고, 이미지 pull 과 모델 자동 수신도 건너뜁니다
번들을 못 찾으면 멈춥니다

서명은 번들 옆의 사이드카로 확인하므로, 반입 때 tar.gz 가 있어야 합니다. 풀린 디렉터리의 부모(/opt/kopens)에서 하나를 찾아 쓰고, 없거나 여럿이면 BUNDLE_TARBALL 로 가리키라고 하고 멈춥니다. 검증 없이 진행하는 ALLOW_UNVERIFIED=1 이 있지만 쓰지 마십시오 — 검증되지 않은 번들을 로드하는 스위치입니다.

기본은 «준비까지»입니다

install.sh 는 /etc/kopens/plantpulse-ai.env 를 만들어 두고 멈춥니다. 기동까지 한 번에 가려면 export START=1 을 먼저 하고 airgap-import.sh 를 실행하십시오. 준비만 했다면 아래 「반입 뒤 기동 순서」를 따릅니다 — 설치기도 끝에 같은 순서를 찍어 줍니다.

2026.10 부터는 채울 값에 플랫폼 자격증명 받기 설정(PP_DATALAKE_ADMIN_URL · PP_DATALAKE_ADMIN_API_KEY)과 플랫폼 신뢰 앵커 /etc/kopens/ca/root.crt 가 들어갑니다. 폐쇄망 안에서도 AI 호스트가 플랫폼 호스트의 :4950 에 닿아야 합니다 → 설치 개요

반입 뒤 기동 순서​

  1. 남은 자리표시자를 채웁니다. 반입 출력이 CHANGE_ME_* 로 남은 키를 찍습니다(관리자 · Neo4j 비밀번호, 플랫폼 토큰, 플랫폼 자격증명 키 등). sudo 로 /etc/kopens/plantpulse-ai.env 를 고치고 권한은 0600 그대로 둡니다.
  2. vLLM 모델을 둡니다 — 아래 「모델은 번들에 없습니다」.
  3. bin/up.sh 로 띄웁니다.
cd /opt/kopens/plantpulse-ai-images/repo
sudo bin/up.sh
자리표시자가 하나라도 남으면 bin/up.sh 가 띄우지 않습니다 (2026.10)

예전 판은 START=1 경로에서만 자리표시자를 막았고, 폐쇄망처럼 나중에 compose-up.sh 로 띄우는 길은 보지 않았습니다. 그래서 관리 콘솔과 Neo4j 가 공개 템플릿에 적힌 비밀번호로 LAN 포트에 열릴 수 있었습니다. 지금은 bin/up.sh 도 남은 키 이름을 찍고 기동을 거부합니다.

bin/update.sh 는 쓰지 마십시오 — 이미지를 먼저 받으려 해서 레지스트리가 없는 폐쇄망에서는 실패합니다.

호스트 전역 설정은 HOST_TUNING 을 따릅니다

install.sh 는 로케일 · 시간대(PP_TZ) · 스왑 · chrony · limits · sysctl · tmpfiles · 방화벽을 바꿉니다. 다른 서비스의 컨테이너가 이미 도는 호스트면 기본이 plan 이라 바뀔 것만 출력합니다. 출력을 보고 필요하면 HOST_TUNING=apply 로 다시 돌리십시오 → 설치 개요

모델은 번들에 없습니다​

🔴 vLLM 모델(LLM · 임베딩 · 리랭커, 합쳐 20GB 이상)은 번들에 들어 있지 않습니다. 온라인 설치는 START=1 때 모델을 자동으로 받지만, 폐쇄망 반입은 그 단계를 건너뜁니다.

  • vLLM 모델 — 인터넷이 되는 장비에서 bin/fetch-models.sh 로 받습니다. 온라인 설치가 받는 것과 같은 출시 가중치(model.kopens.ai)이고, SHA256SUMS 와 대조한 뒤 풉니다(zstd 가 필요합니다). 받을 곳은 MODEL_BASE, 이름은 MODELS 로 줍니다.

    MODEL_BASE=/mnt/usb/models MODELS="Aura-Lite-NVFP4 Aura-Embedding-4B Aura-Reranker-0.6B" \
    bash /opt/kopens/plantpulse-ai-images/repo/bin/fetch-models.sh

    매체로 옮겨 폐쇄망 장비의 /opt/kopens/models 밑에 같은 이름의 디렉터리로 둡니다(위치를 바꿨다면 LLM_MODEL_PATH · EMB_MODEL_PATH · RERANK_MODEL_PATH 를 호스트 env 에 적습니다).

  • 시계열 추론 모델 — 반입할 것이 없습니다. plantpulse-timeseries-insight-server 이미지 안에 들어 있습니다.

  • 녹취 모델(Aura-ASR-Turbo, 약 1.5 GB) — 영상 · 음성 수집과 음성으로 묻기를 쓸 설치만 반입합니다. 녹취 이미지 (plantpulse-asr-audio, 녹취 vLLM 은 생성 vLLM 과 같은 이미지)는 번들에 늘 실려 있으므로 모델만 옮기면 됩니다. 인터넷이 되는 장비에서 스위치를 셸 환경으로 주면 vLLM 모델과 함께 받습니다(받을 곳에 이미 있는 것은 건너뜁니다).

    PI_MEDIA_ENABLED=true MODEL_BASE=/mnt/usb/models \
    bash /opt/kopens/plantpulse-ai-images/repo/bin/fetch-models.sh

    매체로 옮겨 폐쇄망 장비의 /opt/kopens/models/Aura-ASR-Turbo 에 둔 뒤, 호스트 env 에 PI_MEDIA_ENABLED=true 를 넣고 띄웁니다 → 영상 · 음성 수집. 이름만 받으려면 MODELS="Aura-ASR-Turbo" 로 줘도 됩니다. 예전 안내의 COMPOSE_PROFILES=media 를 준 실행도 여전히 이 모델을 받습니다.

download-model.sh 로 받지 마십시오

추론 서버 저장소의 tools/download-model.sh 는 상류 원본 가중치를 받아 Aura-* 이름만 붙입니다. 이름이 같아 아무 검사도 차이를 잡지 못하지만 출시 가중치가 아닙니다. 반드시 bin/fetch-models.sh 를 쓰십시오.

모델 없이 기동하면 스택은 초록으로 뜨고 LLM 만 죽습니다. 기동 전에 자리를 확인하십시오.

번들을 직접 굽는 경우​

배포 서버의 번들 대신 사내에서 구워야 할 때만 씁니다. 대상과 같은 아키텍처의 장비에서 실행합니다 — 교차 빌드는 하지 않습니다.

cd /opt/kopens/plantpulse-ai-docker/bin
./airgap-export.sh
환경 변수기본값뜻
ARCH이 호스트arm64 · amd64. 호스트와 대조해 어긋나면 멈춥니다
OS_TARGET아키텍처를 따름 — arm64 → deb, amd64 → rpmrpm · deb · both — 담을 Docker 오프라인 패키지
EXPORT_TAG오늘 날짜산출물 이름에만 쓰입니다
OUT_DIR<저장소>/dist산출물을 둘 곳

산출물은 dist/plantpulse-ai-images-<태그>-<아키텍처>.tar.gz 와 .sha256 입니다. 이미지 목록은 docker compose config --images 로 뽑으므로 손으로 적지 않습니다 — 모델을 바꾸거나 vLLM 버전을 올려도 스크립트를 고칠 필요가 없습니다. 형제 저장소 둘도 굽기에 쓴 체크아웃 그대로 함께 담깁니다.

직접 구운 번들은 서명이 없습니다

서명(.sha256.sig)은 릴리즈 파이프라인이 붙이고, 손으로 구우면 서명 단계를 건너뜁니다(로그에 「서명 건너뜀」이 찍힙니다). 서명 없는 번들은 반입 0단계 검증을 통과하지 못하므로, 특별한 이유가 없다면 배포 서버의 번들을 쓰십시오.

설치한 뒤에​

순서하는 일명령 · 문서
1기본 비밀번호를 바꾼다초기 비밀번호 변경
2스택이 살아 있는지 본다bin/status.sh · bin/health.sh
3어디가 막혔는지 짚는다bin/doctor.sh

자주 빠지는 함정​

증상원인조치
verify-bundle.sh 가 종료 코드 2cosign 이 없거나 사이드카가 빠졌다통과가 아닙니다. 사이드카 넷을 번들 옆에 두고 다시 검증한다
반입이 「번들을 찾지 못했다」로 멈춘다tar.gz 를 옮기지 않았거나 다른 곳에 있다BUNDLE_TARBALL=/경로/<번들>.tar.gz 로 가리킨다
반입이 아키텍처 불일치로 멈춘다다른 아키텍처 번들uname -m 에 맞는 번들을 받는다
로드 뒤 「이름으로 풀리지 않는 이미지」로 멈춘다번들 결함그 번들을 쓰지 말고 새 번들을 받는다
스택은 초록인데 LLM 만 안 된다모델을 반입하지 않았다위 「모델은 번들에 없습니다」
PI_MEDIA_ENABLED=true 로 띄웠는데 plantpulse-asr 만 안 뜬다녹취 모델(Aura-ASR-Turbo)을 반입하지 않았다위 「모델은 번들에 없습니다」의 녹취 모델
스택이 준비만 되고 안 뜬다START=1 을 안 줬다정상 동작이다. 위 「반입 뒤 기동 순서」대로 값을 채우고 bin/up.sh 로 띄운다
bin/up.sh 가 «still has template placeholders» 로 멈춘다자리표시자(CHANGE_ME_*)가 남았다찍힌 키를 채우고 다시 띄운다
bin/update.sh 가 이미지 pull 에서 실패한다폐쇄망에는 레지스트리가 없다bin/up.sh 를 쓴다
호스트 설정이 바뀌지 않았다다른 컨테이너가 도는 호스트라 HOST_TUNING=plan 이었다출력을 확인하고 HOST_TUNING=apply 로 다시 돌린다

관련 문서​