1. 문제 상황
현재 스프링부트 프로젝트를 Dockerfile로 빌드한 후, 이를 ECR에 업로드하고 쿠버네티스 매니페스트를 통해 pod로 구성하는 작업을 진행중이었다.
auth-service는 Authorized된 토큰만 접근을 허용했기때문에, healthCheck하는 요청조차도 거부해서 pod가 Ready상태가 안되는 문제가 있었다.
근데 오류를 해결하고자 아무리 코드를 업데이트하고 ECR에 푸시 후 새로 pod를 구성해도 문제는 전혀 해결될 기미가 안보였다 ㅠㅠ
2. 문제 원인 분석 & 해결 방법
오류를 무한히 수정했는데도 똑같은 오류가 발생했었기 때문에, JwtFiller로 들어오는 로그를 직접 확인하고자 아래와 같은 로그를 출력하는 코드를 포함시켰다.
log.info("Request Path: {}, Is Public: {}", path,
PUBLIC_URLS.stream().anyMatch(pattern -> pathMatcher.match(pattern, path)));
하지만 여전히 출력되는 에러 내용은 동일했고, 내가 추가한 로그 [INFO]는 전혀 보이지 않았다.
따라서 코드의 문제가 아니라 '업데이트가 안되는건가?'를 의심했다.
기존 업데이트 방식
# 스프링부터 빌드 및 도커이미지 빌드
./gradlew build
dockerfile build -t <image> .
# ECR 로그인 및 docker 이미지 푸시
aws ecr get-login-password --region $AWS_REGION | \
docker login --username AWS --password-stdin <ECR URI>
docker tag <image>:latest <ECR URL>/<image>:latest
docker push <ECR URI>:latest
# 쿠버네티스 매니페스트로 pod 생성
kubectl apply -f manifest.yaml
문제점 1 - 동일한 'latest' 태그 사용
kubectl apply는 리소스 정의(Deployment spec)를 클러스터에 반영한다.
Deployment는 내부적으로 ReplicaSet을 관리하는데,
이때 .spec.template(Pod정의: 의미지, 환경변수, 라벨 등)이 바뀌면 새로운 ReplicaSet을 띄운다.
따라서 동일한 latest 이미지 태그를 사용한다면(= .spec.template이 동일하다면),
Deployment 입장에서는 "새로운 버전이 아니다"라고 판단하여 기존 ReplicaSet이 재사용되고 새 Pod를 생성하지 않는다.
따라서 아무리 에러를 고치고 새로 이미지를 ECR에 푸시했어도 이미지 태그가 동일했기에
Deployment는 기존의 Pod 데이터를 재활용하여 새 이미지를 사용하지 않을 수 있다.
ECR 레포지토리에서도, Latest 태그를 사용한 경우에는 Image Pull 이 전혀 기록되지 않았던 것을 확인할 수 있다.
(아무리 업데이트를 해도 문제 진전이 없었던 이유)
문제점 1의 해결 방법
-> "고유값(Date)" 값을 태그로 지정
이를 해결하기 위해, 이미지 태그를 latest가 아닌 date 값을 활용해
Deployment가 .spec.template이 변경되었음을 알 수 있도록 하였다.
초기에는 % 연산자를 통해 랜덤 생성된 고유값을 사용했지만,
이미지 태그값만 보고는 언제 생성된 이미지인지 알기 어려워 Date 값을 태그로 사용는 방식으로 변경하였다.
# 연월일-시분초 형태 (예: 20250909-153045)
TAG=$(date +%Y%m%d-%H%M%S)
docker build -t <service name>:${TAG} .
docker tag <service name>:${TAG} <ECR_URI>/<service name>:${TAG}
docker push <ECR_URI>/<service name>:${TAG}
문제점2 - 업데이트 시, 배포 중단 발생
기존 업데이트 방식은 delete deployment를 통해
Deployment 객체와 그 Deployment가 관리하는 ReplicaSet, Pod까지 모두 삭제했었다.
이 방식은 기존 리소스를 모두 삭제하고 새로 배포하기 때문에, "업데이트" 보다는 "재생성"에 가까웠다.
깔끔하게 지우는건 좋지만, 서비스가 잠시라도 끊길수밖에 없기 때문에 무중단 배포를 보장하지 않는다.
문제점 2의 해결 방법
-> Rolling Update 방식으로 배포
kubectl rollout restart deployment <deployment-namae> -n <namespace>
# 예시
kubectl rollout restart deployment auth-deployment -n production
3. 해결 완료
드디어 ㅠㅠ
~$ kubectl -n production get pods
NAME READY STATUS RESTARTS AGE
auth-deployment-8456bcc9f9-jqqzq 1/1 Running 0 3m3s