배경
개발을 조금씩 해나가면서 docker의 소중함에 대해 정말 많이 느끼고 있습니다.. 이번 프로젝트 MSA 환경에서도 docker container를 통해 각 서버를 순서대로 띄우려고 했는데 잘 안됐단 말이죠. 구글링과 gpt를 통해 health check를 사용하면 된다는 것을 알아서 적용을 해보았지만 정상적으로 health 체크가 되지 않는지 자꾸 다음 서버가 제대로 띄워지지 않았습니다.. 튜터님이 actuator를 통해 health 체크를 하면 되지 않을까?라고 살짝 언급을 주셔서 그 부분에 이어서 내용을 시작해 보도록 하겠습니다.
내용
먼저 actuator를 활용하기 위해 spring boot의 eureka 서버에 gradle 설정을 해야합니다. spring boot 버전은 3.4.0, jdk는 17버전 기준입니다.
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
다음으로 yml 설정입니다.
spring:
application:
name: server
profiles:
active: dev
server:
port: 19090
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${host.url}:19090/eureka/
instance:
hostname: ${host.url}
management:
endpoints:
web:
exposure:
include: health, info
서버가 실행되고 나면 특정 엔트포인트로 요청을 보내 200응답을 보낼까라고도 생각했지만 튜터님의 말대로 actuator를 활용해 health를 보게 따로 엔드포인트를 만들지 않아도 될겁니다. heath는 up, down 형식으로 응답을 받게 됩니다.(up의 경우 200). 요청의 방법은 local의 경우 http://localhost:19090/actuator/health 이런식으로 접근하면 되고, container의 경우 서비스 이름을 localhost 부분에 적어주시면 됩니다.
다음으로 중요한 Dockerfile입니다.
# Base image
FROM openjdk:17-jdk-slim
# curl 설치
RUN apt-get update && apt-get install -y curl && apt-get clean
# Set the working directory
WORKDIR /app
# Copy the jar file
COPY build/libs/*SNAPSHOT.jar eureka-service.jar
# Expose the service port
EXPOSE 19090
# Run the application
ENTRYPOINT ["java", "-jar", "eureka-service.jar"]
다른 부분은 설정에 맞게 바꾸시면 되고, curl 설치를 제대로 해주셔야 합니다. 이 부분을 작성해두지 않으면 container가 실행된 후 curl 명령어를 사용할 수 없어 healthcheck가 불가능하게 됩니다...!
이 부분을 어떻게 알게 되었냐면, 분명 docker compose도 제대로 작성하고 eureka가 container에 정상적으로 띄워졌으며 http://localhost:19090/actuator/health를 들어가도 정상적으로 up으로 상태를 반환했단 말이죠.. 이상하다 싶어서 eureka 서버가 띄워진 docker container로 들어가 보았습니다.
직접 내부에서 요청을 보내보니 curl 명령어를 찾을 수 없다고 나오더군요. 물론 여기서는 localhost로 적은 부분도 잘못되긴 했지만, 기본적으로 curl 명령어를 찾을 수 없다는게 문제였습니다. 이 부분을 보고 나니 딱 느낌이 오더군요. curl 설치를 해줘야 하는구나! 그래서 위의 Dockerfile에 있는 curl 설치를 꼭 적어주셔야 한다는 겁니다.
다음으로 docker-compose 파일입니다.
version: '3.8'
services:
eureka-service:
build:
context: ./com.msa_delivery.eureka
dockerfile: Dockerfile
ports:
- "19090:19090"
networks:
- my-network
healthcheck:
test: ["CMD", "curl", "-f", "http://eureka-service:19090/actuator/health"]
interval: 10s
timeout: 5s
retries: 5
restart: always
gateway-service:
build:
context: ./com.msa_delivery.gateway
dockerfile: Dockerfile
ports:
- "19091:19091"
networks:
- my-network
depends_on:
eureka-service:
condition: service_healthy
restart: on-failure:5
networks:
my-network:
driver: bridge
위와 같이 eureka-service에 healthcheck부분에 명령어를 입력해주고 gateway-service에 depends_on에 eureka-service의 health를 사용하도록 해주면 eureka-service가 완전히 실행되고 healthcheck가 통과하면 gateway-service가 실행되게 됩니다...!!(local의 경우 healthcheck test부분에서 주소를 localhost로 바꿔주시면 되겠죠?)
container 로그입니다.
자 보이시나요? depends on만 사용했을 때는 단순히 실행 순서만 보장되고 중간중간 실행이 엉키면서 뒤죽박죽으로 보이게 됩니다.(docker desktop에서 확인 시) 즉, 하나의 서비스가 완전히 실행되고 다음 서비스가 실행되는걸 보장해주지 않죠. 하지만 위처럼 healthcheck를 활용해서 설정하게 된다면 하나의 서비스가 완전히 실행된 후 healthcheck가 정상이면 실행되게 할 수 있습니다. + 안정적인 서비스를 위해선 restart도 설정하면 되겠죠? ㅎㅎ
저는 spring app에 대해 관리를 했지만, healthcheck를 해야하는 db 서비스의 경우 따로 간단하게 체크 할 수 있는 명령어가 있는 db가 많으니 구글링을 해보시면 해결가능하실 겁니다.