systemd로 Node.js 애플리케이션을 서비스화하기

systemd로 Node.js 애플리케이션을 서비스화하기
Photo by Wixun Yun / Unsplash

systemd로 Node.js 애플리케이션을 서비스화하기

서버에서 Node.js 애플리케이션을 운영할 때, 단순히 node app.js로 실행하면 터미널이 종료되거나 애플리케이션이 크래시될 때 서비스가 중단됩니다. 이런 문제를 해결하기 위해 systemd를 활용해 Node.js 애플리케이션을 시스템 서비스로 관리하는 방법을 알아보겠습니다.

systemd란?

systemd는 Linux 시스템의 init 시스템으로, 시스템 부팅 과정과 서비스 관리를 담당합니다. Ubuntu 16.04부터 기본 init 시스템으로 채택되었으며, 강력한 서비스 관리 기능을 제공합니다.

기존 실행 방법들과의 비교

1. 직접 실행 (node app.js)

node app.js
# 또는
yarn start

단점:

  • 터미널 종료 시 프로세스 종료
  • 크래시 시 자동 재시작 불가
  • 시스템 부팅 시 자동 시작 불가
  • 로그 관리 어려움

2. nohup 사용

nohup yarn start > app.log 2>&1 &

장점:

  • 터미널 종료되어도 실행 지속
  • 간단한 로그 관리

단점:

  • 크래시 시 자동 재시작 불가
  • 프로세스 관리 번거로움
  • 시스템 부팅 시 자동 시작 불가

3. PM2 사용

pm2 start yarn --name "app" -- start

장점:

  • 자동 재시작
  • 로드 밸런싱
  • 실시간 모니터링
  • 클러스터 모드

단점:

  • 추가 패키지 설치 필요
  • PM2 자체 관리 필요
  • 메모리 오버헤드

4. systemd 사용 ⭐

sudo systemctl start my-app

장점:

  • 시스템 레벨 관리
  • 부팅 시 자동 시작
  • 강력한 재시작 정책
  • 표준화된 로그 관리
  • 리소스 제한 가능
  • 의존성 관리

systemd 서비스 설정하기

1. 서비스 파일 생성

/etc/systemd/system/my-app.service 파일을 생성합니다:

[Unit]
Description=My Node.js Application
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/my-app
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=/usr/bin/yarn start
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=my-app

[Install]
WantedBy=multi-user.target

2. 주요 설정 옵션 설명

[Unit] 섹션

  • Description: 서비스 설명
  • After: 네트워크가 활성화된 후 시작

[Service] 섹션

  • Type=simple: 단순한 포그라운드 프로세스
  • User: 실행할 사용자
  • WorkingDirectory: 작업 디렉토리
  • Environment: 환경 변수 설정
  • ExecStart: 실행할 명령어
  • Restart=always: 항상 재시작
  • RestartSec=10: 재시작 대기 시간 (초)

[Install] 섹션

  • WantedBy=multi-user.target: 멀티유저 모드에서 자동 시작

3. 서비스 등록 및 실행

# 서비스 파일 다시 로드
sudo systemctl daemon-reload

# 서비스 활성화 (부팅 시 자동 시작)
sudo systemctl enable my-app

# 서비스 시작
sudo systemctl start my-app

# 서비스 상태 확인
sudo systemctl status my-app

고급 설정 옵션

재시작 정책

[Service]
Restart=on-failure          # 실패 시에만 재시작
RestartSec=5                # 5초 후 재시작
StartLimitInterval=60       # 60초 간격 내에서
StartLimitBurst=3           # 최대 3번까지 재시작 시도

리소스 제한

[Service]
MemoryLimit=512M            # 메모리 제한
CPUQuota=50%               # CPU 사용률 제한
TasksMax=20                # 최대 프로세스/스레드 수

보안 설정

[Service]
NoNewPrivileges=true        # 새로운 권한 획득 방지
ProtectSystem=strict        # 시스템 디렉토리 쓰기 방지
ProtectHome=true           # 홈 디렉토리 접근 제한

서비스 관리 명령어

기본 명령어

# 서비스 시작/중지/재시작
sudo systemctl start my-app
sudo systemctl stop my-app
sudo systemctl restart my-app

