[Infra] 무중단 배포 구현

이열음·2022년 10월 18일
0

무중단 배포 전략하고 이어지는 글입니다!

결론부터 말하자면..

이전 논의 사항을 바탕으로 우리팀 백엔드 최종 전략은 블루그린이다
현재는 DEV 서버에만 적용되어 있으며, L4 로드밸런싱중 포트를 활용한다.

3일정도 DEV에 신기능 머지 진행 후 에러가 없다고 판단되면 PROD 서버에도 적용할 예정이다. 이전 게시글에서도 말했듯 가해지는 부하가 적고 한정적일 예정이라 현실적으로는 포트단위로 해도 좋을 듯 하나 fail over 대비차원에서 IP단위로도 해볼까 싶다.(아니면 L7에 URL버저닝해서 프엔이랑 같이 돌아가는걸 구상해보아도 좋을 듯 하다.)

그래서 어떻게 했나?

아 몰라 아무튼 지금 우리는 포트 8080과 8081을 번갈아서 사용한다.
설계해서 구현한 로직은 다음과 같다.


1. 깃허브에 머지
2. 젠킨스에 트리거 동작해서 빌드 시작
3. 빌드 완료 → jar 파일 생성
4. 현재 WAS에서 실행중인 포트가 어떤 포트(blue)인지 확인
1. 그림내에선 8080 이라고 가정
5. 실행중이지 않은 포트(green) 지정
1. 그림내에선 8081 이라고 가정
6. green에 방금 빌드한 jar파일 실행
1. 젠킨스에서는 실행이 정상적으로 되는지 15초 간격으로 확인
7. 실행이 확인되면 nginx가 바라보는 포트를 green으로 변경해줌
8. blue 포트가 실행중인 PID 확인 후 프로세스 종료

자동화를 위한 스크립트 해석

쉘에 쓰이는 콘솔 문법들은 직관적이라 따로 설명은 안할거고 궁금한 사람은 추가적으로 찾아보면 좋을 것 같음.

Jenkins

blue_port = default_port, green_port=secondary_port 젠킨스 환경변수로 저장해뒀음

curl 쏴서 현재 올라가있는 포트 확인 후 반대 포트 변수로 설정

if curl -s "http://WAS:${blue_port}" > /dev/null
then
	deployment_target_port=$green_port
else
	deployment_target_port=$blue_port
fi

빌드 후 deployment_target_port에 jar파일 실행

cd 
scp -i 팸키.pem /var/lib/jenkins/workspace/ternoko/backend/build/libs/ternoko-0.0.1-SNAPSHOT.jar ubuntu@WAS:~
export TERM=xterm
ssh -i 팸키.pem -T ubuntu@WAS
ssh -i 팸키.pem ubuntu@WAS ./deploy.sh 

deploy.sh

WAS내에서 죽어있는 포트가 어디인지 확인하고 BLUE_PORT로 지정한뒤 Jar파일 실행

15초 간격으로 포트가 잘 올라갔는지 curl 쏴보면서 확인

잘됐는지 아닌지는 문구로 표시했음.

10번 시도했는데 안되면 Fail나면서 실패


for retry_count in $(seq 10)
do
  if curl -s "http://WAS:${deployment_target_port}" > /dev/null
  then
      echo "새로운 포트 ${deployment_target_port}로 잘 올라갔음"
			/// 여기서부턴 밑에서 따로 설명할 것
      ssh -o StrictHostKeyChecking=no -i key-ternoko.pem -T ubuntu@Nginx
		  ssh -o StrictHostKeyChecking=no -i key-ternoko.pem ubuntu@Nginx "echo 'set \$service_port ${deployment_target_port};' > /etc/nginx/conf.d/service-port.inc && sudo service nginx reload"
		  echo "Nginx가 바라보는 포트를 ${deployment_target_port}로 변경"
		    
		    if [ ${deployment_target_port} -eq default_port ]
		    then
		    	ssh -i key-ternoko.pem -T ubuntu@WAS
		  	ssh -i key-ternoko.pem ubuntu@WAS sudo kill -9 $(ssh -i key-ternoko.pem ubuntu@WAS sudo lsof -i:secondary_port -t) 2> /dev/null
		  else
		    	ssh -i key-ternoko.pem -T ubuntu@WAS
		  	ssh -i key-ternoko.pem ubuntu@WAS sudo kill -9 $(ssh -i key-ternoko.pem ubuntu@WAS sudo lsof -i:defualt_port -t) 2> /dev/null
		  fi
		  echo "구버전 포트 죽임"
		    break
		fi
		/// 여기까지 

  if [ $retry_count -eq 10 ]
  then
    echo "아직 새로운 버전 안올라감"
    exit 1
  fi

  echo "15초 후 재시도, 현재까지 $retry_count번 시도함"
  sleep 15
done

잘 올라온거 확인하면 Nginx 포트 deployment_target_port로 변경

echo "새로운 포트 ${deployment_target_port}로 잘 올라갔음"
ssh -i 팸키.pem -T ubuntu@Nginx
ssh -i 팸키.pem ubuntu@Nginx "echo 'set \$service_port ${deployment_target_port};' > /etc/nginx/conf.d/service-port.inc && sudo service nginx reload"
echo "Nginx가 바라보는 포트를 ${deployment_target_port}로 변경"

/etc/nginx/sites-available/ternoko.conf

엔진엑스 설정파일임. 여기서는 include로 파일을 부르고 proxy_pass에 파일 내의 변수를 박아주게끔 설정했다.

/etc/nginx/conf.d/service-port.inc

이건 포트번호 있는 파일. 임의로 고치면 nginx가 보는 포트가 바뀌게 되니까 젠킨스랑 WAS랑 싱크가 안맞을수도 있다.

WAS에 살아있는 deploy_target_port 의 반대포트 Kill

  if [ ${deployment_target_port} -eq defualt_port ]
     then
    	ssh -i 팸키.pem -T ubuntu@WAS
    	ssh -i 팸키.pem ubuntu@WAS sudo kill -9 $(ssh -i 팸키.pem ubuntu@WAS sudo lsof -i:secondary_port -t) 2> /dev/null
  else
    	ssh -i 팸키.pem -T ubuntu@WAS
  	ssh -i 팸키.pem ubuntu@WAS sudo kill -9 $(ssh -i 팸키.pem ubuntu@WAS sudo lsof -i:default_port -t) 2> /dev/null
  fi
  echo "구버전 포트 죽임"
    break

실행 결과



됐다ㅎㅅㅎ 실제 Jenkins 에서 출력되는 프린트문이다.

유의사항

도메인네임으로 접근시 어떤 포트인지 몰라도 되니까 아무 상관 없다.

어차피 도메인네임으로 접근하면 NginX가 알아서 포트맞춰 요청 보내준다.

포트로 접근할때는 sudo lsof-i:default_portsudo lsof-i:secondary_port 로 지금 올라가있는 포트가 어떤 포트인지 확인해야한다.

0개의 댓글