애니프렌즈 프로젝트에는 AOP와 로그백을 이용해서 클라이언트 요청과 예외를 로깅하고 로그 레벨 별로 파일을 출력하도록 설정하였습니다.
개발 환경에서 클라이언트와 통신하면서 발생하는 문제를 좀 더 쉽게 파악할 수 있을 것이라고 기대했지만 여전히 문제가 되는 부분이 있었습니다. 다음과 같이 로그 파일을 확인하기 위해서는 몇 번의 단계를 거쳐야 했는데 이것이 쌓이면서 피로감이 점점 커져갔습니다.
1. 문제 발생
2. ec2 연결
3. 로그 파일 출력 경로 이동
4. 레벨 별 로그 파일 확인
터미널을 통해 로그를 확인하는 것도 쉬운 일이 아니었습니다. 적어도 지금보다 더 쉽게 로그를 확인 할 수 있는 방법이 필요했습니다.
Loki
Loki는 Grafana에서 만들어진 로그 수집 시스템입니다. Prometheus가 애플리케이션의 메트릭을 수집하는 것과 유사하지만 로그를 수집한다는 점에서 다릅니다.
로키를 이용한 로깅 스택은 다음 3가지 요소로 구성되어 있습니다.
promtail
은 로그를 수집하고 Loki에 전송하는 역할을 담당하는 agent입니다.loki
는 로그 저장 및 쿼리 처리를 담당하는 main server입니다.grafana
는 쿼리를 처리하고 로그를 보여줍니다.
애플리케이션이 배포되어 있는 각각의 로컬 머신에는 프롬테일 에이전트가 존재합니다. 프롬테일의 설정 파일에 출력되는 로그 파일의 위치를 명시하면 이를 수집하여 로키 서버로 push합니다. 그라파나는 로키 서버를 데이터 소스로 하여 수집한 로그를 시각화합니다.
다음의 그림은 프로젝트에 적용한 모니터링 환경입니다. 이를 예로 들면 프로덕션(메인) 서버의 애플리케이션에서 출력된 로그를 프롬테일이 수집하여 모니터링(데브) 서버의 로키 서버에 push 하고 있습니다. 데브 서버 역시 애플리케이션에서 출력된 로그 파일을 로키에 push 합니다.
그럼 로키 서버를 데이터 소스로 하여 nginx, 애플리케이션, 혹은 수집한 다른 로그 파일들을 시각화 할 수 있습니다.
로키, 프롬테일 설정
저는 프롬테일, 로키, 그라파나 모두 로컬로 설치를 진행할 것입니다. 도커나 쿠버네티스를 이용한 다른 방법은 공식 깃허브 또는 공식 문서를 통해 확인하실 수 있습니다.
# 로키, 프롬테일 설정 파일 다운로드
wget https://raw.githubusercontent.com/grafana/loki/main/cmd/loki/loki-local-config.yaml
wget https://raw.githubusercontent.com/grafana/loki/main/clients/cmd/promtail/promtail-local-config.yaml
# 로키 실행 파일 다운로드
wget https://github.com/grafana/loki/releases/download/v2.8.6/loki-linux-amd64.zip
unzip loki-linux-amd64.zip
chmod a+x loki-linux-amd64
# 프롬테일 실행 파일 다운로드
wget https://github.com/grafana/loki/releases/download/v2.8.6/promtail-linux-amd64.zip
unzip promtail-linux-amd64.zip
chmod a+x promtail-linux-amd64
프롬테일 에이전트가 로그 파일을 수집하고 로키 서버로 push 할 수 있도록 설정 파일을 수정합니다. 저는 애플리케이션의 로그와 nginx의 로그를 수집하고 싶습니다.
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://{로키 서버 주소}:{로키 서버 포트}/loki/api/v1/push
scrape_configs:
- job_name: application
static_configs:
- targets:
- localhost
labels:
job: application_dev
__path__: {애플리케이션 로그 파일 출력 경로}/*log
- job_name: nginx
static_configs:
- targets:
- localhost
labels:
job: nginx_dev
__path__: {nginx 로그 파일 출력 경로}/*log
프롬테일, 로키 실행 파일을 편하게 다루기 위해 systemd 서비스 파일로 등록해줍니다.
cd /etc/systemd/system
sudo vi promtail.service
[Unit]
Description=Promtail service
After=netowrk.target
[Service]
ExecStart={프롬테일 실행파일 경로}/promtail-linux-amd64 -config.file {프롬테일 설정 파일 경로}/promtail-local-config.yaml
Restart=always
[Install]
WantedBy=default.target
sudo vi loki.service
[Unit]
Description=Loki service
After=netowrk.target
[Service]
ExecStart={로키 실행파일 경로}/loki-linux-amd64 -config.file {로키 설정 파일 경로}/loki-local-config.yaml
Restart=always
[Install]
WantedBy=default.target
서비스 파일 저장까지 완료했으면 다음 명령으로 프롬테일 에이전트와 로키 서버를 가동합니다.
sudo systemctl start promtail
sudo systemctl start loki
만일 프롬테일과 로키가 정상적으로 가동되었다면 각각 {서버 IP}:9080
, {서버 IP}:3100
으로 접속 시 다음과 같은 화면을 확인할 수 있습니다.
그라파나 시각화
그라나파나에 접속하여 로키 서버를 데이터소스로 등록합니다.
이제 등록한 데이터 소스를 이용하여 원하는 패널을 선택적으로 추가할 수 있습니다. 새로운 New dashboard → Add visualization → Loki datasource 를 선택합니다.
로키 서버가 프롬테일이 보내준 로그 파일을 정상적으로 수집하고 있다면 Label filters를 통해서 원하는 로그 파일을 선택할 수 있습니다. Line contains와 같은 속성들을 지정하여 보고 싶은 로그를 선택하는 것도 가능합니다.
저의 경우는 Debug 레벨의 로그에서 [Request]
라는 문자열이 포함된 로그만 확인하고 싶습니다. Run query
버튼을 눌러 원하는대로 작동하는 것을 확인했다면 Apply
버튼으로 통해 패널을 적용합니다.
이렇게 애플리케이션, nginx, 필터 설정까지 완료하면 다음과 같은 모니터링이 완성됩니다.
로그 파일을 모아서 볼 뿐인 간단한 모니터링이지만 ec2에 연결할 필요 없이 익숙한 웹 환경을 통해 쉽고 빠르게 로그를 확인할 수 있습니다.
설정 중 발생했던 이슈
1. ec2 간 통신 허용하기
프롬테일 에이전트가 로키 서버로 로그 파일을 push 하지 못하는 상황을 마주하였습니다.
journalctl -u promtail
이는 ec2 보안 그룹의 인바운드 규칙을 적절하게 설정하지 않아 발생한 문제였습니다. 보안 그룹의 인바운드 규칙에 로키 서버로 향하는 통신을 허용하니 정상적으로 해결되었습니다.
2. 도커 권한 문제(permission denied)
개발 서버의 경우 도커 컴포즈를 이용하고 있습니다. 로그 파일 출력을 위해 바인트 마운트 설정을 해주었으나 지속적으로 파일 출력이 불가하다는 에러 메시지가 출력되었습니다. 원인은 도커 컴포즈로 디렉터리가 생성되는 과정에서 root 권한의 디렉터리가 생성되었기 때문이었습니다.
다음 명령을 통해 디렉터리 접근 권한을 ec2-user로 변경해주었습니다. 이후 정상적으로 로그가 출력되는 것을 확인할 수 있었습니다.
chown ec2-user:ec2-user logs
참고
서로 다른 EC2 인스턴스간에 연결하기 (feat. Ping)
Grafana, Loki, Promtail 을 이용한 로그 모니터링 및 알림 시스템
Loki: like Prometheus, but for logs.
'백엔드' 카테고리의 다른 글
프로젝션, 인덱스로 조회 성능 개선하기(feat.ngrinder) (0) | 2023.12.16 |
---|---|
낙관적 락, 데드락, 비관적 락 (1) | 2023.12.10 |
존재하지 않는 객체와 협력하기 (1) | 2023.11.20 |
AWS CodeDeploy를 이용한 배포 성공 이후 발생하는 permission denied (0) | 2023.11.07 |
Parameter와 Argument (0) | 2023.06.20 |