CI CD 파이프라인

React 프로젝트 쉽게 무중단 배포하기 (EC2 + Nginx + Jenkins)

초록색거북이 2023. 9. 1. 11:33
728x90
반응형
SMALL

(기본적으로 AWS 사용법을 알고 있다고 생각하고 글을 작성하였습니다.)

 

 

안녕하세요. 대부분의 회사들은 죽지않는 서비스를 만들기 위해 무중단 배포를 구축한다고 하네요.

그래서 저도 무중단 배포가 너무 해보고 싶었어요.

 

만들면서 여러 삽질도 하면서 포기도 했다가 그러면서 제 방법이 정답은 아니지만, 무중단 배포가 되는 환경을 구축했습니다.

 

여러분들은 시간 낭비하지않게 쉽게 설명해드리고 저의 지식을 공유해드리겠습니다.

 

우선

 

무중단 배포가 뭘까요?

 

https://hudi.blog/zero-downtime-deployment/

 

무중단 배포 아키텍처와 배포 전략 (Rolling, Blue/Green, Canary)

중단 배포 방식과 다운타임 다운타임 서버 한대로 서비스를 운영한다고 가정해보자. 현재 서버에는 V1 버전이 실행되고 있는 상황이다. 그리고 우리는 이번에 여러 기능을 추가한 V2 버전을 새로

hudi.blog

무중단 배포에 대해 자세히 알고싶으시다면 이 블로그를 읽고 오세요.

 

 

 

 

[본론]

 

우선 저는 무중단배포를 위해 - 2대의 서버

Nginx 서버를 위한 - 1대의 서버

Jenkins를 돌리기위한 서버 - 1대의 서버

 

총 4대의 서버가 필요 했습니다.

빠르게 여러대의 서버를 사용하고 무료로 사용할수 있는 좋은 클라우드 AWS 를 사용했습니다. ㅋㅋ

(1년은 무료티어로 이용가능합니다.)

 

young-server1  =  애플리케이션 서버 1번

young-server2 =  애플리케이션 서버 2번

jenkins-server  = 젠킨스 서버

nginx-server = 엔진엑스 서버

 

young-server1 와 young-server2 에는 간단한 리엑트 프로젝트를 올렸습니다.

 

대략 소스코드를 보여드리면

import React from 'react';

const Test = () => {
    return (
        <>
        무중단 배포 화이팅
        </>
    );
}
export default Test;

무중단 배포 화이팅 이라는 텍스트가 보이는 프로젝트에요.

 

young-server1  =  애플리케이션 서버 1번

young-server2 =  애플리케이션 서버 2번

 

이 두 서버에 각 각 접속해서 백그라운드로 애플리케이션을 3000 포트로 돌려줍시다.

이렇게 말이죠.

이렇게 되면       공인IP:3000    으로 각각 서버를 주소창에 치면 위에 작성했던 '무중단배포화이팅' 을 보실수 있습니다.

 

근데 나중에 도메인을 샀다고 가정해봅시다. 

(구매한 도메인 : test.co.kr)

 

사람들이 접속할때 test.co.kr 로 접속을 하지,  test.co.kr:3000 으로 접속하지는 않습니다.

 

사실 80포트는 생략 가능한 포트여서 test.co.kr:80 이렇게 생겼지만 test.co.kr 접속할 수 있는 이유가 이거입니다.

 

80포트로 들어가 3000포트로 리다이렉트 해줄수 있는게 바로 Nginx 입니다. 

 

또한 로드밸런싱이라고 서버 부하를 분산해주는 기능이 있습니다.

 

저희는 위에 이미 Nginx 를 이용할수 있는 서버를 만들어 두었으니, Nginx 를 만들러 가봅시다.

[nginx]

 

nginx-server = 엔진엑스 서버

 

접속 한 후 Nginx 를 설치해줍시다! (설치 방법은 구글링해서 찾아보세요.)

 

설치를 다 하셨다면.



cd /etc/nginx/conf.d 경로로 들어가줍니다.

 

vim young.conf. (young 대신 원하는 이름으로 만들어주셔도됩니다.)

 

young.conf 에 이렇게 작성해줍니다.

 

upstream young {
        server 공인아이피:3000 (1번서버입니다.);
        server 공인아이피:3000 (2번서버입니다.);
}
server {
        listen  80; # nginx를 통해 외부로 노출되는 port.
        server_name 공인아이피 (엔진엑스 서버입니다.);
        location / {
          client_max_body_size 20M;
          proxy_pass    http://young; # arbitrary한 upstream명
        }
    }

위에 upstream 기능은 저 두개의 서버를 로드밸런싱 해주기 위해 설정해주는 곳입니다.

 

아래 server 기능은 server_name 위치를 80 포트로 받겠다 라는 뜻 입니다.

 

즉 엔직엑스 서버 공인아이피로 접속을 하면 upstream 기능을 통해 저 두개의 서버로 분산해서 리다이렉트 해줍니다.

 

이로써 80( 생략가능한포트) 포트로 엔직엑스 서버에 접속하게 되면 1번서버 2번서버를 차례로 접속하게 해주겠네요.

 

이제 nginx 를 재시작 해주고 주소창에 엔직엑스 서버 공인아이피로 접속을 해보세요. 잘 접속 될겁니다.

 

[jenkins]

이제 저희는 띄어진 서버에 배포를 해보고싶어요.

 

어떻게 할까요??

 

Jenkins가 모든걸 해결해줍니다.

 

