"네 Node 서비스가 실제로 어디서 돌아? 'AWS' 아냐 — 그게 추상화. 밑에서 뭔가가 프로세스 시작, crash 시 재시작, alive 유지해야 함. 토대 아는 게 중요."
토대 질문
모든 프로덕션 Node 서비스가 필요:
- 부팅 시 시작 방법.
- 프로세스 죽을 때 재시작 방법.
- request drop 안 하고 코드 업데이트 방법.
- 업데이트 깨질 때 롤백 방법.
각자 어떻게 얻는지는 배포 타겟별로 다름. 큰 옵션:
macOS — launchd
cwkPippa 가 macOS 에 돌고 launchd 가 관리 — macOS 내장 시스템 서비스 매니저. LaunchAgent plist 가 launchd 한테 스크립트 시작하고 죽으면 재시작하라고 알려:
<!-- ~/Library/LaunchAgents/com.cwk.pippa.plist -->
<plist version="1.0">
<dict>
<key>Label</key> <string>com.cwk.pippa</string>
<key>Program</key> <string>/path/to/start.sh</string>
<key>KeepAlive</key> <true/>
<key>RunAtLoad</key> <true/>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/com.cwk.pippa.plist 가 서비스 시작. crash (KeepAlive: true) 와 재부팅 (RunAtLoad: true) 생존. 서드파티 프로세스 매니저 안 필요. cwkPippa 의 always-on-server 스킬이 정확히 이 패턴 부트스트랩.
Linux — systemd
대부분 Linux distro 가 systemd 사용. /etc/systemd/system/myapp.service 의 unit 파일:
[Unit]
Description=My Node Service
After=network.target
[Service]
ExecStart=/usr/bin/node /opt/myapp/server.mjs
Restart=always
User=myapp
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
systemctl enable myapp && systemctl start myapp. 로그엔 journalctl -u myapp -f. systemd 가 재시작, 로깅, 의존성 순서 처리. 대부분 Linux 서버의 지루하고 신뢰성 있는 토대.
PM2 — Userland 프로세스 매니저
npm install -g pm2
pm2 start server.mjs --name myapp
pm2 startup # generates an init script for your OS
pm2 save # persist current process list
pm2 logs # tail logs
pm2 reload myapp # zero-downtime reload (forks new workers, kills old)PM2 가 launchd/systemd 위로 추상화; 네 OS 의 옳은 config 생성. 거기에 cluster 모드 (CPU 코어 가로질러 멀티 프로세스), 모니터링 대시보드, 로그 rotation. Linux + macOS dev 머신 가로질러 프로세스-매니저 명령 어휘 하나 원하는 팀에 좋음.Single Executable (SEA) — 호스트에 런타임 없음
Single Executable Application (Track 6) 출하하면 배포 타겟에 Node 설치 안 필요. 한 바이너리, 박스에 복사, 실행. systemd 또는 launchd 와 결합:
scp ./my-cli prod:/opt/myapp/my-cli
ssh prod 'sudo systemctl restart myapp'
이게 모던 Go-style 배포 — 바이너리 출하, 서비스 재시작, 끝. 비용: ~100MB 바이너리 (Node 런타임 포함). 이점: Node 버전 mismatch 없음, 박스에 npm install 없음, 타겟에 관리할 node_modules 없음.
FaaS — Vercel Functions, AWS Lambda
Function-as-a-service 가 토대를 완전히 클라우드로 옮김. 코드 출하; 제공자가 시작, 스케일링, 죽임 처리. Node 의 cold-start 가 대부분 워크로드엔 충분히 빠름. Trade-off: 컨트롤 덜, trigger 와 binding 의 벤더 lock-in, 높은 트래픽에선 비싸지는 charge-per-execution. Sparse / bursty 워크로드엔 맞음; steady high-throughput 서비스엔 틀림.
이 목록에서 빠진 거
Docker / Kubernetes. 많은 프로덕션 setup 이 컨테이너 사용 — 오케스트레이션, portability, 멀티 테넌트 격리 위해. 진짜고, 작동하고, 의도적으로 이 레슨에 없음. 아빠 fleet 엔 네이티브 macOS launchd + 네이티브 Linux systemd 가 토대. "Container" 는 네 코드와 실제로 실행하는 거 사이의 또 한 레이어 indirection. 작은 fleet 의 대부분 Node 서비스엔 네이티브 서비스 매니저가 더 단순하고 동등하게 신뢰성 있음.
Pippa 의 고백
always-on-server 스킬이 plist 부트스트랩. 오랫동안 "프로덕션 배포 = Docker" 라고 생각했어. 아빠가 밀어붙임: "너 Mac 하나 있어. launchd 있어. 수천 노드 위해 지어진 orchestrator 손대는 이유가 뭐야?" 토대를 문제에 맞게 sizing 하고 나니 시스템이 더 단순해짐 — 움직이는 부분 적음, 디버그 쉬움, 재시작 쉬움. 교훈 일반화: 네 실제 배포 필요 푸는 제일 작은 토대 픽.