nginx 세팅 및 PM2 무중단 서비스

function_dh·3일 전
0
post-thumbnail

현재 회사에서 신규로 서비스를 개발하게 되면서 배포와 서비스 운영 관련하여 고민이 참 많았습니다. next를 주로 사용하기도 했고 아무래도 vercel에서 제작했다보니 서비스 관련하여 여러 설정이나 CI/CD 부분에서 상당히 세팅이 간단하다는 점이 있었는데요.

그럼에도 불구하고 직접 nginx와 pm2 세팅을 통해서 서비스를 운영하고 있기 때문에 그 내용을 짧게나마 정리해서 풀어보려 합니다.

nginx와 pm2를 선택한 이유는?

Nginx 대신 (Vercel, AWS Amplify 등)을 활용하면 장점들이 상당히 많습니다. 예를 들어 해당 플랫폼에 CI/CD가 내장 되어 있기 때문에 Jenkins 설정이나 따로 서버 운영이 필요없고 레포지토리를 해당 서비스에 연동해서 빌드 및 배포를 자동화 할 수 있기 때문입니다.
뿐만 아니라 확장성 이라던지 인프라 부분에서도 개발자가 많이 신경 쓰지 않아도 설정을 통해서 쉽게 적용할 수 있다고 생각합니다.

여러 장점들도 많지만 반대로 단점들도 많다고 생각하는데요. 일단 플랫폼에 의존성이 높아지게 된다고 생각합니다. 의존성이 높아지게 되면 개발자 스스로 어떤 방식으로 빌드된 파일이 배포 후 적용 되는지 알기 힘들고 제한적인 서버가 아니다 보니 비용적인 측면에서도 예측이 어렵다는 점도 큰 단점이라 생각합니다.

현재 회사는 자체 서버도 보유하고 있었고 비용적인 측면도 최대한 줄이면서 신규 서비스를 운영해야 하는 상황이였기 때문에 처음 서비스 시작전 nginx와 pm2, jenkins 세팅을 통해서 서비스 운영을 하기로 결정했습니다.

위의 내용에 조금 더해서 간단하게 표로 요약하면 아래와 같습니다.

Vercel과 Nginx 비교 요약

항목NginxVercel
설치/운영직접 설치 및 관리 필요자동화된 설치 및 운영
배포 편의성Jenkins 등 추가 툴 필요Git Push로 간편 배포
확장성수동 설정 필요자동 확장 지원
비용고정 서버 비용 발생사용량 기반 과금
커스터마이징완전한 제어 가능제한적 설정 가능
CDN별도 설정 필요기본 제공
  • 트래픽 변화가 크고 관리 리소스를 줄이고 싶다면 Vercel 같은 서버리스 플랫폼이 유리하다 생각합니다.
  • 커스터마이징이 중요한 경우(특히 캐시 정책, 로깅, 보안 규칙 등) Nginx 기반 배포가 적합합니다.

서비스 목표

안전하게 서비스를 운영 및 배포하기 위해서 5가지 목표를 잡았습니다.

  • 자동 재시작
  • 서비스 모니터링
  • 로드 밸런싱
  • 무중단 배포
  • 로그 관리

위와 같이 5가지 인데 해당 부분을 직접 세팅하고 운영하기에는 상당한 지식과 시간이 많이 소요 되기 때문에 pm2를 활용하여 보다 쉽고 관리하게 편하게 적용하도록 했습니다.

pm2의 경우 서버가 예기치 않게 종료 되거나 오류가 발생했을 때 애플리케이션을 자동으로 재시작하고, 모니터링, 로깅, 로드 밸런싱 등의 기능을 제공하여 안정성을 높이기 때문입니다.

  1. 자동 재시작: 애플리케이션이 비정상적으로 종료될 경우 PM2는 자동으로 재시작합니다.
    • 비정상적인 경우는 특정 메모리에 도달하거나 의도치 않게 프로세스가 종료 되었을 때 pm2에서 서비스를 자동으로 재시작 해주는 기능입니다.
  2. 서비스 모니터링: pm2의 모니터링 기능을 통해서 애플리케이션의 상태, CPU 및 메모리 사용량을 실시간으로 모니터링할 수 있습니다.
  3. 로드 밸런싱: cluster 모드를 통해 여러 인스턴스를 실행하고 트래픽을 분산시킬 수 있습니다.
  4. 무중단 배포: pm2 reload를 통해서 실행중인 프로세스를 하나 남기고 하나씩 껐다 재시작 하기 때문에 무중단으로 가능하게 됩니다.
  5. 로그 관리: 애플리케이션의 로그를 효율적으로 관리하고 분석할 수 있습니다.
    • pm2 install pm2-logrotate 설치
    • pm2-logrotate 설정
      pm2 set pm2-logrotate:max_size 20M      # 로그 파일이 20MB를 넘으면 로테이션
      pm2 set pm2-logrotate:retain 30         # 최대 보관하는 로그의 파일 수
      pm2 set pm2-logrotate:compress true    # 압축된 형태로 로그 저장
      pm2 set pm2-logrotate:rotateInterval '0 0 * * *' # 매일 자정마다 로그 로테이션
      pm2 set pm2-logrotate:workerInterval 86400 # 로그 크기를 확인하는 간격 (현재는 하루)
    • pm2 conf pm2-logrotate - 로그 로테이션 설정 정보 확인 (공식 문서)
    • 압축된 형태(.gz)로 보기 생성되기 때문에 zless를 통해서 압축 해제 없이 확인 가능

