EdgeCtrl은 EdgeNode(클라이언트)와 PublicNode/PublicNest(서버)로 구성된 분산 제어 시스템입니다. PublicNode 또는 PublicNest는 HTTP API를 통해 외부 요청을 받아 연결된 EdgeNode에 명령을 전달하고, EdgeNode는 해당 명령을 실행하여 결과를 반환합니다.
- 역할: 클라이언트 측면에서 동작하는 프로그램
- 플랫폼: Node.js 기반, Linux, Windows, macOS 지원
- 연결: PublicNode와 Socket.IO를 통해 실시간 연결
- 기능:
- PublicNode로부터 명령 수신 및 처리
- 처리 결과를 PublicNode에 응답
- EdgeNodeID로 식별
- PublicNode 연결 끊김 시 자동 재연결 (1초×5 → 3초×5 → 10초×5 → 30초×5)
- 역할: 서버 측면에서 동작하는 중앙 서버
- 기술: Node.js + Express + Socket.IO
- 포트: 3001
- 기능:
- HTTP API를 통해 외부 요청 수신
- 연결된 EdgeNode에 명령 전달 및 응답 반환
- EdgeNodeID별 명령 전달
- 연결된 EdgeNode 상태 모니터링
/status/엔드포인트를 통한 상태 조회
- 역할: 서버 측면에서 동작하는 중앙 서버 (NestJS 기반)
- 기술: NestJS + TypeScript + Socket.IO
- 포트: 3002
- 기능:
- PublicNode와 동일한 기능 제공
- 구조화된 코드 및 타입 안정성
- HTTP API를 통해 외부 요청 수신
- 연결된 EdgeNode에 명령 전달 및 응답 반환
- EdgeNodeID별 명령 전달
- 연결된 EdgeNode 상태 모니터링
/status/엔드포인트를 통한 상태 조회
┌─────────────┐
│ User │
│ (HTTP API) │
└──────┬──────┘
│
│ HTTP Request
│ (POST /api)
│
├─────────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ PublicNode │ │ PublicNest │
│ (Port 3001) │ │ (Port 3002) │
│ │ │ │
│ Express + │ │ NestJS + │
│ Socket.IO │ │ Socket.IO │
│ │ │ │
│ - POST /api │ │ - POST /api │
│ - POST │ │ - POST │
│ /api/all │ │ /api/all │
│ - GET │ │ - GET │
│ /status/ │ │ /status/ │
└──────┬───────┘ └──────┬───────┘
│ │
│ Socket.IO │ Socket.IO
│ (command/ │ (command/
│ command_ │ command_
│ response) │ response)
│ │
└────────┬────────┘
│
┌────────┴────────┐
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ EdgeNode │ │ EdgeNode │
│ (ID1) │ │ (ID2) │
│ │ │ │
│ - hello │ │ - hello │
│ - google │ │ - google │
└──────────┘ └──────────┘
- User → PublicNode/PublicNest: HTTP POST 요청으로 명령 전달
- PublicNode/PublicNest → EdgeNode: Socket.IO를 통해 명령 전달
- EdgeNode: 명령 실행 (hello, google 등)
- EdgeNode → PublicNode/PublicNest: Socket.IO를 통해 결과 응답
- PublicNode/PublicNest → User: HTTP 응답으로 결과 반환
참고: PublicNode와 PublicNest는 동일한 기능을 제공하며, 선택적으로 사용할 수 있습니다. PublicNode는 Express 기반, PublicNest는 NestJS 기반입니다.
EdgeCtrl/
├── EdgeNode/ # EdgeNode 클라이언트
│ ├── edge_node.js # 메인 클라이언트 프로그램
│ ├── package.json # Node.js 의존성
│ └── Dockerfile # Docker 이미지 빌드 파일
│
├── PublicNode/ # PublicNode 서버 (Express)
│ ├── public_node.js # 메인 서버 프로그램
│ ├── package.json # Node.js 의존성
│ └── Dockerfile # Docker 이미지 빌드 파일
│
├── PublicNest/ # PublicNest 서버 (NestJS)
│ ├── src/ # 소스 코드
│ │ ├── main.ts # 진입점
│ │ ├── app.module.ts # 메인 모듈
│ │ ├── events.gateway.ts # Socket.IO 게이트웨이
│ │ ├── api.controller.ts # API 컨트롤러
│ │ ├── status.controller.ts # 상태 컨트롤러
│ │ └── interfaces/ # 타입 정의
│ ├── package.json # Node.js 의존성
│ ├── tsconfig.json # TypeScript 설정
│ └── Dockerfile # Docker 이미지 빌드 파일
│
├── docker-compose-public.yml # PublicNode 운영 환경 Docker Compose
├── docker-compose-publicnest.yml # PublicNest 운영 환경 Docker Compose
├── docker-compose-edge.yml # EdgeNode 운영 환경 Docker Compose
├── docker-compose-public.dev.yml # PublicNode 개발 환경 Docker Compose
├── docker-compose-publicnest.dev.yml # PublicNest 개발 환경 Docker Compose
├── docker-compose-edge.dev.yml # EdgeNode 개발 환경 Docker Compose
└── README.md # 이 파일
- Node.js 18 이상
- Docker 및 Docker Compose (Docker 사용 시)
- npm 또는 yarn
cd PublicNode
npm install
npm startPublicNode는 기본적으로 http://localhost:3001에서 실행됩니다.
cd PublicNest
npm install
npm run start:dev # 개발 모드
# 또는
npm run build
npm run start:prod # 프로덕션 모드PublicNest는 기본적으로 http://localhost:3002에서 실행됩니다.
cd EdgeNode
npm install
# 기본 EdgeNodeID로 실행 (기본값: 'default')
npm start
# 또는 특정 EdgeNodeID로 실행
EDGE_NODE_ID=node1 npm start
# 또는
node edge_node.js node1EdgeNode와 PublicNode는 별도로 배포됩니다.
운영 환경:
# PublicNode 빌드 및 실행
docker-compose -f docker-compose-public.yml up -d
# 로그 확인
docker-compose -f docker-compose-public.yml logs -f
# 서비스 중지
docker-compose -f docker-compose-public.yml down개발 환경:
# PublicNode 개발 환경으로 실행 (소스 코드 볼륨 마운트)
docker-compose -f docker-compose-public.dev.yml up
# 백그라운드 실행
docker-compose -f docker-compose-public.dev.yml up -d운영 환경:
# PublicNest 빌드 및 실행
docker-compose -f docker-compose-publicnest.yml up -d
# 로그 확인
docker-compose -f docker-compose-publicnest.yml logs -f
# 서비스 중지
docker-compose -f docker-compose-publicnest.yml down개발 환경:
# PublicNest 개발 환경으로 실행 (소스 코드 볼륨 마운트, 자동 재시작)
docker-compose -f docker-compose-publicnest.dev.yml up
# 백그라운드 실행
docker-compose -f docker-compose-publicnest.dev.yml up -d운영 환경:
# EdgeNode 빌드 및 실행
# 동일 머신에서 Docker로 실행 시: 서비스 이름 사용
PUBLIC_NODE_URL=http://publicnode:3001 EDGE_NODE_ID=node1 \
docker-compose -f docker-compose-edge.yml up -d
# 별도 머신에서 실행 시: 실제 IP 주소 또는 호스트명 사용
# PUBLIC_NODE_URL=http://192.168.1.100:3001 EDGE_NODE_ID=node1 \
# docker-compose -f docker-compose-edge.yml up -d
# 또는 .env 파일 사용
# .env 파일에 다음 내용 추가:
# EDGE_NODE_ID=node1
# PUBLIC_NODE_URL=http://publicnode:3001 # 동일 머신
# 또는
# PUBLIC_NODE_URL=http://192.168.1.100:3001 # 별도 머신
docker-compose -f docker-compose-edge.yml up -d
# 로그 확인
docker-compose -f docker-compose-edge.yml logs -f
# 서비스 중지
docker-compose -f docker-compose-edge.yml down개발 환경:
# EdgeNode 개발 환경으로 실행
# 동일 머신에서 Docker로 실행 시: 서비스 이름 사용
PUBLIC_NODE_URL=http://publicnode:3001 EDGE_NODE_ID=node1 \
docker-compose -f docker-compose-edge.dev.yml up
# 백그라운드 실행
PUBLIC_NODE_URL=http://publicnode:3001 EDGE_NODE_ID=node1 \
docker-compose -f docker-compose-edge.dev.yml up -d
# 별도 머신에서 실행 시: 실제 IP 주소 사용
# PUBLIC_NODE_URL=http://192.168.1.100:3001 EDGE_NODE_ID=node1 \
# docker-compose -f docker-compose-edge.dev.yml up -d여러 EdgeNode 실행 예시:
# node1 실행 (동일 머신)
PUBLIC_NODE_URL=http://publicnode:3001 EDGE_NODE_ID=node1 \
docker-compose -f docker-compose-edge.yml up -d
# node2 실행 (별도 컨테이너, 동일 머신)
docker-compose -f docker-compose-edge.yml run -d \
-e EDGE_NODE_ID=node2 \
-e PUBLIC_NODE_URL=http://publicnode:3001 \
edgenode
# 별도 머신에서 실행 시
# PUBLIC_NODE_URL=http://192.168.1.100:3001 EDGE_NODE_ID=node1 \
# docker-compose -f docker-compose-edge.yml up -dEDGE_NODE_ID: EdgeNode 식별자 (기본값: 'node1', Docker에서는 환경변수로 설정)PUBLIC_NODE_URL: PublicNode 서버 URL (기본값: 'http://localhost:3001', Docker에서는 환경변수로 설정)- 동일 머신에서 Docker로 실행 시:
http://publicnode:3001또는http://host.docker.internal:3001 - 별도 머신에서 실행 시:
http://실제IP주소:3001또는http://호스트명:3001 - 예:
http://192.168.1.100:3001또는http://publicnode.example.com:3001
- 동일 머신에서 Docker로 실행 시:
PORT: 서버 포트 (기본값: 3001)NODE_ENV: 실행 환경 (production/development)
PORT: 서버 포트 (기본값: 3002)NODE_ENV: 실행 환경 (production/development)
EdgeCtrl은 PublicNode/PublicNest와 EdgeNode가 별도로 배포되는 구조입니다. 배포 환경에 따라 네트워크 설정이 달라집니다.
PublicNode와 EdgeNode가 같은 머신에서 Docker로 실행되는 경우입니다.
-
공유 네트워크 생성:
# 네트워크가 없으면 생성 (한 번만 실행) docker network create edgectrl_network -
PublicNode 실행 (먼저 실행):
docker-compose -f docker-compose-public.dev.yml up -d # 또는 운영 환경 docker-compose -f docker-compose-public.yml up -d -
EdgeNode 실행:
# PUBLIC_NODE_URL을 서비스 이름으로 설정 (같은 네트워크 내에서 접근) PUBLIC_NODE_URL=http://publicnode:3001 EDGE_NODE_ID=node1 \ docker-compose -f docker-compose-edge.dev.yml up -d
- 네트워크 이름:
edgectrl_network(모든 서비스가 공유) - EdgeNode의 PUBLIC_NODE_URL:
http://publicnode:3001(서비스 이름 사용, 권장)- 또는
http://host.docker.internal:3001(호스트 머신 접근)
- 장점:
- 같은 네트워크 내에서 서비스 이름으로 자동 DNS 해석
- 네트워크 격리로 보안 향상
- 포트 충돌 없음
모든 docker-compose 파일에서 네트워크를 external: true로 설정하여 공유 네트워크를 사용합니다:
networks:
edgectrl_network:
name: edgectrl_network
external: truePublicNode와 EdgeNode가 서로 다른 머신에서 실행되는 경우입니다.
PublicNode 머신:
# PublicNode 실행 (포트 3001 노출)
docker-compose -f docker-compose-public.yml up -d
# PublicNode의 실제 IP 주소 확인
# 예: 192.168.1.100EdgeNode 머신:
# EdgeNode 실행 (PublicNode의 실제 IP 주소 사용)
PUBLIC_NODE_URL=http://192.168.1.100:3001 EDGE_NODE_ID=node1 \
docker-compose -f docker-compose-edge.yml up -d
# 또는 호스트명 사용 (DNS 설정 필요)
PUBLIC_NODE_URL=http://publicnode.example.com:3001 EDGE_NODE_ID=node1 \
docker-compose -f docker-compose-edge.yml up -dPublicNode 머신 (호스트에서 직접 실행):
cd PublicNode
npm install
npm start # 포트 3001에서 실행EdgeNode 머신 (Docker):
# PublicNode 머신의 IP 주소 사용
PUBLIC_NODE_URL=http://192.168.1.100:3001 EDGE_NODE_ID=node1 \
docker-compose -f docker-compose-edge.yml up -dPublicNode 머신:
# 네트워크 생성 (선택사항, PublicNode만 사용)
docker network create edgectrl_network
# PublicNode 실행
docker-compose -f docker-compose-public.yml up -d
# PublicNode의 실제 IP 주소 확인
hostname -I # 또는 ifconfigEdgeNode 머신:
# EdgeNode는 네트워크 설정 불필요 (외부 접근)
PUBLIC_NODE_URL=http://192.168.1.100:3001 EDGE_NODE_ID=node1 \
docker-compose -f docker-compose-edge.yml up -d- 네트워크: EdgeNode는 별도 네트워크 불필요 (외부 접근)
- EdgeNode의 PUBLIC_NODE_URL:
http://실제IP주소:3001(예:http://192.168.1.100:3001)- 또는
http://호스트명:3001(DNS 설정 필요)
- 포트 포워딩: PublicNode의 포트 3001이 외부에서 접근 가능해야 함
- 방화벽: PublicNode 머신의 방화벽에서 포트 3001 허용 필요
-
네트워크 존재 확인:
docker network ls | grep edgectrl_network -
네트워크 생성:
docker network create edgectrl_network
-
컨테이너가 네트워크에 연결되어 있는지 확인:
docker network inspect edgectrl_network
-
PUBLIC_NODE_URL 확인:
http://publicnode:3001(서비스 이름 사용)- 또는
http://host.docker.internal:3001(호스트 접근)
-
네트워크 연결 확인:
# EdgeNode 머신에서 PublicNode 접근 테스트 curl http://192.168.1.100:3001/status/ -
포트 포워딩 확인:
# PublicNode 머신에서 포트 리스닝 확인 netstat -tuln | grep 3001 # 또는 lsof -i :3001
-
방화벽 설정 확인:
# PublicNode 머신에서 방화벽 규칙 확인 # macOS sudo pfctl -s rules # Linux sudo iptables -L -n sudo ufw status
-
Docker 포트 바인딩 확인:
# PublicNode 컨테이너의 포트 매핑 확인 docker ps | grep publicnode # 0.0.0.0:3001->3001/tcp 형태로 표시되어야 함
| 시나리오 | 네트워크 설정 | PUBLIC_NODE_URL 예시 | 주의사항 |
|---|---|---|---|
| 동일 머신 (Docker) | 공유 네트워크 사용 | http://publicnode:3001 |
네트워크 사전 생성 필요 |
| 동일 머신 (호스트+Docker) | 네트워크 불필요 | http://host.docker.internal:3001 |
호스트에서 PublicNode 실행 |
| 별도 머신 (Docker) | 네트워크 불필요 | http://192.168.1.100:3001 |
포트 포워딩 및 방화벽 설정 필요 |
| 별도 머신 (호스트+Docker) | 네트워크 불필요 | http://192.168.1.100:3001 |
포트 포워딩 및 방화벽 설정 필요 |
PublicNode(포트 3001)와 PublicNest(포트 3002)는 동일한 API 인터페이스를 제공합니다. 아래 예시는 PublicNode를 기준으로 작성되었으며, PublicNest를 사용할 경우 포트만 3002로 변경하면 됩니다.
엔드포인트: POST /api
요청 본문:
{
"edgeNodeID": "node1",
"method": "hello",
"uri": "hello",
"data": {
"message": "Hello World"
}
}응답:
{
"status": "success",
"edgeNodeID": "node1",
"command": "hello",
"result": {
"message": "Hello World",
"status": "success",
"edgeNodeID": "node1"
},
"timestamp": "2024-01-01T00:00:00.000Z"
}엔드포인트: POST /api/all
요청 본문:
{
"method": "hello",
"uri": "hello",
"data": {
"message": "Hello All"
}
}응답:
{
"success": [
{
"edgeNodeID": "node1",
"result": { ... },
"timestamp": "..."
},
{
"edgeNodeID": "node2",
"result": { ... },
"timestamp": "..."
}
],
"failed": [],
"total": 2,
"successCount": 2,
"failedCount": 0
}엔드포인트: GET /status/
응답:
{
"publicNode": {
"status": "running",
"uptime": 3600,
"timestamp": "2024-01-01T00:00:00.000Z"
},
"edgeNodes": {
"total": 2,
"connected": 2,
"disconnected": 0,
"list": [
{
"edgeNodeID": "node1",
"socketId": "abc123",
"connected": true,
"connectedAt": 1234567890
},
{
"edgeNodeID": "node2",
"socketId": "def456",
"connected": true,
"connectedAt": 1234567891
}
]
},
"history": {
"total": 10,
"recent": [ ... ]
}
}Hello 메시지를 표시합니다.
요청:
{
"edgeNodeID": "node1",
"method": "hello",
"data": {
"message": "Hello from User!"
}
}동작:
- macOS:
osascript를 사용하여 다이얼로그 표시 - Windows:
msg명령어로 메시지 표시 - Linux: 콘솔에 메시지 출력
사용 사례:
-
원격 알림 전송
- 여러 EdgeNode에 동시에 알림 메시지 전송
- 예: "시스템 점검이 시작됩니다", "업데이트가 완료되었습니다"
-
상태 확인
- EdgeNode가 정상적으로 동작하는지 확인
- 연결 테스트 및 응답 확인
-
사용자 알림
- 중요한 작업 완료 알림
- 예: "백업이 완료되었습니다", "다운로드가 완료되었습니다"
-
모니터링 및 로깅
- 특정 이벤트 발생 시 알림
- 예: "로그 파일이 임계값을 초과했습니다"
실제 사용 예시:
# 모든 EdgeNode에 알림 전송
curl -X POST http://localhost:3001/api/all \
-H "Content-Type: application/json" \
-d '{
"method": "hello",
"data": {
"message": "시스템 점검이 10분 후 시작됩니다."
}
}'
# 특정 EdgeNode에 개인화된 메시지 전송
curl -X POST http://localhost:3001/api \
-H "Content-Type: application/json" \
-d '{
"edgeNodeID": "node1",
"method": "hello",
"data": {
"message": "node1: 작업이 완료되었습니다."
}
}'기본 브라우저를 실행하고 google.com으로 이동합니다.
요청:
{
"edgeNodeID": "node1",
"method": "google",
"data": {}
}동작:
- macOS:
open https://www.google.com - Windows:
start https://www.google.com - Linux:
xdg-open https://www.google.com
사용 사례:
-
원격 브라우저 제어
- 원격으로 특정 웹사이트 열기
- 예: 대시보드, 모니터링 페이지, 문서 페이지 열기
-
자동화된 웹 접근
- 스크립트나 스케줄러를 통한 자동 웹사이트 접근
- 예: 매일 특정 시간에 리포트 페이지 열기
-
사용자 지원
- 원격 지원 시 필요한 웹사이트를 사용자 화면에 표시
- 예: 도움말 페이지, 설정 페이지 열기
-
정보 공유
- 여러 EdgeNode에 동시에 동일한 웹사이트 열기
- 예: 회의 링크, 공지사항 페이지
-
모니터링 및 대시보드
- 원격 모니터링 대시보드 열기
- 예: 서버 상태, 로그 뷰어, 메트릭 대시보드
실제 사용 예시:
# 특정 EdgeNode에서 Google 열기
curl -X POST http://localhost:3001/api \
-H "Content-Type: application/json" \
-d '{
"edgeNodeID": "node1",
"method": "google",
"data": {}
}'
# 모든 EdgeNode에서 동시에 Google 열기 (회의 링크 공유 등)
curl -X POST http://localhost:3001/api/all \
-H "Content-Type: application/json" \
-d '{
"method": "google",
"data": {}
}'
# 스케줄러와 함께 사용 (cron 등)
# 매일 오전 9시에 모든 EdgeNode에서 대시보드 열기
# 0 9 * * * curl -X POST http://localhost:3001/api/all -H "Content-Type: application/json" -d '{"method":"google","data":{}}'확장 가능성:
- 현재는
google.com만 지원하지만, 향후 다른 URL도 지원하도록 확장 가능 - 예:
{"method": "openurl", "data": {"url": "https://example.com"}}
PublicNode 사용 (포트 3001):
curl -X POST http://localhost:3001/api \
-H "Content-Type: application/json" \
-d '{
"edgeNodeID": "node1",
"method": "hello",
"data": {
"message": "Hello from Curl!"
}
}'PublicNest 사용 (포트 3002):
curl -X POST http://localhost:3002/api \
-H "Content-Type: application/json" \
-d '{
"edgeNodeID": "node1",
"method": "hello",
"data": {
"message": "Hello from Curl!"
}
}'PublicNode 사용:
curl -X POST http://localhost:3001/api \
-H "Content-Type: application/json" \
-d '{
"edgeNodeID": "node1",
"method": "google",
"data": {}
}'PublicNest 사용:
curl -X POST http://localhost:3002/api \
-H "Content-Type: application/json" \
-d '{
"edgeNodeID": "node1",
"method": "google",
"data": {}
}'PublicNode 사용:
curl -X POST http://localhost:3001/api/all \
-H "Content-Type: application/json" \
-d '{
"method": "hello",
"data": {
"message": "Hello All Nodes!"
}
}'PublicNest 사용:
curl -X POST http://localhost:3002/api/all \
-H "Content-Type: application/json" \
-d '{
"method": "hello",
"data": {
"message": "Hello All Nodes!"
}
}'PublicNode 사용:
curl http://localhost:3001/status/PublicNest 사용:
curl http://localhost:3002/status/PublicNode 사용:
curl -X POST http://localhost:3001/api \
-H "Content-Type: application/json" \
-d '{
"edgeNodeID": "node1",
"method": "hello",
"data": {
"message": "Hello World"
}
}' | jqPublicNest 사용:
curl -X POST http://localhost:3002/api \
-H "Content-Type: application/json" \
-d '{
"edgeNodeID": "node1",
"method": "hello",
"data": {
"message": "Hello World"
}
}' | jqEdgeNode는 PublicNode와의 연결이 끊어지면 다음 순서로 재연결을 시도합니다:
- 1초 주기로 5번 시도
- 3초 주기로 5번 시도
- 10초 주기로 5번 시도
- 30초 주기로 5번 시도 (이후 계속 유지)
각 단계에서 최대 시도 횟수에 도달하면 다음 단계로 진행하며, 마지막 단계(30초)에서는 계속 재연결을 시도합니다.
-
PublicNode 또는 PublicNest가 실행 중인지 확인:
# PublicNode 확인 curl http://localhost:3001/status/ # PublicNest 확인 curl http://localhost:3002/status/
-
EdgeNode 로그 확인:
docker-compose -f docker-compose-edge.yml logs edgenode
-
네트워크 연결 확인:
PUBLIC_NODE_URL환경 변수가 올바른지 확인 (포트 포함)- 동일 머신 (Docker):
http://publicnode:3001또는http://host.docker.internal:3001 - 별도 머신:
http://실제IP주소:3001(예:http://192.168.1.100:3001) - PublicNest 사용 시: 포트를 3002로 변경
- 방화벽 설정 확인 (별도 머신인 경우)
- 자세한 내용은 네트워크 설정 가이드 참조
-
EdgeNode가 등록되었는지 확인:
# PublicNode 사용 시 curl http://localhost:3001/status/ # PublicNest 사용 시 curl http://localhost:3002/status/
-
EdgeNodeID가 올바른지 확인:
- 요청의
edgeNodeID와 실제 EdgeNode의EDGE_NODE_ID가 일치해야 합니다.
- 요청의
-
명령어 이름 확인:
- 지원하는 명령어:
hello,google
- 지원하는 명령어:
-
서버 포트 확인:
- PublicNode는 포트 3001, PublicNest는 포트 3002를 사용합니다.
- EdgeNode의
PUBLIC_NODE_URL이 올바른 포트를 가리키는지 확인하세요.