반응형

 

지난 글에서는 코드를 올리면 서버까지 자동으로 전달되는 흐름을 만들어봤습니다.

그런데 막상 서버에 새 코드가 도착하면, 한 가지 문제가 남습니다. 

지금 돌아가고 있는 서비스를 어떻게 새 버전으로 바꾸지 ? 

 

가장 단순한 방법은 이렇습니다.

돌아가던 걸 끄고,새 걸 켠다. 문제는 이 사이입니다. 

크고 켜는 그 몇 초에서 몇십 초 동안, 우리 사이트에 들어온 사람은 접속이 안되는 화면을 보게 됩니다.

방문자가 적을 땐 티가 안나지만, 누군가 딱 그 순간에 들어오면 사이트 죽었네 하고 나가버리는 경우가 생깁니다.

 

이걸 막는게 무중단 배포입니다.

서비스를 한 순간도 끊지 않고 새 버전으로 바꾸는 방법인데, 그 중 가장 이해하기 쉬운 방식이 블루-그린 배포입니다.

이번 글에서는 블루-그린에 대해서 정리하겠습니다.

 


블루 - 그린

 

  • 블루 : 지금 실제로 손님을 받고 있는 현재 버전
  • 그린 : 새로 배포할 다음 버전 

핵심 아이디어는 새 버전(그린)을 옛 버전(블루)옆에 몰래 하나 더 띄어놓고, 그게 정상으로 작동하는 걸 확인한 다음에야 손님을 그쪽으로 넘깁니다. 

옛 버전은 그때까지 멀쩡히 돌고 있으니, 손님 입장에서는 끊기는 순간이 없습니다.

 

식당으로 비유하면 이렇습니다. 

손님 받는 주방(블루)은 그대로 돌리면서, 옆에 새 주방(그린)을 차려놓고 시범 운영을 해봅니다.

새 주방이 음식을 제대로 내는 걸 확인하면, 그때 손님 주문을 새 주방으로 돌리고 옛 주방을 정리합니다.

손님은 밥을 먹다 끊긴 적이 없습니다. 

 


전체 순서 보기 

 

  1. 처음엔 옛 버전만 돌아가고, 사용자는 옛 버전을 보고 있습니다.
  2. 새 버전을 옆에 하나 더 띄웁니다. 이 순간 잠깐 두 버전이 동시에 떠 있습니다.
  3. 새 버전이 정상으로 응답하는지 건강검진(헬스체크)을 합니다.
  4. 검진을 통과하면 옛 버전을 내립니다. 만약 통과하지 못하면 새 버전을 그냥 버리고 옛 버전을 그대로 둡니다.
  5. 트래픽을 새 버전 쪽으로 넘깁니다. 이제 사용자는 새 버전을 보게 됩니다.

여기서 가장 중요한 단계가 3번, 건강검진입니다.

새 버전이 제대로 켜졌는지 확인하지 않고 무작정 손님을 넘기면, 새 버전에 문제가 있을 때 그대로 장애로 이어집니다.

그래서 정상이라고 확인되기 전에는 절대 손님을 안넘긴다가 블루 - 그린의 핵심 약속입니다.

 


건강검진(헬스체크) 

 

건강검진은 말 그대로 너 지금 정상이냐고 새 버전에게 물어보는 겁니다.

보통 서버 프로그램은 나 살아있어요 라고 대답해주는 전용 주소를 하나 열어둡니다.(/health)

배포 스크립트는 새 버전을 띄운 뒤 이 주소에 계속 물어봅니다.

새 버전아, 지금 정상이야?  → 아직... (대답 없음)
새 버전아, 지금 정상이야?  → 아직...
새 버전아, 지금 정상이야?  → 네! 정상입니다

 

이렇게 정상 이라는 대답이 올 때까지 몇 초 간격으로 반복해서 물어봅니다.

정해둔 시간 (예:3분)안에 정상 대답이 오면 통과, 안오면 실패로 처리 합니다.

 

한 가지 팁을 드리면, 프로그램이 켜진 것과 준비된 것은 다릅니다.

특히 자바 같은 언어로 만든 서버는 컨테이너가 실행된 뒤에도 내부적으로 한참 준비를 합니다.

그래서 켜지자마자 물어보면 아직 준비 중이라 실패로 오해할 수 있습니다.

이걸 막으려면 처음 몇십 초는 아예 물어보지 않고 기다려주는 여유 시간을 두는 게 좋습니다.

 


어떻게 구현하나요 ? 

 

블루 - 그린은 도커를 쓰면 구현이 깔끔합니다.

같은 프로그램을 이름만 다르게 두 개 띄울 수 있습니다.

아래는 배포 스크립트(.sh 파일)의 뼈대입니다. 본인 환경에 맞게 바꿀 부분은 OOO으로 표시했습니다.

 

[1단계 - 새 버전(그린)띄우기]

# 새 버전을 'green'이라는 이름으로 띄운다
docker run -d \
  --name OOO-green \
  --health-cmd="OOO(정상인지 확인하는 명령어, 예: wget으로 health 주소 호출)" \
  --health-interval=30s \
  --health-start-period=60s \
  OOO(실행할 이미지 이름):OOO(버전 태그)

 

여기서 --health-* 로 시작하는 옵션들이 건강검진 설정입니다.

도커가 알아서 일정 간격으로 검진을 해주고, 그 결과를 정상(healthy)또는 비정상으로 기록해줍니다.

--health-start-period가 아까 말한 여유 시간입니다.

 

[2단계 - 건강검진 통과 기다리기]