# 서비스 상태 확인
sudo systemctl status my-app

# 서비스 활성화/비활성화 (부팅 시 자동 시작)
sudo systemctl enable my-app
sudo systemctl disable my-app

로그 관리

# 실시간 로그 보기
sudo journalctl -u my-app -f

# 최근 로그 확인
sudo journalctl -u my-app -n 50

# 특정 시간 범위 로그
sudo journalctl -u my-app --since "2024-01-01" --until "2024-01-02"

자동화 스크립트 예제

실제 운영 환경에서 사용할 수 있는 배포 스크립트:

setup-service.sh

#!/bin/bash

SERVICE_NAME="my-app"
WORK_DIR="/home/ubuntu/my-app"
USER="ubuntu"

# 서비스 파일 생성
sudo tee /etc/systemd/system/$SERVICE_NAME.service > /dev/null << EOL
[Unit]
Description=My Node.js Application
After=network.target

[Service]
Type=simple
User=$USER
WorkingDirectory=$WORK_DIR
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=$WORK_DIR/start.sh
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=$SERVICE_NAME

[Install]
WantedBy=multi-user.target
EOL

# 실행 스크립트 생성
tee $WORK_DIR/start.sh > /dev/null << EOL
#!/bin/bash
cd $WORK_DIR
yarn start
EOL

chmod +x $WORK_DIR/start.sh

# systemd 등록
sudo systemctl daemon-reload
sudo systemctl enable $SERVICE_NAME

echo "✅ Service setup complete!"

deploy.sh

#!/bin/bash

SERVICE_NAME="my-app"

echo "🔄 Stopping service..."
sudo systemctl stop $SERVICE_NAME

echo "📦 Pulling latest code..."
git pull origin main

echo "🔨 Building application..."
yarn build

echo "🚀 Starting service..."
sudo systemctl start $SERVICE_NAME

echo "✅ Deployment complete!"
sudo systemctl status $SERVICE_NAME --no-pager

systemd의 장단점

장점 ✅

  1. 시스템 통합: Linux 시스템과 완벽하게 통합
  2. 자동 재시작: 크래시 시 자동으로 재시작
  3. 부팅 시 자동 시작: 서버 재부팅 후 자동으로 서비스 시작
  4. 강력한 로그 관리: journald를 통한 체계적인 로그 관리
  5. 리소스 제어: CPU, 메모리 등 리소스 사용량 제한 가능
  6. 의존성 관리: 다른 서비스와의 시작 순서 제어
  7. 보안: 다양한 보안 옵션 제공
  8. 표준화: 대부분의 Linux 배포판에서 표준

단점 ❌

  1. Linux 전용: Windows나 macOS에서 사용 불가
  2. 학습 곡선: 초기 설정과 개념 이해 필요
  3. 복잡성: 간단한 애플리케이션에는 과도할 수 있음
  4. 디버깅: 문제 발생 시 systemd 지식 필요

모니터링과 알림

서비스 상태 모니터링

# 서비스가 실행 중인지 확인
systemctl is-active my-app

# 서비스가 활성화되어 있는지 확인
systemctl is-enabled my-app

알림 설정 (OnFailure)

[Unit]
OnFailure=failure-notification@%n.service

결론

systemd는 Node.js 애플리케이션을 프로덕션 환경에서 안정적으로 운영하기 위한 강력한 도구입니다. 초기 설정은 다소 복잡할 수 있지만, 한 번 설정하면 다음과 같은 이점을 얻을 수 있습니다:

  • 높은 안정성: 자동 재시작과 에러 복구
  • 운영 편의성: 표준화된 관리 명령어
  • 확장성: 여러 서비스 동시 관리 가능
  • 보안성: 시스템 레벨 보안 기능

특히 서버 운영 경험이 있거나 안정적인 서비스 운영이 중요한 경우라면 systemd 도입을 강력히 추천합니다.


이 글이 도움이 되셨다면 실제 프로젝트에 적용해보시고, 궁금한 점이 있으시면 언제든 문의해주세요! 🚀

Subscribe to Keun's Story newsletter and stay updated.

Don't miss anything. Get all the latest posts delivered straight to your inbox. It's free!
Great! Check your inbox and click the link to confirm your subscription.
Error! Please enter a valid email address!