Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔧 Blue-Green 배포를 위한 deploy script 수정 #154

Merged
merged 5 commits into from
Aug 24, 2024

Conversation

jinlee1703
Copy link
Member

@jinlee1703 jinlee1703 commented Aug 15, 2024

작업 이유

  • 서비스 안정성 향상을 위한 무중단 필요성 대두

작업 사항

프로세스

graph TD
	A[시작] --> B{현재 실행 중인 서비스 확인}
	B -->|Blue| C[Green 서비스 선택]
	B -->|Green| D[Blue 서비스 선택]
	C --> E[새 버전 이미지로 선택된 서비스 시작]
	D --> E
	E --> F{헬스 체크}
	F -->|성공| G[이전 서비스 중지 및 제거]
	F -->|실패| H[새 서비스 중지 및 제거]
	G --> I[nginx 설정 업데이트]
	H --> J[이전 서비스 재시작]
	I --> K[배포 완료]
	J --> L[롤백 완료]
Loading
  • docker-compose.yml 수정 (was)

    ...
    was_blue:
      container_name: was_blue
      image: pennyway/pennyway-was:${WAS_VERSION}
      ports:
        - "${WAS_BLUE_PORT:-8080}:8080"
      environment:
        - TZ=Asia/Seoul
      env_file:
        - .env
      depends_on:
        - rdb
        - cache
      
    was_green:
      container_name: was_green
      image: pennyway/pennyway-was:${WAS_VERSION}
      ports:
      	- "${WAS_GREEN_PORT:-8081}:8080"
      environment:
      	- TZ=Asia/Seoul
      env_file:
      	- .env
      depends_on:
      	- rdb
      	- cache
  • nginx.conf 수정 (bastion)

    upstream backend {
      server xxx.xxx.xxx.xxx:8080;
      server xxx.xxx.xxx.xxx:8081;
    }
    ...    
  • deploy.yml 수정

    ...
    # 별도 script 파일을 분리하여 동작
    chmod +x deploy.sh 
    bash -x ./deploy.sh
  • deploy.sh 작성

      #!/bin/bash
      
      set -e
      
      # 현재 실행 중인 서비스 확인
      CURRENT_SERVICE=$(docker-compose ps --services --filter "status=running" | grep "was_")
      
      # 새 서비스 결정
      if [ "$CURRENT_SERVICE" = "was_blue" ]; then
        NEW_SERVICE="was_green"
        NEW_PORT="8081"
      else
        NEW_SERVICE="was_blue"
        NEW_PORT="8080"
      fi
      
      echo "Current service: $CURRENT_SERVICE"
      echo "New service: $NEW_SERVICE"
      echo "New port: $NEW_PORT"
      
      # 버전 설정
      if [ -z "$VERSION" ]; then
        VERSION="latest"
      fi
      echo "Version: $VERSION"
      
      # .env 파일 업데이트
      sed -i "s/WAS_VERSION=.*/WAS_VERSION=$VERSION/" .env
      
      # 새 서비스 시작
      docker-compose up -d $NEW_SERVICE
      
      echo "Waiting for service to start..."
      sleep 30
      
      # 헬스 체크
      for i in {1..30}; do
        echo "Attempting health check ($i/30)..."
        echo "Checking port: $NEW_PORT"
      
        if nc -z localhost $NEW_PORT; then
          echo "Port $NEW_PORT is open. Proceeding with HTTP check."
      
          CURL_OUTPUT=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$NEW_PORT/v3/api-docs)
      
          if [ "$CURL_OUTPUT" -eq 200 ]; then
            echo "Health check passed. New version is healthy."
      
            # 이전 서비스 중지 및 제거
            if [ -n "$CURRENT_SERVICE" ] && [ "$CURRENT_SERVICE" != "$NEW_SERVICE" ]; then
              echo "Stopping and removing old service: $CURRENT_SERVICE"
              docker-compose stop $CURRENT_SERVICE
              docker-compose rm -f $CURRENT_SERVICE
            else
              echo "No old service to remove or new service is the same as current service."
            fi
      
            # 새 서비스가 실행 중인지 확인
            echo "Verifying new service is running..."
            RUNNING_SERVICE=$(docker-compose ps --services --filter "status=running" | grep "was_")
            if [ "$RUNNING_SERVICE" = "$NEW_SERVICE" ]; then
              echo "Deployment successful. New service $NEW_SERVICE is running."
              exit 0
            else
              echo "Error: New service $NEW_SERVICE is not running after deployment."
              exit 1
            fi
          else
            echo "Health check failed. HTTP status: $CURL_OUTPUT"
          fi
        else
          echo "Port $NEW_PORT is not open yet."
        fi
      
        echo "Checking container status and logs:"
        docker-compose ps $NEW_SERVICE
        docker-compose logs --tail=50 $NEW_SERVICE
      
        echo "Waiting 20 seconds before next attempt..."
        sleep 20
      done
      
      echo "Health check failed after 30 attempts. Rolling back..."
      docker-compose stop $NEW_SERVICE
      docker-compose rm -f $NEW_SERVICE
      if [ -n "$CURRENT_SERVICE" ]; then
        echo "Ensuring old service is running: $CURRENT_SERVICE"
        docker-compose up -d $CURRENT_SERVICE
      fi
      echo "Rollback complete. Deployment failed."
      exit 1

