Server

무중단 배포 자동화

민철킹 2021. 9. 17. 14:34

안녕하세요 !! 😜

Nginx를 통한 Reverse Proxy에 이어 길고 길었던! 무중단 배포 자동화에 대해 이야기해보려합니다.

무중단 배포를 위해 작성한 쉘 스크립트에는 3가지가 있습니다.

  • deploy.sh
  • overwrite.sh
  • rollback.sh

본고에서는 먼저 무중단 배포가 무엇인지를 설명드리고 각각의 쉘 스크립트에 대해 설명드리는 순서로 진행하겠습니다.


무중단 배포

무중단 배포란 말 그대로 서버의 중단 없이 배포를 진행하는 것을 의미합니다.

저희는 Nginx를 사용한 Blue-Green Cycle을 통해 무중단 배포를 진행하였는데 평상시 저희 서버는 Nginx에 두 개의 포트를 연결하여 동작합니다.

이제부터 새로운 버전을 배포하는 곳을 Green, 구 버전을 Blue이라 지칭하겠습니다. 무중단 배포의 프로세스는 아래와 같습니다.

  • Nginx와 Green(8081)의 연결을 해제합니다.
    • 더 이상 트래픽은 Green로 가지 않게 됩니다.
  • 현재 Green에 클라이언트의 요청이 존재할 수 있으므로 Connection Pool의 Timeout 시간을 고려해 30초간 대기합니다.
  • Green의 프로세스를 종료합니다.
  • Green에 새로운 버전을 배포합니다.
  • Green을 Nginx와 연결하고, Blue를 Nginx와 연결해제합니다.

이것이 무중단 배포의 기본 프로세스입니다. 결론적으로 저희의 서버는 중단되지 않고 배포를 하게 되었습니다.

하지만 여기서 끝이 아닙니다. 기본 프로세스를 거친 후에 Nginx는 Green과만 연결되어 있습니다.

 Green은 신버전이기 때문에 검증된 버전이 아닙니다. 따라서 배포 이후 문제가 발생할 수도 있습니다. 만약 문제가 존재한다면 이전 버전으로 Rollback을 문제가 없다면 Blue(8080)에도 신버전을 배포하고 Nginx와 연결하여 배포 이전과 동일하게 Nginx와 두 개의 서버가 연결되어 부하를 줄이도록 해야합니다.

물론 이 과정도 중단되지 않고 수행되어야겠지요.

각설하고 이제 코드로 살펴보시죠!

deploy.sh

deploy.sh는 AWS CodeDeploy를 통해 자동으로 실행됩니다.

 

 

CURRENT_PID=$(ps -ef | grep 8081 | grep -v grep | awk '{print $2}')

먼저 8081 포트를 사용 중인 PID를 찾습니다.

 

 

sed -i "s/server 127.0.0.1:8081;/#server 127.0.0.1:8081;/g" $CONF_PATH

리눅스 sed 명령어를 통해 Reverse Proxy설정 파일을 수정하여 8081을 연결 해제합니다.

 

sudo systemctl reload nginx

Nginx에 변경사항을 반영합니다.

 

sleep 30 kill -9 $CURRENT_PID

Timeout시간을 고려해 30초를 대기하고 프로세스를 종료합니다.

 

chmod -x /home/ubuntu/app/build/libs/$JAR_NAME 
nohup java -jar -Dserver.port=8081 -Djasypt.encryptor.password="$JASYPT_PASSWORD" -Dspring.profiles.active=prod /home/ubuntu/app/build/libs/$JAR_NAME >> /dev/null &

권한을 변경하고 Green에 배포를 진행합니다.

 

sed -i "s/#server 127.0.0.1:8081;/server 127.0.0.1:8081;/g" $CONF_PATH 
sed -i "s/server 127.0.0.1:8080;/#server 127.0.0.1:8080;/g" $CONF_PATH 
sudo systemctl reload nginx

Green을 다시 연결하고 Blue를 연결해제한 후 변경사항을 반영합니다.


overwrite.sh

먼저 overwrite.sh는 신버전에 문제가 없음을 확인한 후에 Blue에도 신버전을 배포하는 역할을 합니다.

 

또한, 해당 버전의 jar를 다음 배포를 위해 백업해둡니다.

 

즉, 여기서 백업해둔 jar는 다음 배포 시 Rollback을 위해 사용될 수 있습니다.

 

overwrite.sh은 deploy.sh만 수행된 상태입니다.

이제 코드를 살펴보죠!

 

 

CURRENT_PID=$(ps -ef | grep 8080 | grep -v grep | awk '{print $2}') kill -9 $CURRENT_PID

먼저 8080에 실행 중인 PID를 확인하고 종료합니다.

 

chmod -x /home/ubuntu/app/build/libs/$JAR_NAME 
nohup java -jar -Djasypt.encryptor.password="$JASYPT_PASSWORD" -Dspring.profiles.active=prod /home/ubuntu/app/build/libs/$JAR_NAME >> /dev/null &

권한을 주고 8080에도 신버전을 배포를 진행합니다. 기본 포트가 8080이기 때문에 따로 port를 지정해주지 않았습니다.

 

sed -i "s/#server 127.0.0.1:8080;/server 127.0.0.1:8080;/g" $CONF_PATH 
sudo systemctl reload nginx

8080도 마찬가지로 Nginx와 재연결시켜주고 변경사항을 반영합니다.

이 또한 서버의 중단 없이 수행되었습니다.


rollback.sh

Rollback은 새로 배포한 신버전에 문제가 발견되어 이전 버전으로 되돌려야할 때를 뜻합니다. 이 때 overwrite.sh에서 백업된 이전 버전의 jar를 사용하게 되는데요.

 

사실 위의 코드와 매우 비슷하기 때문에 설명으로만 대신하겠습니다.

rollback.sh은 deploy.sh만 수행된 상태입니다.

또한, 8080이 Nginx와 연결이 해제되어있을 뿐, 이전 버전의 jar를 통해 서버는 띄워져 있는 상태입니다.

 

그럼 과정을 살펴보죠.

먼저, Blue와 Nginx를 재연결하고 Green과 Nginx를 연결해제한 후 변경사항을 반영합니다.

 

마찬가지로 30초를 대기한 후, Green의 프로세스를 종료합니다.

 

Green/8081에 이전 버전의 jar(백업된)를 배포합니다. 이 과정을 통해 Green이 아닌 Blue가 되겠죠?

이를 다시 Nginx와 재연결하고 변경사항을 반영하면 Rollback 또한 중단없이 수행됩니다.


마치며

저희는 이번 작업을 통해 무중단 배포의 자동화를 적용하게 되었습니다. 이를 통해 빠르고 안전한 CI/CD가 구축된 것 같습니다.

스스로 부족함을 많이 느끼면서 반대로 개발의 묘미, 프로젝트의 묘미를 다시 한번 체감합니다.

무중단 배포를 맡게되며 백엔드 개발자가 단순히 Spring과 JPA만 다루는 것이 아닌 CI/CD, 무중단 배포, 로드 밸런싱등에 대한 지식을 가져야한다고 느꼈습니다.

 

프로젝트의 Github 주소 : https://github.com/TEAM-ARK/sprout-backend

 

GitHub - TEAM-ARK/sprout-backend: Study community of developers.

Study community of developers. Contribute to TEAM-ARK/sprout-backend development by creating an account on GitHub.

github.com

 

반응형

'Server' 카테고리의 다른 글

Nginx를 통한 리버스 프록시  (0) 2021.09.17