사내 프로젝트를 젠킨스를 통해 배포 자동화를 구축 후, 문제가 발생하게 된다.

상기의 이미지처럼, Jenkins Build Step을 쉘 스크립트로 비교적 간단하게 작성했다.

 

NestJS로 프로젝트를 구성했던 터라,

  1. npm run build 후(TypeScript compile to JavaScript)
  2. 생성된 dist 디렉토리의 main.js 실행이 필요했기에 pm2 기본 config 파일을 생성(ecosystem.config.js)
  3. 해당 config.js 파일 내부에 필요한 인스턴스 갯수와, 실행 파일의 경로를 작성해주었다.
// root/ecosystem.config.js

module.exports = {
  apps: [
    {
      name: 'primary',
      script: './dist/main.js',
      instances: 1,
      exec_mode: 'cluster',
    },
    {
      name: 'replica',
      script: './dist/main.js',
      instances: 13,
      exec_mode: 'cluster',
    },
  ],
};

위의 단계를 통해 프로젝트 레포지토리에 푸쉬 이벤트 발생 시, 레포지토리에서 웹 훅을 발생시켜 Jenkins 서버에서 자동으로

위 첫번째 사진의 Build Step들이 실행되도록 구축하였다.

 

요약

  • Jenkins Build Step에서 노드 프로세스 매니저인 Pm2를 config.js 실행 시키도록 설정
  • 위의 Jenkins jobs 이 끝난 후, 배포 성공 여부를 슬렉 알림으로 받음
  • 배포 서버에 정상적으로 변경 사항이 반영된 것까지 확인 후, 모든 것이 끝났다고 생각했다.

그러나, 문제는 여기서 발생하게 된다.

  • 배포 서버의 pm2 로그 확인을 위해 ssh로 접속 후, pm2 logs를 확인 해보았지만 .. 아무것도 보이지 않았다
  • 뭔가 잘못된 것을 직감 하고 배포 된 웹서버에 접속해보았지만...이게 웬일 ? 실제로 웹은 정상적으로 동작하고 있었다. (ㄷㄷㄷ...)
  • 다시 말하자면, 젠킨스에서 pm2 start와 reload가 잘 일어 났지만, 서버의 pm2 list엔 전혀 찾아 볼 수가 없었다.

왜 이런일이 발생한걸까? 처음부터 접근 방법이 잘못 되었던 것이다.

 

Jenkins 잡에서 실행되는 pm2 프로세스는 서버 로컬 환경이 아닌 젠킨스 내의 새로운 세션에서 실행된다.

따라서 이 새로운 세션에서 pm2를 실행한 것이니, 로컬 환경에서 직접 프로세스의 목록을 확인이 불가능 했던 것이다.

 

또한 pm2는 현재 사용자 세션과 관련된 프로세스 목록만 표시하기 때문에, 젠킨스 내부의 새로운 세션에서 실행되는 프로세스는 해당 세션에 대한 정보를 표시 할 수 없으며, pm2 list에서 보이지 않았던 것이다.

 

서버 로컬 환경에서 pm2 list가 나오지 않았던 이유를 알게됐다.. 하지만 왜? 젠킨스는 이렇게 동작하는 걸까 ?

기존 처음 젠킨스를 접하고, 쉘 스크립트로 파이프라인을 구축했을 때, 해당 서버의 로컬 환경에서 정의된 쉘 스크립트를 그대로 실행하는 줄 알았다. 

그러나, 젠킨스 잡은 젠킨스에서 실행되는 작업 단위로, 일반적으로 빌드, 배포, 테스트 등의 작업만을 수행 한다.

 

위에 설명한 바와 같이 젠킨스 잡은 새로운 세션에서 실행되며, 이는 젠킨스 잡이 독립된 환경에서 실행되도록 하는 데 목적이 있다.

  1. 환경 분리 : 젠킨스 잡은 여러 개의 빌드 또는 배포를 병렬로 실행할 수 있다. 이를 위해 각 Job은 독립된 환경에서 실행되어야 한다.
    즉, 각 Job은 자체적인 프로세스 그룹 또는 세션에서 실행되어 서로의 작업에 영향을 주지 않는다.
  2. 격리와 안정성 : 새로운 세션에서 Jenkins Job을 실행함으로써, 현재 사용자 세션 또는 기존의 실행 중인 프로세스에 영향을 주지 않고 독립적으로 실행될 수 있다. 이렇게 함으로써 잡의 실행 중에 발생하는 예외나 에러가 다른 프로세스에 영향을 주지 않고 안정적으로 처리 될 수 있다.
  3. 자원 관리: 젠킨스 잡이 별도의 세션에서 실행되면, 해당 세션에 할당된 자원(메모리, CPU등) 을 더 효율적으로 관리가 가능하다.