리뷰어가 중점적으로 확인해야 하는 부분

  • fork 레포지토리에서 테스트 완료하였고, Notion에 누락되었던 환경 변수 업데이트(새로 추가된 사항은 없음)하였습니다.
  • Blog 포스팅

동작 결과

deploy.sh를 실행할 때마다 blue-green 배포가 실행됩니다.

Blue 배포

image

Green 배포

image

발견한 이슈

  • 없음

@jinlee1703 jinlee1703 added the enhancement New feature or request label Aug 15, 2024
@jinlee1703 jinlee1703 self-assigned this Aug 15, 2024
@jinlee1703 jinlee1703 changed the title Blue-Green 배포를 위한 deploy script 수정 🔧 Blue-Green 배포를 위한 deploy script 수정 Aug 15, 2024
@psychology50
Copy link
Member

방법1. 현재 브랜치에 PR synchronize되면 github actions 동작하도록 트리거 설정해두기
방법2. 개인 repo에 secret key 전부 넣어보고 테스트 하기

정도...?
전자는 Actions 로그에 실패 기록이 남는다는 흠이 있긴 한데, 전 상관 없어서 괜찮은데
다른 문제는 태그랑 릴리즈 조건 때문에 골치가 좀 아프네요..

@jinlee1703
Copy link
Member Author

정도...? 전자는 Actions 로그에 실패 기록이 남는다는 흠이 있긴 한데, 전 상관 없어서 괜찮은데 다른 문제는 태그랑 릴리즈 조건 때문에 골치가 좀 아프네요..

후자가 깔끔하긴 한데, repo가 달라짐에 따라 생기는 문제가 있을까봐 고민되긴 하네요..

@psychology50
Copy link
Member

후자가 깔끔하긴 한데, repo가 달라짐에 따라 생기는 문제가 있을까봐 고민되긴 하네요..

그럼 후자로 테스트 해보시도, 병합 전에 전자로 최종 테스트 해보시면 어떤가요??

@jinlee1703
Copy link
Member Author

jinlee1703 commented Aug 19, 2024

그럼 후자로 테스트 해보시도, 병합 전에 전자로 최종 테스트 해보시면 어떤가요??

그럼 Draft로 전환 후에 성공 시 다시 전환하도록 하겠습니다~

@jinlee1703 jinlee1703 marked this pull request as draft August 19, 2024 13:21
@jinlee1703 jinlee1703 marked this pull request as ready for review August 24, 2024 03:44
@psychology50
Copy link
Member

하나 이해 안 가는 부분만 있어서, 답변해주시고 바로 병합하시면 될 것 같습니다!

하나의 compose 파일에 was-green, was-blue 서비스가 모두 정의되어 있는 거 같은데, 어떻게 docker-compose를 했을 때 선택적으로 서비스를 재실행하는 건가요??
전 당연히 두 파일을 분리해야 한다고 생각했는데, 원리가 궁금해서 커멘트 남깁니다!

@jinlee1703
Copy link
Member Author

jinlee1703 commented Aug 24, 2024

하나의 compose 파일에 was-green, was-blue 서비스가 모두 정의되어 있는 거 같은데, 어떻게 docker-compose를 했을 때 선택적으로 서비스를 재실행하는 건가요?? 전 당연히 두 파일을 분리해야 한다고 생각했는데, 원리가 궁금해서 커멘트 남깁니다!

# 새 서비스 결정
if [ "$CURRENT_SERVICE" = "was_blue" ]; then
  NEW_SERVICE="was_green"
  NEW_PORT="8081"
else
  NEW_SERVICE="was_blue"
  NEW_PORT="8080"
fi

# 새 서비스 시작
docker-compose up -d $NEW_SERVICE

요 부분을 보면 $NEW_SERVICE라는 환경 변수를 통해 새롭게 실행할 서비스의 이름(was_blue or was_green을 함께 입력하도록 스크립트를 작성하였습니다. 이렇게 하면 docker-compose.yml에 정의되어 있는 모든 서비스가 아닌 해당 이름과 동일한 서비스만 실행시킬 수 있는 것을 확인하였습니다 :)

@psychology50
Copy link
Member

아..? 저렇게 서비스 이름을 선택할 수 있었다는 걸 완전히 까먹고 있었네요.
나머지는 사전에 찾아봤던 내용이라 이해할 수 있었습니다. 수고하셨어요!

@jinlee1703 jinlee1703 merged commit f3216b4 into dev Aug 24, 2024
1 check passed
@jinlee1703 jinlee1703 deleted the feat/PW-511-zero-downtime-deployment branch August 24, 2024 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants