Skip to content

야 너두 무중단 배포 할 수 있어 🫵

KimYujeong edited this page Jan 7, 2024 · 3 revisions

feat. docker, nginx, 배포 쌩노베의 우아한 우하하 무중단 배포 도전기

#무중단_배포 #blue/green #nginx #graceful_shutdown #docker_compose


무중단 배포의 필요성

intro

신규 버전을 새롭게 배포하는 과정을 가정해보자.

현재 실행중인 버전을 종료하고 신규 버전을 실행하는 동안 사용자는 서비스를 이용할 수 없다. 이러한 사용자 경험 저하를 방지 하고자 서비스의 중단 없이 업데이트를 수행하는 무중단 배포를 구현하기로 결심했다 🔥


어떤 배포 전략을 사용할까?

무중단 배포 전략에는 Rolling 배포, Blue/Green 배포 크게 두 종류가 있었다. 두 전략은 트래픽을 점진적으로 옮기느냐, 한꺼번에 옮기느냐의 차이가 있었다.

strategies

Rolling 배포는 트래픽을 점진적으로 옮기는 배포 전략으로, 구버전이 실행되고 있는 인스턴스를 점차적으로 신규 버전으로 전환한다. 클라우드 서비스를 이용하여 간편하게 구현할 수 있지만, 구버전과 신규버전이 동시에 서비스되므로 호환성 문제가 발생할 수 있다.

반면, Blue/Green 배포는 트래픽을 한 번에 전환하는 방식이다. 버전 호환성이 발생하진 않지만 실제 운영에 필요한 서버 자원에 비해 2배의 자원을 확보해야 한다는 단점이 있다.

우리는 클라우드 서비스의 로드밸런서를 사용하지 않기 때문에 여러 대의 인스턴스를 활용하는 Rolling 전략은 적합하지 않다고 판단했다 . 무중단 배포를 위해 Blue/Green 전략을 채택했다!! 👍


nginx와 graceful shutdown의 도입

nginx

Blue/Green 배포를 구현하기 위해 nginx를 활용했다. 버전별로 포트 번호를 다르게 사용하여 신규 버전을 구동하고, 신규 어플리케이션이 동작하면 nginx 설정 파일을 수정하여 신규 어플리케이션으로 프록시한다.

graceful shutdown

그리고 graceful shutdown을 적용하여 실행 중인 구버전의 어플리케이션을 종료하기로 결정했다. graceful은 더 이상 새로운 요청을 받지 않고 기존 요청들을 완료한 후에 어플리케이션을 종료 하는 것을 의미한다.

graceful shutdown2

현재 진행중인 작업을 완료하고 종료하기 때문에 사용자에게 적절한 메시지를 제공할 수 있고, 종료 프로세스를 부드럽게 수행함으로써 UX 경험을 향상 시킬 수 있다. 뿐만 아니라 트랜잭션이 진행중이더라도 완료되기까지 기다리기 때문에 데이터의 무결성을 보장 할 수 있다.


Blue/Green 배포 구현 과정

before

Blue/Green 배포을 도입하기 전의 플로우부터 살펴보자. 하나의 인스턴스에 여러 어플리케이션을 실행시키고, nginx가 URL에 따라 서로 다른 어플리케이션으로 프록시한다. 현재 WAS 서버는 3000번, 시그널링 서버는 3001번 포트를 사용하고 있다 🏃

Step1️⃣ 각 버전을 위한 Docker Compose 작성하기

docker compose

앞서 언급했듯이 Blue/Green 배포 전략은 운영에 필요한 서버 자원 대비 2배의 서버 자원이 필요하다. 같은 포트에서 신규 버전의 어플리케이션을 띄울 수 없으므로 Blue와 Green을 위한 Docker Compose 파일을 작성해줬다. Blue는 3000번, 3001번 포트를, 그린에서는 3002번과 3003번 포트를 사용한다.


Step2️⃣ Blue/Green 환경을 확인하여 새로운 어플리케이션 띄우기

step2

이제 동작 과정과 함께 Blue/Green 전략 구현 방식에 대해 알아보자. 서버 인스턴스는 Blue를 실행하는 중이며 새로운 신규 버전을 배포해야 하는 상황이다. 구버전의 어플리케이션이 Blue에서 실행중이므로 Green에 신규 버전의 어플리케이션을 실행한다.


Step3️⃣ nginx 설정 파일을 수정하여 새로운 어플리케이션으로 프록시하기

step 3

Green에서 새로운 어플리케이션을 성공적으로 실행하면, nginx는 Green으로 프록시되로록 설정 파일을 수정해야 한다. Blue로 프록시하는 부분을 Green으로 수정한다.


Step4️⃣ graceful shutdown

step 4-1

이제 tini라는 초기화 프로세스를 이용하여 graceful shutdown을 구현해보자. tini는 Tiny but valid Init의 약자로, 컨테이너 환경에서 프로세스를 초기화하고 부모 프로세스로부터 전달된 종료 신호를 수신하는 도구다.

즉, 도커 컨테이너에서 어플리케이션이 실행되더라도 tini에 의해 종료 신호를 캐치할 수 있다. 이때 SIGTERM 신호를 보내는 명령어를 사용하도록 주의해야 한다. SIGKILL은 프로젝트 강제 종료 신호이므로 graceful shutdown을 시도하지 않는다 🚨

SIGTERM SIGKILL
정상 종료 강제 종료
docker stop docker-compose down docker rm -f docker kill

step4-2

Blue 버전의 프로세스들은 SIGTERM을 수신하면 server.close()를 호출하여 새로운 요청을 받지 않도록 서버를 닫는다. 현재 진행중인 작업이 끝날 때까지 기다렸다가 작업이 끝나면 app.close()를 통해 정상적으로 종료된다 👍



Authored by @kimyu0218

💦 우당탕탕 이슈 해결기

BE

FE

FE/BE

🧑‍🏫 멘토링 일지

📢 회의록

💬 스크럼

💭 팀 회고

💭 개인 회고

🏃 Ongoing Project

Clone this wiki locally