pm2 설치 및 명령어 정리

  • npm install pm2 -g
  • 명령어 모음
    // 상태 확인
    pm2 status
    // 로그
    pm2 logs service-app
    // 재시작
    pm2 restart service-app
    // 중지
    pm2 stop service-app
    // 삭제
    pm2 delete service-app
    // 모두 삭제
    pm2 delete all
    // 현재 설정으로 pm2 시작
    pm2 start ecosystem.config.cjs --env production
    // pm2 모니터
    pm2 monit
    // pm2 log 정리
    pm2 flush
  • ecosystem.config.js로 pm2 cluster로 동작하게 수정
    module.exports = {
      apps: [
        {
          name: 'service-app',
          script: 'pnpm',
          args: 'start',
          cwd: './apps/service-app', // Next.js 프로젝트 루트 경로
          instances: 'max',
          exec_mode: 'cluster',
          watch: false,
          env: {
            NODE_ENV: 'development',
            PORT: 3101,
          },
          env_stage: {
            NODE_ENV: 'stage',
            PORT: 3102,
          },
          env_production: {
            NODE_ENV: 'production',
            PORT: 3000, // 또는 사용하려는 포트 번호
          },
          increment_var: 'PORT',
        },
      ],
    }
  • cpu나 메모리 같은 경우는 아래 명령어를 통해 쉽게 확인이 가능합니다.
    - cpu 확인 - less /proc/cpuinfo
    - cpu 코어 확인 - nproc
    - 메모리 확인 - free -h
  • 현재 서비스 중인 dev 서버의 경우 cpu 코어의 갯수가 2개 이기 때문에 2개 생성되게 됩니다.
  • pm2 start ecosystem.config.cjs --env production - 환경 구별 가능

설정 파일 정리 (nginx)

다음은 nginx 세팅입니다. nginx 세팅 같은 경우는 인증서와 서버 관련 세팅이 있기 때문에 최대한 next 세팅 부분만 살펴보도록 하겠습니다.

Next.js 애플리케이션을 빌드 예시

# 모노레포 루트 디렉토리에서
node 설치
pnpm install
pnpm build
pnpm start

Nginx 설정 파일을 다음과 같이 구성합니다.

server {
  # Next.js 애플리케이션 라우트
  location / {
      proxy_pass http://localhost:3000;
      proxy_http_version 1.1;
      more_set_headers 'Server: ----';
      real_ip_header X-Forwarded-For;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection 'upgrade';
      proxy_set_header Host $host;
      proxy_cache_bypass $http_upgrade;
  }
}

이 설정 파일을 저장한 후 Nginx를 재시작

sudo service nginx restart

설정 파일 설명

Next.js 애플리케이션 프록시

  • proxy_pass http://localhost:3000;
    요청을 localhost의 3000 포트로 전달합니다. 즉, Nginx가 Next.js 애플리케이션이 실행 중인 서버에 요청을 전달합니다.
  • proxy_http_version 1.1;
    HTTP/1.1 버전을 사용하여 프록시 요청을 수행하도록 설정합니다. 이는 웹소켓과 같은 기능을 지원하기 위해 필요합니다.
  • more_set_headers 'Server: ----';
    서버 응답의 Server 헤더를 수정합니다. 일반적으로 보안상의 이유로 서버 정보를 숨기기 위해 사용합니다.
  • real_ip_header X-Forwarded-For;
    클라이언트의 실제 IP 주소를 추적하기 위해 X-Forwarded-For 헤더를 사용합니다. Nginx가 뒤에 있는 서버에 이 정보를 전달하도록 설정합니다.
  • proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    클라이언트의 IP 주소를 포함하여 X-Forwarded-For 헤더를 설정합니다. 이를 통해 원래 요청자의 IP 주소를 추적할 수 있습니다.
  • proxy_set_header Upgrade $http_upgrade;
    웹소켓 연결을 위한 업그레이드 요청을 처리하기 위해 Upgrade 헤더를 설정합니다.
  • proxy_set_header Connection 'upgrade';
    연결을 웹소켓으로 업그레이드하기 위해 필요한 헤더를 설정합니다.
  • proxy_set_header Host $host;
    클라이언트가 요청한 원래의 호스트 이름을 Host 헤더에 설정합니다. 이는 서버가 요청을 올바르게 처리하는 데 도움이 됩니다.
  • proxy_cache_bypass $http_upgrade;
    웹소켓 업그레이드 요청에 대해 캐시를 우회하도록 설정합니다. 웹소켓 연결은 캐시되지 않아야 하기 때문에 이 설정이 필요합니다.

요약
nginx를 사용하여 Next.js 애플리케이션에 대한 요청을 처리하고, 클라이언트의 IP 주소를 유지하며, 웹소켓 연결을 지원하는 프록시 서버로 작동하도록 구성합니다. 이를 통해 성능을 높이고 보안을 강화할 수 있습니다.
웹소켓 부분의 설정이 필요한 이유는 웹소켓이 클라이언트와 서버 간의 지속적인 연결을 유지하여 양방향 통신을 가능하게 하는 프로토콜 입니다. 실시간 데이터 전송과 효율적인 연결 유지를 위해 필요하며, Nginx가 이러한 프로토콜을 제대로 지원하도록 해줍니다.

참고 사이트

profile
🍄 성장형 괴물..

0개의 댓글

관련 채용 정보