개요
24년 2월에 처음 오픈하여 운영하기 시작한 Dayner 커피 사이트 운영 중 발생한 접속 장애 및 최근 도입한 캐시 메커니즘의 성능 분석 필요성을 느껴서 도입하게 되었습니다. AWS 내부에서도 Cloud Watch 로 지원을 해주고 있지만 캐시히트율이나 JVM 내부에 대한 분석은 지원해주지 않기 때문에 AWS EC2 상의 스프링 애플리케이션을 로컬 환경에서 Grafana를 통해 모니터링하기로 결정했습니다.
이틀간 테스트 해본결과 로컬에서 계속 가동하여도 큰 문제는 없었으나 추후에 안쓰는 라즈베리파이나 무료 ec2 에 올려놔도 좋을것 같습니다ㅎㅎ
준비
1. AWS EC2 인스턴스에서 실행 중인 스프링 부트 애플리케이션+promethus 엔드포인트 활성화
2. Docker (Promethus, Grafana)
3. 로컬 - Ec2 포워딩
4. 연결 및 캐시히트율 설정
Actuator?
스프링 부트 애플리케이션에 내장된 기능으로, 다양한 애플리케이션 정보를 HTTP 엔드포인트를 통해 제공한다.
- 애플리케이션 상태 -healty check 가능
- 컨텍스트 빈 목록
- JVM 상태 -메모리 사용 상태 추적 가능
- HTTP 요청 및 응답 추적 정보
Prometheus?
프로메테우스는 오픈 소스 모니터링 시스템으로, 다양한 데이터 소스에서 시계열 데이터를 수집, 저장 및 쿼리할 수 있다.
따라서 위의 엑츄에이터는 프로메테우스와 쉽게 통합되어 애플리케이션 메트릭을 프로메테우스에 노출할 수 있다.
함께 사용하는 이점
- 엑츄에이터는 애플리케이션 내부 정보를 제공하고, 프로메테우스는 다양한 데이터 소스의 메트릭을 통합하여 애플리케이션 전체의 상태 및 성능을 파악할 수 있다.
- 프로메테우스는 PromQL이라는 강력한 쿼리 언어를 제공하여 원하는 메트릭 데이터를 추출하고 분석할 수 있다.
- 프로메테우스는 메트릭 기반 알림을 설정하여 특정 조건 충족 시 어드민에게 알릴 수 있다.
Grafana?
엑츄에이터와 프로메테우스에서 수집된 데이터를 시각화한다.
- 그래프, 차트, 테이블 등 다양한 시각화 옵션
- 여러 시각화 요소를 조합하여 맞춤형 대시보드를 생성
따라서 우리는 Springboot 애플리케이션에서
1. Actuator를 사용하여 애플리케이션의 내부 상태와 메트릭 데이터를 특정 엔드포인트로 노출하고
2. Prometheus가 데이터 수집을 한 후에
3. Grafana 로 수집된 데이터를 시각화 해보겠습니다.
스프링 promethus 엔드포인트 활성화
스프링의 build. gradle 파일에 actuator 와 promethus 를 임포트 합니다.
추가적으로 노출할 metric 이나 포트 등 설정을 해주어야하는데 보안상 프로젝트가 실행되는 포트(8080)에 deploy 하거나 default 값인 url (/actuator/prometheus)로 설정을 하면 공격 당하기 쉽기 때문에 적절히 바꿔주는게 좋습니다.
(추천) 코드를 업데이트 하여 먼저 로컬에서 실행을 시켜서 localhost:{ 포트 }/{ 원하는 url } 로 접속하여 정보가 보여지는지 확인합니다.
위와 같은 화면이 보이면 OK
현재 진행 사항은 아래와 같다.
이후에 Ec2 에도 코드를 업데이트 해줍니다.
이후로는 프로젝트가 Deploy 되어있는 구조에 따라서 접근 방식이 달라집니다. 예를 들어, 단순히 Spring 애플리케이션을 EC2에 배포하고 AWS가 제공하는 엔드포인트를 통해 접근하는 경우, 동일한 방식으로 Prometheus에 접근할 수 있습니다. 그러나 제 경우에는 아래와 같은 인프라 구조로 배포중에 있기에
도메인을 통한 접속을 위해 CloudFront를 사용하고 있지만, Prometheus의 포트를 CloudFront에서 직접 열어 접근하는 방식은 보안상 적절하지 않다고 판단했습니다. 이외에도 모니터링 데이터를 수집하는 시스템은 집에 계속 있기에 딱히 인터넷으로의 접근을 원치 않아서 이런 구조로 만들어봤습니다.
따라서 기존의 SH 포워딩을 사용하여 EC2 인스턴스 상의 Prometheus 포트와 로컬 시스템의 Prometheus 와 Grafana 로 모니터링 할 계획입니다.
Docker 로 Prometheus , Grafana 말아주기
Prometheus.yml 설정파일을 따로 만들어주었다.
아래 공식문서를 참고했다.
- Global 설정
- scrape_interval: 15s: Prometheus가 메트릭을 수집하는 간격
- Scrape 설정
- prometheus 메트릭을 수집
- 타겟으로 localhost:{ 포트} 을 지정하여 Prometheus 자체 모니터링을 한다.
- 이후에 grafana를 외부 pc에 올렸을때 prometheus 의 상태를 확인 하기 위함이나 지금 다시 생각해보니 쿠버네티스에서 관리해버리면 굳이 필요없을것 같다ㅎㅎ
- spring-actuator 스프링 애플리케이션의 메트릭을 수집
- metrics_path는 스프링 actuator 가 메트릭을 노출하는 경로
- scrape_interval은 job의 메트릭 수집 간격, 나중에 조금 늘릴 생각이다. 30s~1m 정도
- targets host.docker.internal:{ ssh로 포워딩 한 포트 }을 지정
(Docker 컨테이너가 호스트 시스템의 서비스에 접근할 때 사용하는 DNS 이름) 아래 공식 문서 참고
- prometheus 메트릭을 수집
Docker-compose.yml Prometheus와 Grafana를 Docker 컨테이너로 실행하기 위한 설정을 하였다.
이 또한 문서에 친절히 나와있다. 여담으로 이번엔 기술블로그를 보지 않고 이렇게 구현하면 되지 않을까? 구조를 예상하고 메뉴얼로만 만들었는데 뚝딱 되서 쾌감이 좀 있었다 ㅎㅎ
- Prometheus
- image: prom/prometheus: Prometheus 공식 Docker 이미지
- ports: - " ----:9090": 호스트의 포트를 컨테이너의 9090 포트에 바인딩
- volumes: Prometheus 데이터를 저장할 볼륨을 마운트
- command: 현재 디렉토리의 prometheus.yml 파일(아까 만든거)을 컨테이너의 /etc/prometheus/prometheus.yml에 마운트하여 Prometheus 설정을 제공, Prometheus 실행 시 사용할 명령어를 미리 지정
- networks: 서비스가 monitoring-network라는 Docker 브리지 네트워크에 연결되도록 설정
- Grafana
- image: grafana/grafana: Grafana 공식 Docker 이미지를 사용합니다.
- ports: - "3030:3000": 호스트의 3030 포트를 컨테이너의 3000 포트에 바인딩
- volumes: - grafana-data:/var/lib/grafana: Grafana 데이터를 저장할 볼륨을 /var/lib/grafana에 마운트
- environment: Grafana의 관리자 패스워드와 사용자 가입 허용 여부(로컬에서 사용하기에 문제없다)
- networks: - Docker 브리지 네트워크에 연결되도록 설정
- 네트워크 및 볼륨 설정:
- monitoring-network: 서비스 간 통신을 위한 사용자 정의 Docker 네트워크입니다.
- grafana-data: Grafana 데이터를 저장하기 위한 볼륨
전체 인프라 스트럭쳐를 그려보면 아래와 같다.
로컬 특정 포트로 SSH 이용하여 포워딩
ssh -L { 포워딩 하고싶은 로컬 대상 포트} :localhost:{ 스프링 actuator 포트} user@your-ec2-public-dns
이렇게 매번 명령어를 입력해도 좋지만 난 .ssh 내의 config 파일에 또 다른 호스트를 추가해주었다.
또 공식문서 참조
로컬 포워드 옵션을 이용해 [ 로컬 대상 포트 : localhost:EC2 인스턴스의 포트 ] 해주면 된다.
이후에 ssh (호스트명)으로 ssh 접속을 한 후에 localhost:로컬 대상 포트 로 접근을 하면 Ec2 에 올라와있는 스프링 부트의 actuator 가 뿌려주는 메트릭들을 받을수 있는걸 확인할 수있다.
Grafana 에 Prometheus 연결
이후에 deploy 한 Grafana의 로컬 포트로 접속하면 Grafana 에 접속이 가능하다.
좌측에 DataSource
우상단에 Add new db
우린 Prometheus 로 했으니 Prometheus 를 선택한다.
이후에는 아래와 같은 설정 창이 나오는데 Connection 항목에 위에서 메트릭을 확인했다고 해당 url 을 신나게 적으면 안된다 ㅎㅎ
해당 url 에서 메트릭을 수집하는 Prometheus 의 위치로 작성을 해주어야하는데
docker inspect 명령어로 직접 IP 를 찾아서 포트와 함께 입력해두어도 좋고 docker 생성시에 프로필 명으로 사용했던 prometheus 를 그대로 사용해도 무방하다
이후에 Save & Test 로 연결이 되나 확인해보자
아래 화면이 나오면 정상적으로 연결이 완료되었다.
글이 길어져서 캐시 히트율이나 오픈라이브러리에 사람들이 만들어놓은 대시보드를 이용해서 손쉽게 모니터링 하는 법을 간략하게 작성하겠다.