# green이 '정상' 상태가 될 때까지 기다린다
while true; do
  상태=$(docker inspect --format='{{.State.Health.Status}}' OOO-green)
  if [ "$상태" = "healthy" ]; then
    echo "정상 확인! 다음 단계로 진행"
    break
  fi
  sleep 5   # 5초 쉬고 다시 확인
done

 

도커가 기록해준 건강검진 결과를 5초마다 꺼내 보면서, 정상(healthy)이 될 때까지 기다리는 부분입니다.

실제로는 여기에 정해둔 시간이 지나면 포기하고 실패 처리하는 부분도 같이 넣어야 합니다.

안 그러면 새 버전이 영영 안 켜질때 무한정 기다리게 됩니다.

 

[3단계 - 옛 버전 내리고, 이름 바꾸기]

# 옛 버전(blue) 내리기
docker stop OOO-blue
docker rm OOO-blue

# 새 버전(green)의 이름을 blue로 바꾼다
docker rename OOO-green OOO-blue

 

여기가 살짝 신기한 부분인데, 새 버전의 이름을 옛 버전 이름으로 바꿔치기합니다.

이렇게 하면 실제로 돌아가는 건 새 버전인데, 이름표는 항상 blue로 유지됩니다.

다음 배포 때 또 green을 새로 띄우면 되니, 같은 절차를 계속 반복할 수 있게 됩니다.

 

[4단계 - 트래픽을 새 버전으로 넘기기]

 

마지막으로 사용자 접속을 새 버전 쪽으로 넘겨야 합니다.

보통 앞단에 Nginx같은 교통 정리 담당(리버스 프록시)을 두는데, 컨테이너가 바뀌면 이 친구에게 이제 새 쪽을 보라고 한번 알려줘야 합니다.

# Nginx에게 설정을 다시 읽으라고 신호를 준다 (끊김 없이)
docker exec OOO-nginx nginx -s reload

 

이 reload는 Nginx를 껐다 켜는 게 아니라, 돌아가는 상태에서 설정만 새로 읽게 하는 명령이라 이것 역시 서비스가 끊기지 않습니다.

 


일이 잘못됐을 때 - 롤백

 

블루 - 그린의 큰 장점 하나가 되돌리기(롤백)가 쉽다는 점입니다.

새 버전을 올렸는데 한참 뒤에야 문제가 발견됐다고 해봅시다. 이럴 때 옛 버전의 이미지만 보관해뒀다면, 그 버전으로 다시 띄우기만 하면 됩니다.

# 문제가 생겨서 이전 버전으로 되돌리기
docker stop OOO-blue
docker rm OOO-blue
docker run -d --name OOO-blue OOO(이전 버전 이미지):OOO(되돌릴 버전 태그)

 

그래서 배포할 때마다 버전마다 다른 이름표를 붙여서 이미지를 보관해두는 게 중요합니다.

날짜-고유번호 같은 형식으로 태그를 붙여두면 나중에 어제 그 버전으로 돌려줘가 가능해집니다.

 

한 가지 주의할 점은 되돌릴 때도 컨테이너가 새로 떠서 위치가 바뀌므로, 위 4단계 Nginx다시 읽기를 똑같이 한 번 해줘야 트래픽이 제대로 넘어갑니다. 
이걸 빠트리면 되돌렸는 데도 화면이 안바뀌는 상황이 생길 수 있습니다.

 


완벽한 무중단은 아니다.

 

여기까지 오면 서비스가 한 순간도 끊기지 않는다고 하고 싶지만, 정확히 말하면 아주 짧은 빈틈이 있을 수 있습니다.

옛 버전을 내린 시점과 Nginx에게 새쪽을 보라고 알려준 시점 사이에, 잠깐이지만 이미 사라진 옛 버전으로 접속이 갈 수 있습니다.

이 구간에서 운 나쁜 요청은 잠깐 오류를 받을 수 있습니다.

 

개인 프로젝트나 방문자가 많지 않은 서비스라면 이 빈틈은 사실상 체감되지 않습니다.

다만 완벽한 0초 무중단을 노린다면, 옛 버전을 내리기 전에 먼저 Nginx가 새 쪽을 보게 만들어두고 그 다음에 옛 버전을 내리는 식으로 순서를 바꾸는 방법이 있습니다.

처음부터 완벽하게 만들 필요는 없고, 이런 한계가 있다는 것만 알아두시면 나중에 트래픽이 늘었을 때 개선할 지점이 됩니다.

 


정리 

 

이번 글에서는 서비스를 끊지 않고 새 버전으로 바꾸는 블루 - 그린 배포를 정리했습니다.

핵심만 다시 짚으면 이렇습니다.

  • 새 버전(그린)을 옛 버전(블루)옆에 먼저 띄운다
  • 새 버전이 정상인지 건강검진으로 확인한다 - 통과 전에는 절대 손님을 넘기지 않습니다.
  • 통과하면 옛 버전을 내리고, 이름을 바꿔서 다음 배포를 준비합니다.
  • 트래픽 담당(Nginx)에게 새 쪽을 보라고 알려줍니다.
  • 버전마다 태그를 붙여 이미지를 보관해두면 되돌리기가 쉬워집니다.

 

다음 글에서는 이 모든게 돌아가는 무대인 서버 자체를 세팅하는 방법을 다루겠습니다.

홈 서버든 클라우드 서버든 리눅스 위에서 하는 일은 거의 같으니 Nginx 설치부터 차근차근 정리하겠습니다. 

728x90
반응형