IDE 에서 프로젝트를 커밋만 하면 무중단 배포로 모든게 완벽하게 되면 얼마나 좋을까요??

지금 해보겠습니다.

위에 만들었던 

https://yjkim-dev.tistory.com/12

https://yjkim-dev.tistory.com/13

https://yjkim-dev.tistory.com/14

위에 링크를 가셔서 

순서대로 따라 하시면 됩니다.

 

순서대로 다 따라 하셨으면 github 과 jenkins 와 webhook 을 이용하여 커밋 시 jenkins 가 반응을 할겁니다.

 

이제 jenkins 안에 파이프라인 스크립트가 잘 작성해주면 모든게 끝납니다.

 

잘 생각해봅시다.

 

저희 EC2 에 접속할때 ec2 생성시 주는 pem 키가 있잖아요? 그거를 jenkins 에 등록해야합니다.

왜냐면 스크립트 작성할 때 ssh 로 ec2서버에 접속할 거거든요.

 

 

 

아무렇게나 설정해주셔도 되는데 중요한건 저 KEY 안에 EC2 인스턴스 만들면서 발급받았던 키값을 전부 복사 해서 붙여넣어줘야합니다.

 

그러고 저장 하면 젠킨스한테 ec2 접속할수 있도록 미리 정보를 준거에요.

 

이제 파이프라인 스크립트 작성하러 가봅시다.

 

위에 github + jenkins + webhook 연결하는 링크를 보고 오셨으면

이렇게 새로운 ITEM 하나가 있을거에요

 

여기에 접속 한후 

 

아래로 내려다보면

 

PIPELINE 적는 칸이 있을거에요.

 

거기에 복사하여 붙여넣어주시고, 각자 본인의 환경에 맡게 수정해줍시다.

 

pipeline {
    agent any
    stages {
        stage('Checkout') {
            steps {
                git branch: 'main',
                    credentialsId: 'github_token',
                    url: '배포할 나의 깃주소'
            }
        }        
        stage('young-server1 port kill And deploy'){
            steps {
                sshagent (credentials: ['ssh-young']) {
                    sh'''
                    ssh -o StrictHostKeyChecking=no ubuntu@1번서버공인아이피 '
                    PID=$(sudo lsof -t -i :3000 -s TCP:LISTEN)
                    sudo lsof -t -i :3000 -s TCP:LISTEN
                    if [ ${PID} != "" ]; then
                        sudo kill -9 ${PID}
                    else
                        echo Not exist process
                    fi
                    cd /app/young/young
                    sudo git pull
                    sudo npm install
                    sudo npm run build
                    sudo nohup npm run start > /dev/null 2>&1 &
                    '
                    '''    
                }
            }
        }
        stage('young-server2 port kill And deploy'){
            steps {
                sshagent (credentials: ['ssh-young']) {
                    sh'''
                    ssh -o StrictHostKeyChecking=no ubuntu@2번서버공인아이피 '
                    SLEEP_TIME=10
                    ATTEMPTS=25
                    PID=$(sudo lsof -t -i :3000 -s TCP:LISTEN)
                    for ATTEMPT in $(seq ${ATTEMPTS}); do
                        STATUS_CODE=$(curl -sL -w %{http_code} 1번서버공인아이피 -o /dev/null)
                    if [ ${STATUS_CODE} == "200" ]; then
                        echo 1번서버공인아이피 server1 complete
                        if [ ${PID} != "" ]; then
                            sudo kill -9 ${PID}
                        else
                            echo Not exist process
                        fi
                            cd /app/young/young
                            sudo git pull
                            sudo npm install
                            sudo npm run build
                            sudo nohup npm run start > /dev/null 2>&1 &
                            exit 0                    
                    else
                        echo 1번서버공인아이피 server1 not yet
                        sleep ${SLEEP_TIME}
                    fi
                done
                exit 1
                    '    
                    '''
                }
                
            }
        }
    }
}

 

이 스크립트에 대해 정리해서 설명해드리면

 

stage('checkout') 

- github 과 jenkins pipeline을 연결 한다.

 

stage('young-server1 port kill And deploy')

1.  1번 서버로 접속하여 3000포트가 떠있는지 확인후 떠있으면 3000포트를 죽인다.

2. /app/young/young 경로로 들어가 git pull 로 최신화를 해온다.

3. npm install -> npm run build -> 백그라운드로 애플리케이션 실행시킨다.

 

stage('young-server2 port kill And deploy')

1.  2번 서버로 접속하여 curl 명령어를 통해 아까 띄었던 1번 서버가 제대로 실행되고있는지 파악한다.

(for문으로 서버가 제대로 실행되고있을때까지 for문을 탈출하지못합니다.)

2.  1번 서버가 제대로 실행되었다면 2번서버 3000포트가 띄어있는지 확인후 떠있으면 3000포트를 죽인다.

3. /app/young/young 경로로 들어가 git pull 로 최신화를 해온다.

4. npm install -> npm run build -> 백그라운드로 애플리케이션 실행시킨다.

 

아는사람은 서버가 잠시 끊긴다는걸 알지만 

잘모르는사람은 서버가 끊긴다는걸 잘 모르는 

무중단 배포를 구축해봤습니다. ㅋㅋ

 

설명이 부족해서 중간에 하다가 막히시는 부분은 댓글 달아주시면 성의 있게 답변해드리겠습니다.

 

또한 잘못된 내용이 있다면 언제든지 태클 환영입니다.

 

 

 

시도를 92번이나...ㅋㅋ

728x90
반응형
LIST