오늘은 HealthCheck가 뭔지 왜하는지에 대해서 적어보려고해요
이전 프로젝트에서 Docker + GitHub Action을 사용해서 무중단 CICD를 구축했었는데 구축 당시 HealthCheck라는 단계를 거쳤습니다. 그 당시에는 구현이 가장 급했기 때문에 코드 하나하나가 어떤 의미로 사용되는지 몰랐는데 문득 이걸 왜하지? 라는 생각이 들었습니다.
그전에.. 왜 무중단 CICD를 구축했는지, 그리고 대략적인 툴 사용 이유와 개념 가볍게 짚고 넘어갈께요
무중단 CICD(Blue Green) 구축이유
- 이전 프로젝트에서 수작업으로 배포를 진행을 했습니다. 그렇다 보니 코드의 수정이 생길 때마다 SSH을 통해 서버를 닫고 열어야했는데, 너무 잦은 수정으로 인해 배포 과정에서 시간을 너무 잡아먹드라구요
- 그래서 CICD를 구축해야겠다고 생각을 하게 되었고, 현재 하고 있는 프로젝트는 실제 유저가 들어오게 될 예정이다보니 무중단 CICD를 더욱이나 도입해야겠다고 생각했습니다!
배포 전략(Blue Green)
- 실행중인 8080포트에 연결이 되어있었습니다.
- 수정이 완료되어 다시 배포해야하는 상황에서, 8081포트를 생성합니다.
- 홀라당~ 수정이 완료된 서버인 8081 포트로 교체합니다.
- 그리고 기존의 8080포트의 서버를 제거합니다.
Docker + GitHub Action을 썼던이유
- Docker를 쓴 이유
- 사실 큰 이유는 없었는데요 저에게 가장 친숙했던 컨테이너 관리 툴이라서 선택했습니다! 근데 사실 쿠버네티스 쓸걸 좀 후회중…(추후 바꿀 수도 있음) 이유
- GitHub Action을 쓴 이유
- GitHub로 협업을 하다보니 좀더 편하게? 설정을 하고 싶어서 사용하게 되었답니다
쿠버네티스랑 Docker의 차이
쿠버네티스는 컨테이너 런타임을 통해 컨테이너를 다루는 도구를 말해요. 쿠버네티스가 해 주는 일은 여러 서버(노드)에 컨테이너를 분산해서 배치하거나, 문제가 생긴 컨테이너를 교체하거나, 컨테이너가 사용할 비밀번호나 환경 설정을 관리하고 주입해 주는 일 등입니다. 이것을 컨테이너 오케스트레이션이라고 하죠.
Q. 쿠버네티스가 컨테이너를 다루는 도구라면 도커를 다루는 도구는 아니란 말이네요?
A. 네 앞에서 언급했듯이, 쿠버네티스의 역할은 컨테이너를 분산 배치, 상태 관리 및 컨테이너의 구동 환경까지 관리해 주는 도구이고, 도커는 컨테이너를 다루는 도구(컨테이너 런타임) 중 하나입니다. 쿠버네티스는 컨테이너를 다루기 위해 도커 이외에도 다양한 컨테이너 런타임 소프트웨어를 사용할 수 있습니다.
네~.. 그렇다고 합니다. 저는 여태 잘 모르고 있다가 최근에야 알게 되었어요.
쿠버네티스로 바꿀까 고민했던 이유는 “컨테이너 오케스트레이션”이 필요하다고 생각했기 때문입니다.!
최근에 서버가 닫힌 상황이 생겼는데, 모르고 계속 있었던 일이 있었는데요, 원인을 찾으려고 하는데 3일이나 걸렸던……ㅠㅠ 근데 쿠버네티스를 썼다면 계속 healthcheck를 하고 서버가 문제가 생겼으면 다른 컨테이너로 교체를 했을텐데.. 그러면… 조급하지 않았을 텐데… 라고 생각했답니다…
자! 이제 HealthCheck가 뭔지 왜하는지
HealthCheck가 뭔지
쉽게 말해 “서버의 상태를 확인하여 서버의 작동 유무를 확인하는것” 입니다.
최근 클라우드 공부 중에 Load Balancer에 대해 공부하다가 Health Check이야기 한번더 나왔는데, 언제 쓰이는지 토스 기술 아티클 하나 남겨두고 갈께요.
추후에 여러 서버 관리 + 대용량 데이터 + 여러가지 장애 상황이 생기기 전에 더 잘 알아놔야겠다는 생각이 들었습니다.
CICD에서 어디에서 Health Check가 이루어 지는지
요로코롬 실제 deploy.sh 에서 작동중인 우리 healthcheck양…
#!/bin/bash
nginx_config_path="/etc/nginx"
all_port=("8080" "8081")
available_port=()
server_name=우리 서버이름
docker_ps_output=$(docker ps | grep $server_name)
running_container_name=$(echo "$docker_ps_output" | awk '{print $NF}')
blue_port=$(echo "$running_container_name" | awk -F'-' '{print $NF}')
web_health_check_url=/actuator/health
if [ -z "$blue_port" ]; then
echo "> 실행 중인 서버의 포트: 없음"
else
echo "> 실행 중인 서버의 포트: $blue_port"
fi
# 실행 가능한 포트 확인 ( all_port 중 blue_port를 제외한 port )
for item in "${all_port[@]}"; do
if [ "$item" != "$blue_port" ]; then
available_port+=("$item")
fi
done
# 실행 가능한 포트 없으면 끝내기
if [ ${#available_port[@]} -eq 0 ]; then
echo "> 실행 가능한 포트가 없습니다."
exit 1
fi
green_port=${available_port[0]}
echo "----------------------------------------------------------------------"
# docker image pull
echo "> 도커 이미지 pull 받기"
docker pull 우리 서버이름/${server_name}
# green_port로 서버 실행
echo "> ${green_port} 포트로 서버 실행"
echo "> docker run -d --name ${server_name}-${green_port} -p ${green_port}:8080 -e TZ=Asia/Seoul 우리 서버이름/${server_name}"
docker run -d --name ${server_name}-${green_port} -p ${green_port}:8080 -e TZ=Asia/Seoul 우리 서버이름/${server_name}
echo "----------------------------------------------------------------------"
# green_port 서버 제대로 실행 중인지 확인
sleep 10
for retry_count in {1..10}
do
echo "> 서버 상태 체크"
echo "> curl -s http://localhost:${green_port}${web_health_check_url}"
# http://localhost:{그린포트}{health check 주소} -> nginx
response=$(curl -s http://localhost:${green_port}${web_health_check_url})
up_count=$(echo $response | grep 'UP' | wc -l)
if [ $up_count -ge 1 ]
then
echo "> 서버 실행 성공"
break
else
echo "> 아직 서버 실행 안됨"
echo "> 응답 결과: ${response}"
fi
if [ $retry_count -eq 10 ]
then
echo "> 서버 실행 실패"
docker rm -f ${server_name}-${green_port}
exit 1
fi
sleep 2
done
echo "----------------------------------------------------------------------"
# nginx switching
echo "> nginx 포트 스위칭"
echo "set \$service_url http://127.0.0.1:${green_port};" | sudo tee ${nginx_config_path}/conf.d/service-url.inc
sudo nginx -s reload
sleep 1
echo "----------------------------------------------------------------------"
# nginx를 통해서 서버 접근 가능한지 확인
response=$(curl -s http://localhost${web_health_check_url})
up_count=$(echo $response | grep 'UP' | wc -l)
if [ $up_count -ge 1 ]
then
echo "> 서버 변경 성공"
else
echo "> 서버 변경 실패"
echo "> 서버 응답 결과: ${response}"
exit 1
fi
# blue_port 서버 있다면 중단
if [ -n "$blue_port" ]; then
echo "> 기존 ${blue_port}포트 서버 중단"
echo "> docker rm -f ${server_name}-${blue_port}"
sudo docker rm -f ${server_name}-${blue_port}
fi
다시 한번 Blue Green CICD에 대해 이야기 해보자면
- 실행중인 컨테이너를 확인하고
- 실행가능한 포트가 있는지 확인(8080을 쓰고 있었다면 8081 사용 가능한지 체크)
- 8080을 쓰고 있었기 때문에 8081포트로 이미지를 내려받고 컨테이너를 실행합니다.
- 새로 실행시킨 8081컨테이너가 제대로 작동되는지 확인
- 제대로 작동하면 8080 → 8081로 스위치!
- 8080 삭제
여기서 HealthCheck는 4번째 단계에서 이루어 집니다.
HealthCheck 왜 하는건지
결론은 우리가 배포할 서버가 지금 정상 상태인지 확인하기 위해 사용했습니다.
지금은 배포 단계에서만 사용했기에 간단하게만 알아봤는데, 토스 기술 아티클을 보니까 healthcheck가 성공(200)이 되었는지 동작원리를 세세하게 더 알아볼 필요가 있다는것을 알게 되었네요…
Reference
https://kimjingo.tistory.com/74
https://mr-popo.tistory.com/230
https://www.samsungsds.com/kr/insights/220222_kubernetes1.html
https://toss.tech/article/how-to-work-health-check-in-spring-boot-actuator
'Back-end > Spring' 카테고리의 다른 글
[Spring] File과 JSON 데이터를 multipart/form-data로 받아오는 방법 (9) | 2024.01.19 |
---|---|
[Spring] JPA 활용2 - 지연로딩과 조회 성능 최적화 (0) | 2022.07.25 |
[Spring] JPA 활용2 - 준비 (0) | 2022.07.25 |
[Spring] JPA 활용2 - API 개발 기본 (0) | 2022.07.25 |
[Spring] 빈 생명주기 콜백 (0) | 2021.10.05 |
댓글