nextjs 무중단 배포방법 파악2

study, share · 2021-9-29

← 리스트로

nextjs 무중단 배포방법 파악2

  • 목차
    1. 예상하지 못했던 문제점 및 해결방법
    • build시 .next가 업데이트 되면서 실시간으로 잘못 반영되는 문제
    • node process의 process.send 호출시 정의되지 않는 함수 에러 발생
    • ecosystem.config.js의 script에 npm script를 활용하면 정상 동작하지 않음
    • 프로젝트 nodejs 버전관리 문제
    1. 젠킨스 설치 및 세팅
    2. 젠킨스 설치 (mac)
    3. 젠켄스 플러그인 설치
    4. 젠킨스 서버와 서비스 서버 사이에 ssh 인증하기 (매번 암호 기입없이 ssh 접근)
    5. jenkins관리 > Global Tool Configuration 에서 nodeJS 버전 세팅
    6. 새로운 item 추가

1. 예상하지 못했던 문제점 및 해결방법

build시 .next가 업데이트 되면서 실시간으로 잘못 반영되는 문제

  • 문제점: pm2 reload를 하기도 전에 build시 생성되는 .next 파일이 업데이트 되는 순간 사용자는 깨진 화면을 보게됨
  • 해결 방법: 새로운 버전이 생길때마다 빌드되는 디렉토리를 새롭게 생성하고 reload시 새로운 디렉토리를 반영
  1. next.config.js 에 distdir을 배포 버전명으로 지정 (생성)
  • 빌드시 지정된 디렉토리에 결과물 생성
  • next.config.js
    
    const projectInfo = require('./package.json');
    const dev = process.env.NODE_ENV !== 'production';
    const distDir = dev ? '.next' : `build-${projectInfo.version}`;
    
    module.exports = {
      reactStrictMode: true,
      distDir
    }
    
  1. server.js 에 distdir을 배포 버전명으로 지정 (반영)
  • 빌드시 지정된 디렉토리에 결과물 생성
  • server.js
    const distDir = dev ? '.next' : `build-${projectInfo.version}`;
    const app = next({ 
      dev,
      conf: {
        distDir
      },
    });
    

node process의 process.send 호출시 정의되지 않는 함수 에러 발생

  • 문제점: pm2 의 graceful reload 가이드에 따라 process.send 함수 실행시 에러 발생
  • 해결방법: send 메서드는 부모 프로세스가 있을때만 존재함(pm2의 관리대상인 process 일때만). dev서버를 올리기 위해 단독으로 node server.js를 실행하면 에러가 발생하므로 아래처럼 예외처리 해줌.
// process.send is not a function
if (process.send) {
  process.send('ready');
}

ecosystem.config.js의 script에 npm script를 활용하면 정상 동작하지 않음

  • 문제점: cluster 옵션을 주었음에도 reload시 프로세스가 죽거나 뜰때 포트 충돌 에러발생
// ~/.pm2/pm2.log
Error: listen EADDRINUSE: address already in use :::3000
  at Server.setupListenHandle [as _listen2] (net.js:1318:16)
  at listenInCluster (net.js:1366:12)
  at Server.listen (net.js:1452:7)
  at Function.listen (/Users/a210331005/project/jmnet.cappuccino/node_modules/express/lib/application.js:618:24)
  at /Users/a210331005/project/jmnet.cappuccino/server.js:15:25
Emitted 'error' event on Server instance at:
  at emitErrorNT (net.js:1345:8)
  at processTicksAndRejections (internal/process/task_queues.js:80:21) {
    code: 'EADDRINUSE',
    errno: -48,
    syscall: 'listen',
    address: '::',
    port: 3000
  }
  • 해결방법: npm 스크립트를 직접 사용하지 않고 node 명령어로 직접 실행하도록 함
module.exports = {
  apps: [
    {
      name: "cappuccino",
      script: "./server.js",
      instances: 3,
      exec_mode: "cluster",
      wait_ready: true,
      listen_timeout: 3000,
      autorestart: true,
      max_memory_restart: "1G",
      env: { NODE_ENV: "production" },
    },
  ],
};

프로젝트 nodejs 버전관리 문제

  • 문제점: 프로젝트에서 사용하려는 주요 모듈을 버전업 하고자 할때, nodejs버전을 중간에 바꾸기 힘들 수 있음
  • 해결방법: nvm을 이용하여 세팅
    • .nvmrc에 버전명시 프로젝트 install시 nvm use 명령으로 버전을 바꿔주도록 세팅

2. 젠킨스 설치 및 세팅

  1. 젠킨스 설치 (mac)
    // 설치 (lts로 설치하지 않으면 버전 디펜던시가 깨지면서 프러그인 자동 설치가 안됨)
    $ brew install jenkins-lts
    
    // 시작
    $ brew services start jenkins-lts
    
    // ip및 port 변경 하는 곳
    $ sudo vim /usr/local/Cellar/jenkins-lts
    
  2. 젠킨스 플러그인 설치
    • Bitbucket Plugin (빌드 유발 옵션에 사용되지만 현재는 사용하지 않음)
    • NodeJS Plugin
  3. 젠킨스 서버와 서비스 서버 사이에 ssh 인증하기 - 매번 암호 기입없이 ssh 접근
    ssh-keygen -t rsa -b 4096 -m PEM // 젠킨스 서버에서
    
    // 젠킨스 서버에서 만든 퍼블릭 키를, 서비스 서버의 authorized_keys에 등록
    id_rsa.pub >> /root/.ssh/authorized_keys
    
    chmod 700 ~/.ssh // 파일 권한 변경
    chmod 600 ~/.ssh/authorized_keys
    
  4. jenkins관리 > Global Tool Configuration 에서 nodeJS 버전 세팅
    • 어떤 버전이 어디에서 사용되는지 관리할 수 있음
  5. 새로운 item > Freestyle project 클릭
    • 소스관리 Git선택
      • Repository URL, username / password 기입
      • target branch 설정
    • 빌드환경
      • Delete workspace before build starts 선택
      • Provide Node & npm bin/ folder to PATH 선택 (NodeJS Plugin)
        • 프로젝트에 사용하고자 하는 nodejs버전 선택
    • Add build Step > Execute shell 선택 후 배포 스크립트 기입
      node --version // NodeJS Plugin 로 설정한 버전이 잘 반영되는지 테스트
      npm install // 프로젝트 설치
      npm run lint // 코드 검증
      rm -rf node_modules // 실제 서버로 복사하기 전에 불필요한 파일 제거 
      
      // 실제 서버로 파일 복사
      rsync -avz --exclude .git/ ../react_study a210331005@192.168.0.4:/Users/a210331005/deploytest/
      
      -#!/bin/sh
      ssh -t -t a210331005@192.168.0.4 <<EOF // 실제 서버에 ssh로 접속
       cd /Users/a210331005/deploytest/react_study // 프로젝트 폴더로 이동
       rm -rf node_modules // 기존 모듈 삭제
       nvm install // .nvmrc에 명시된 버전으로 설치
       nvm use // // .nvmrc에 명시된 버전으로 변경
       npm install // 프로젝트 설치
       npm run build:reload && exit // 빌드 후 pm2를 reload하고 ssh에서 빠져나감
      EOF