따라서 젠킨스 잡은 새로운 세션에서 실행되며, 젠킨스에서 실행되는 pm2 프로세스는 새로운 세션에서 실행되어 pm2 list를 통해 직접 빌드 스크립트에서 확인을 해야한다.

 

젠킨스 pm2가 새로운 세션에서 동작한다는 것을 인지한 후, 해당 빌드 스크립트(젠킨스 잡)에서 프로세스 로그를 표현하기엔 보기가 상당히 불편했기 때문에 다른 방법을 모색 해보았다.

 

자동 업데이트 스크립트 구성하기

젠킨스에 의해 실행될 스크립트를 먼저 작성.

#!/bin/bash
sudo npm install # yarn이나 npm 둘 다 하나만
npm run build
pm2 restart ecosystem.config.js

해당 파일을 프로젝트 루트 경로에 생성 해주고, Jenkins 잡 빌드 스크립트에서 해당 파일을 실행 시켜준다면,

처음 원했던 대로 새로운 세션에서 실행되지 않고 서버 로컬 환경에서 pm2 프로세스로 실행이 되며 서버 로그를 쉽게 확인이 가능했다.. !

 

Terraform ?

  • Hashicorp에서 오픈 소스로 개발 중인 클라우드 인프라스트럭처 자동화를 지향하는 IaC 도구
  • HCL(Hashcorp Configuration Language) 언어를 사용하여 리소스를 선언
  • 인스턴스, 네트워크와 같은 low-level뿐 아니라 DNS, SaaS와 같은 high-level의 요소도 관리가 가능.

Terraform 특징

  • IaC
    • 인프라를 코드로 정의하여 생산성과 투명성을 높임.
    • 정의한 코드를 쉽게 공유하여 협업이 가능
  • Execution Plan
    • 사소한 변경이 인프라 전체에 어떤 영향을 미칠지 미리 확인이 가능함.
    • 종속성 그래프를 작성하여 이 그래프를 바탕으로 계획을 세우고, 적용되었을 때 변경되는 인프라 상태를 확인가능
  • Change Automation
    • 여러 장소에 같은 구성의 인프라를 구축하고 변경할 수 있도록 자동화가 가능
    • 인프라를 구축하는 데 드는 시간을 절약하고 사람이 직접 했을 때의 실수를 줄일 수 있음.

'''
알파벳 대문자와 숫자(0~9)로만 구성된 문자열이 입력으로 주어진다.
이때 모든 알파벳을 오름차순으로 정렬하여 이어서 출력한 뒤에, 그 뒤에 모든 숫자를 더한 값을
이어서 출력합니다.

예를 들어 K1KA5CB7이라는 값이 들어오면 ABCKK13을 출력합니다.
'''

def replace():
    strings = input()
    alphabet = []
    num = 0

    for string in strings:
        if string.isalpha():
            alphabet.append(string)
        else:
            num += int(string)
    alphabet.sort()
    result = ''.join(alphabet)
    print(result + str(num))
replace()

'알고리즘,자료구조' 카테고리의 다른 글

[왕실의 나이트]  (3) 2023.07.10
'''
주어진 8 X 8 체스판에서 , 특정한 좌표가 주어졌을 때,
나이트가 이동 가능한 경로의 경우의 수를 출력 하시오.

나이트는
수평으로 두칸 이동한 뒤에 수직으로 한 칸 이동하거나,
수직으로 두 칸 이동한 뒤에 수평으로 한 칸 이동할 수 있습니다.

행의 좌표는 1~8 까지로 표시하며, 열의 좌표는 a~h 까지로 표시합니다.
'''


