Information Security Study
240711 ~ 12 파이프라인으로 배포 고도화하기, 스크립트로 CI/CD 실습하기(롤백 트러블슈팅) 본문
240711 ~ 12 파이프라인으로 배포 고도화하기, 스크립트로 CI/CD 실습하기(롤백 트러블슈팅)
gayeon_ 2024. 7. 12. 16:44파이프라인으로 배포 고도화하기
이전에 작성한 코드를 리팩토링했다.
deploy 스테이지에는 호출구문만 남기고 나머지는 def로 pipeline 밖으로 빼 가독성을 높였다. (코드는 노션)
또 배포 결과를 출력할 수 있도록 애플리케이션 실행 확인용 코드를 추가했다.
배포 후 콘솔에 출력되는 문장이 존재하는지에 따라 정상적으로 실행되었는지 확인한다.
또한 jar 파일 실행 전 이미 실행 중이라면 해당 배포를 종료시키는 구문도 추가로 작성했다.
이 당시의 코드는 30초 sleep 후 배포하는 방식이었다.
하지만 빌드가 30초 이상이 걸리면 정상 실행 중이어도 실패로 이어지는 문제가 있기 때문에
더 효율적인 방법으로 수정했다.
while문과 maxAttemps = 50, checkInterval = 5로 변수를 생성하고 로그파일을 주기적으로 확인하는 로직을 최대 50번까지 확인할 수 있는 코드를 작성했다.
(5초에 한 번씩 체크, 최대 50번까지 체크 -> 50번을 모두 채우지 않아도 5초에 한 번씩 체크해서 배포가 완료되면 빠져나올 수 있다. 만일 50번 모두 체크했지만 배포가 되지 않았다면 실패로 간주한다.)
리팩토링 코드 수정(강의교안 버전)(노션참고)
스크립트로 CI/CD 실습하기
CI 지속적 통합
CD 지속적 전달, 배포
지금까지 작성한 스크립트에는 테스트 코드가 없었다.
대부분의 어플리케이션에는 테스트 코드가 있기 때문에 실습해봤다.
빌드 전에 테스트코드를 먼저 실행하고 통과했다면 빌드단계로 넘어가도록 한다.
stage('Test') {
steps {
script {
sh './gradlew test'
}
}
}
빌드 스테이지 전에 테스트 스테이지를 작성한다.
콘솔을 보면
빌드 성공이라고 뜨지만
실제로 빌드한 것이 아니라 테스트가 성공했다는 결과이다. (.jar 파일 생성 x)
하지만 아직까지는 애플리케이션 내부에 테스트 코드를 작성하지 않았기 때문에 당연히 성공이 뜬다.
pipeline 스테이지에도 작성하고 애플리케이션 내부에도 테스트 코드를 작성해야 한다.
테스트 코드에 실행 불가능한 코드를 작성하고 빌드를 하면
빌드가 들어가기 전에 테스트 단계에서 실패했다고 뜬다.
다시 이 에러를 발생시키는 코드를 지우고 다음 실습을 진행했다.
배포 발생 시 구버전으로 롤백하기
통합에는 성공했지만 배포에 실패하는 경우!
롤백 과정
1) 현재 실행중인 버전의 jar를 백업한다.
2) 신버전으로 배포를 시도한다.
3-1) 성공하면 신버전을 그대로 유지하지만
3-2) 실패하면 다시 백업된 jar로 서비스를 유지한다.
3-2) 배포 실패 시 실습 시나리오
신버전 배포 후 /hello 엔드포인트에 접속이 되지 않을 때
서버 자체를 의도적으로 마비시킬 수 없으니 /hello를 삭제하는 방법을 택하는 것이다.
먼저 애플리케이션의 /hello 엔드포인트를 주석처리한다.
파이프라인 스크립트에서는 배포 함수를 배포/테스트 함수로 수정하고
롤백 함수를 추가했다.
deployAndTest() 에서는 배포 후 curl 명령어로 웹 애플리케이션의 상태를 확인해 CD 테스트를 수행한다.
만약 CD 테스트에 실패하면 rollbackToPreviousVersion() 을 호출해 이전 버전으로 롤백한다.
rollbackToPreviousVersion()에서는 배포 중 문제가 발생했을 경우 이전에 백업한 jar 파일로 롤백을 수행한다.
먼저 이전 버전의 애플리케이션 프로세스를 종료하고
백업한 jar파일을 이전의 배포 경로로 이동시켜 애플리케이션을 롤백한다.
그리고 나서 이전 버전의 애플리케이션을 실행하고
정해진 시간 동안 정상적으로 시작되었는지 확인해 롤백 성공 여부를 판단한다.
+ 처음에 자꾸 상태코드가 000으로 출력되어서 왜 그런가~ 했더니
curl 접속 주소에 포트번호를 작성하지 않아서였다.
+ 포트번호 추가 후 콘솔에서 200으로 뜨지만 CD 테스트 수행 구문에서 자꾸 else문으로 가지 않고 롤백함수를 호출해서 cdTestResult를 출력하니 상태코드값이 아닌 명령어의 정상 종료 코드인 0을 가지고 있었다.
찾아보니 returnStatus: true 옵션이 종료 코드를 반환했기 때문이었다.
HTTP 응답 코드를 사용하려면 returnStdout: true를 사용하고 sh 명령 끝에 .trim()을 붙여야 한다.
trim()은 공백을 제거하는 함수이다.
이렇게 수정하니 정상적으로 동작했다.
1) hello 페이지가 삭제된 경우
빌드 후 콘솔을 보면
배포까지는 성공했지만
hello 페이지에 접속이 되지 않아 롤백을 수행한다는 로그를 볼 수 있다.
더 내리면 롤백이 성공적으로 수행되었다는 로그도 볼 수 있다.
2) hello 페이지가 정상적으로 존재하는 경우
배포 성공, CD 테스트에 통과해 롤백 함수를 호출하지 않는다.
+) 엔드포인트를 주석처리 후 엔드포인트에 접속하면 제대로 롤백이 되지 않고 화이트라벨이 뜨는 문제가 발생했다. 하지만 위와 같이 콘솔 로그에는 롤백이 잘 되었다고 출력되었고..
백업파일을 덮어씌우기 전 정상 애플리케이션을 실행했을 때 백업파일과 현재 빌드된 .jar 파일이 존재한다.
이때 java -jar 명령으로 각 .jar 파일을 실행 후 엔드포인트에 접속해봤다.
둘 다 접속이 잘 되는 것으로 보아 여기까지는 문제가 없다.
그 다음으로 파일 덮어씌우는게 안 되는 건가 싶어 백업파일을 원본 .jar 파일에 덮어씌울 때 잘 되는지를 확인했다.
로컬에서 mv 명령어를 쓰고 엔드포인트에 접속하면 백업버전 .jar 파일이 잘 실행되고 있다..
cp 명령이 문제인가 싶어 새 파일들을 만들어 테스트해봤는데 문제가 없었다.
대체 로컬에서는 잘 덮어씌워지는데 왜 젠킨스 파이프라인에서는 안되나 다시 스크립트를 확인했는데...
백업파일 생성하는 구문에서 문제가 있었다.
현재 백업파일 생성 로직은 지금 빌드된 .jar 파일을 그대로 복사해둬서 제대로 저장은 되지만
문제는!!!! 이렇기 때문에 이후에 오류 애플리케이션을 빌드했을 때도 오류본 .jar 파일을 백업파일로 저장하게 된다는 것이었다..
의도는 정상 파일을 백업파일로 사용하려 했으나 어차피 빌드할 때마다 백업파일도 현재 빌드한 .jar파일로 갱신되어서 당연히 롤백이 되지 않았던 것이다..
애초에 아래와 같이 잘못된 구문을 사용해서 backupJarFile이 이전 버전을 저장하고 있지 않았다는 점이다..
// 기존 JAR 파일 백업
sh script: "ssh -o StrictHostKeyChecking=no ubuntu@$targetServerIp 'cp $deployPath/파일명.jar $deployPath/$backupJarFile'", returnStatus: true
그래서 우선 롤백이 되는지 실습을 해야 하니 아래와 같이 백업파일이 없는 경우에만 백업파일을 생성하도록 수정했다.
// 백업 파일 생성
def checkBackupCmd = "ssh -o StrictHostKeyChecking=no ubuntu@$targetServerIp '[ ! -f $deployPath/$backupJarFile ]'"
드디어.. 롤백이 되었다..
롤백 가능한 최종 코드 (노션)
'네트워크 캠퍼스 > NHN클라우드-Jenkins' 카테고리의 다른 글
크론탭으로 로깅 스크립트 실행하기 (0) | 2024.07.23 |
---|---|
젠킨스 파이프라인에서 .sh 실행하기 (0) | 2024.07.23 |
240710 젠킨스 파이프라인 사용하기 (0) | 2024.07.10 |
240709 도커 이미지 배포로 전환하기 (0) | 2024.07.09 |
240702 webhooks로 자동 배포하기(이어서), 아틸러리로 스트레스 테스트하기, Nginx로 무중단배포 스크립트 작성하기 (0) | 2024.07.02 |