[TIL] 폐쇄망에서 Node.js 바이너리 배포하기

iamwoosung·2025년 1월 13일

TIL

목록 보기
3/5

📌 개요

프로젝트를 진행하다 폐쇄망 현장에서 커스터마이징과 배포를 진행하게 되었다. 개발 언어나 DBMS, IDE는 네트워크 없이 수동 설치가 가능했지만 node.js를 바이너리 형식(.exe)으로 배포하려니 관련 라이브러리가 의존성 이슈로 동작하지 않았다.


약 일주일가량 구글링과 삽질 끝에 문제를 해결하게 된 내용을 기록한다.






📌 개발 환경과 라이브러리

node.js로 개발을 하면서 Docker나 클라우드의 VM 인스턴스에 배포한 경험은 있었지만 폐쇄망에서 바이너리(.exe) 형식의 배포는 처음이었다. 배포된 .exe 파일을 Node.js가 설치되지 않은 윈도우 서버 OS에서 윈도우 서비스 형식으로 구동하는 것까지가 클라이언트의 요청이었다.


✨ 개발 및 구축 환경

🍀 개발 환경
OS: Windows 10
IDE: Visual Studio Code
Node.js Version: 18.13.0
NPM Version: 8.19.3
Network: 폐쇄망

🍀 구축 환경
OS: Windows Server OS
Program Release Type: Windows Service
Node.js Version: 미설치
Network: 폐쇄망




✨ pkg 라이브러리

node.js 배포 시 사용하려는 라이브러리는 pkg 라이브러리이다.
npm 내용을 참고하면 배포된 실행파일은 node.js나 라이브러리가 설치되지 않은 환경에서도 실행 가능하다. 개발 시 사용된 라이브러리(node_modules dir)들이 같이 패키징 되기 때문이다.

This command line interface enables you to package your Node.js project into an executable that can be run even on devices without Node.js installed.




✨ pkg 사용(희망편)

정상적으로 네트워크가 설정되어 있다면 아래와 같이 동작된다.




🍀 설치

npm i pkg




🍀 설정
app.js express 예제

const express = require('express');
const app = express();

app.get('/test', (req, res) => {
    res.json({
        result: 'Success',
    });
});

app.listen(3000, () => {
    console.log(`server is listening at localhost:${ 3000 }`);
});

package.json

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1", 
    "build": "pkg ."
  },
  "bin": "./app.js",
  "pkg":{
    "scripts": [
      "./app.js"
    ],
    "targets": [
      "node18-win-x64"
    ], 
    "outputPath": "dist"
  }, 
  • build: pkg .: npm run build 입력 시 패키징 모듈이 실행
  • bin: ./app.js: .exe 파일 실행 시 app.js가 구동되도록 설정
  • scripts: [./app.js]: 패키징에 포함할 주요 파일
  • targets: [node18-win-x64]: 패키징 환경(Node.js 버전, OS, 비트)
  • outputPath: dist: 결과물을 출력할 디렉토리 위치
  • assets: [views/**/*]: 위 예제에서 사용하지 않았지만 Vue, React 등 프론트 결과물을 views 디렉터리 안에 포함하여 패키징 가능하다.




🍀 패키징

npm run build




🍀 실행

바이너리를 실행하게 되면 Console가 팝업되고 웹 브라우저에서 express 서버가 실행된 localhost:3000/test 접속 시 정상 동작하는 것을 확인할 수 있다.






📌 해결 방법

✨ pkg 사용(절망편)

하지만 내가 경험한 환경은 폐쇄망이기 때문에 라이브러리 사용을 위해서는 수동으로 붙여 넣거나, proxy를 통해서 다운로드해야만 했다. 하지만 빌드를 하게 되면 아래와 같이 일부 파일이 누락되었다고 에러가 발생한다.

> pkg@5.8.0
> Targets not specified. Assuming:
  node18-linux-x64, node18-macos-x64, node18-win-x64
> Fetching base Node.js binariees to PKG_CACHE_PATH
  fetched-v18.2.0-linux-x64            [] 0%> Not found in remote cache: 
  {"tag":"v3.4", "name":"node-v18.5.0-linux-x64"}

와이어샤크로 패킷을 확인하니, 빌드 시 pkg 모듈이 실행되면서 node.org로 Request 패킷을 요청하고 있었다. 폐쇄망이니 패킷이 송신될 리가 없기 때문에 에러가 발생하는 것으로 추론하였다.




✨ 해결 방법

pkg 모듈이 실행될 때 요청하는 파일을 강제로 넣어주면 해결될 거 같았다. 문제는 어떤 파일을 어디에 넣어주어야 하는지였다.




🍀 파일 수동 다운로드

역시나 같은 문제로 앓는 이들이 존재했고 Github에 업로드되어 있는 Assets 중 개발 환경에 맞는 파일을 다운로드할 수 있었다. (node-version-os-bit 포맷)




🍀 파일 수동 설정

에러 로그 마지막 줄의 tagname 키가 힌트였다.

{"tag":"v3.4", "name":"node-v18.5.0-linux-x64"}

Windows OS 기준 C:\Users\{사용자명}\.pkg-cache\v3.4 디렉토리를 생성하고 다운로드 한 파일을 붙여 넣은 후, 파일명을 fetched로 변경한다.


빌드 성공!..






📌 후기

해결 과정만 간단하게 작성했지만, 실제는 일주일가량의 시행착오가 있었다.
사실 중간에 포기하고 개발망 구성을 요청하려 했는데, 망 구성까지 이주 정도 소요된다 하였고 데드라인을 넘게 될 거 같아 다시 삽질을 시작했다. (역시 안되는 건 없다..)






📌 레퍼런스

(Assets) https://github.com/vercel/pkg-fetch?tab=readme-ov-file
(Packaging) https://blog.outsider.ne.kr/1379
(Issue) https://stackoverflow.com/questions/67076767/nodejs-pkg-error-not-more-than-one-entry-file-directory-is-expected
(Issue) https://copycd.tistory.com/62
(Issue) https://www.reddit.com/r/node/comments/1bnfpdg/packaging_nodejs_script_to_exe/?rdt=53063

0개의 댓글