def chess():
    count = 0
    information = input()
    row = int(information[1])
    # 열의 값은 a~h 까지의 문자로 주어지므로 아스키 코드로 변경 후 (예 : a = 97) a로 빼고 1을 더하면 해당 열의 값을 구할 수 있다.
    # information[0]가 c일 경우는 99 이므로, a=97을 뺀후 , 1을 더하면 열의 좌표인 3이 된다.
    colunm = int(ord(information[0])) - int(ord('a')) + 1

    # 나이트가 이동가능한 좌표를 튜플 리스트로 저장해놓는다.
    # ex) x 좌표가 -2 가 된다는 것은 위로 이동한다는 것, 또한 y 좌표가 1 이 되는 것은 오른쪽으로 이동
    steps = [(-2, 1), (-2, -1), (-1, 2), (1, 2), (2, -1), (2, 1), (1, -2), (-1, -2)]

    for step in steps:
        # 나이트가 이동 가능한지 체크
        # 들어온 행 값 ( information[1])에 x좌표를 더해 계산함
        next_row = row + step[0]
        # 들어온 열 값 ( information[1])에 y좌표를 더해 계산함
        next_colunm = colunm + step[1]

        # 이동 가능한 스텝은 체스 판 8x8 크기 안에 있어야 함.
        if 1 <= next_row <= 8 and 1 <= next_colunm <= 8:
            count += 1
    print(count)


chess()

'알고리즘,자료구조' 카테고리의 다른 글

문자열 재정렬  (0) 2023.07.11

대중적인 formatting rule과 linting rule로 설정함

(rule이 각자 다를 수 있으니 충분한 협의 후 코딩 rule마다 변경)

 

1. node package manager install : npm init -y

—> package.json

의존성 표시

 

2. Formatting: prettier

npm install --save-dev prettier

 

—>package.json (prettier install)

—>package-lock.json

 

3. prettier 사용 시 필요 (+ prettier Extension)

.prettierrc 파일 생성

<—.prettierrc—>

 

{

    "semi" : false,  

    "singleQuote": true

}

 

4. .vscode 폴더 생성 -> settings.json 파일 생성 ( 로컬 파일 세팅 모아둠, 본 프로젝트에만 쓰이는 세팅들 for javascript)

<—settings.json—>

{

    "[javascript]": {

        "editor.formatOnSave": true,

        "editor.defaultFormatter": "esbenp.prettier-vscode"

    },

    "[json]": {

      "editor.defaultFormatter": "esbenp.prettier-vscode",

      "editor.formatOnSave": true,

      "editor.tabSize": 2,

      "editor.detectIndentation": false,

      "editor.insertSpaces": true

    },

    "[jsonc]": {

      "editor.defaultFormatter": "esbenp.prettier-vscode",

      "editor.formatOnSave": true,

      "editor.tabSize": 2,

      "editor.detectIndentation": false,

      "editor.insertSpaces": true

    },

    "tailwindCSS.emmetCompletions": true  // tailwindCSS 사용시에만

}

5. eslint 설치 : npm install —save-dev eslint

 

5-1. eslint 사용 시 필요 —> eslint 설정 파일 생성

< — .eslintrc.js —>

module.exports = {

  root: true,

  parserOptions: {

    ecmaVersion: 2020,

  },

  extends: ['airbnb-base', 'plugin:node/recommended', 'prettier'],

  rules: {

    'import/prefer-default-export': ['off'],

  },

}

 

6.  airbnb-base linting rule 설치

npm install --save-dev eslint-config-airbnb-base eslint-plugin-import

 

  1. npm install --save-dev eslint-config-prettier
  2. npm install --save-dev eslint-plugin-node
  3. < — .eslintrc.js —>

module.exports = {

  extends: ['airbnb-base', 'plugin:node/recommended', 'prettier'],

}

7. prettier 확장자 설치 (+eslint)

 

8. type checking (  // @ts-check   )

 npm install --save-dev typescript

 

9. node환경에서 type checking

npm install --save-dev @types/node(노드에서 주로 사용되는 객체들의 타입정보)

 

10. jsconfig.json

<  jsconfig.json >

{

  "compilerOptions": {

    "strict": true,

    "noImplicitAny": true,

    "noUnusedParameters": true,

    "noUnusedLocals": true,

    "noUncheckedIndexedAccess": true

  },

  "include": ["src/**/*"],

  "exclude": ["node_modules"]

}

+ Recent posts