본문 바로가기

데이터베이스/ELK

Elastic APM을 이용한 Django 모니터링 연동

0. 들어가며

프로젝트에서 이벤트 로깅만 남기는 것이 아니라 시스템 로깅 (트랜잭션, CPU 부하 등등..)도 시각화할 수 있도록 APM을 도입을 권하기 위해 테스트용으로 연동이 잘되는지, 서버가 정상적으로 띄어지는지 확인하기 위해 구현하였다.

실제로 Elastic APM 보다 유료 APM이 더 인기 많고 많은 기업에서 사용하지만, Elastic Stack을 이미 사용하고 있다면 Elastic APM을 사용하는 것도 좋다.

먼저 알아둬야 할 것은...
도커를 이용해서 APM-Server를 띄울 것이다. APM 서버가 돌아가야 Kibana에서 APM을 사용할 수 있다.
그 다음엔 웹 어플리케이션(python, java ...)에서 APM-Server을 연동할 수 있도록 APM-Agent 설정을 해줘야 한다.

 

 

1. Elastic Stack Docker (APM-Server)

ELK를 띄우기 위한 Docker 세팅은 컴포즈 파일만 올리고 생략하겠음,,,,

 

(1) docker-compose.yml

version: '3'

services:
  elasticsearch:
    restart: unless-stopped
    build: ./elasticsearch
    container_name: elasticsearch
    volumes:
      - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro,z
      - ./elasticsearch/data:/usr/share/elasticsearch/data
    environment:
      - TZ=Asia/Seoul
      - ELASTIC_PASSWORD=elasticpassword
      - node.name=elasticsearch ## 이 이름에 큰 의미 없음, 왜냐하면 싱글노드로 운영할 계획이기 때문에
      - bootstrap.memory_lock=true
      - discovery.type=single-node ## 단일노드모드로 사용하겠다는 뜻, 엘라스틱서치는 실제로는 멀티노드로 많이 사용한다.
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    ports:
      - "9200:9200"
    networks:
      - elastic

  kibana:
    restart: unless-stopped
    build: ./kibana
    container_name: kibana
    volumes:
      - ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml:ro,z
    ports:
      - "5601:5601" ## 키바나의 기본포트는 5601 이다.
    depends_on:
      - elasticsearch
    networks:
      - elastic

  logstash:
    restart: unless-stopped
    build: ./logstash
    container_name: logstash
    volumes:
      - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro,z
      - ./logstash/pipeline:/usr/share/logstash/pipeline:ro,z
    environment:
      - "LS_JAVA_OPTS=-Xmx256m -Xms256m"
    ports:
      - "5044:5044"
    depends_on:
      - elasticsearch
    networks:
      - elastic

  apm-server:
    restart: unless-stopped
    image: docker.elastic.co/apm/apm-server:7.16.3
    container_name: apm-server
    cap_add: [ "CHOWN", "DAC_OVERRIDE", "SETGID", "SETUID" ]
    cap_drop: [ "ALL" ]
    volumes:
      - ./apm-server/config/apm-server.yml:/usr/share/apm-server/apm-server.yml:ro,z
    ports:
      - "8200:8200"
    depends_on:
      - elasticsearch
      - kibana
    networks:
      - elastic


networks:
  elastic:

ELK와 함께 docker-compose.yml 파일에 apm-server 서버를 8200포트로 띄웠다.

 

당연히 apm-server는 elasticsearch와 kibana를 depends_on 하고 있고, apm-server/config/apm-server.yml 경로에 설정 파일을 /usr/share/apm-server/경로에 마운트 했다.

 

(2) apm-server.yml

apm-server:
  host: "0.0.0.0:8200"
  rum:
    enabled: true
  kibana:
    enabled: true
    host: "kibana:5601"
#    protocol: "http"
    username: "elastic"
    password: "elasticpassword"

#setup.template.enabled: true
#setup.template.name: "apm-%{[observer.version]}"
#setup.template.pattern: "apm-%{[observer.version]}-*"
#setup.template.fields: "${path.config}/fields.yml"
#setup.template.overwrite: false

output.elasticsearch:
  hosts: ["elasticsearch:9200"]
  username: elastic
  password: elasticpassword
#  index: "apm-%{[observer.version]}-%{+yyyy.MM.dd}"
#  indices:
#    - index: "apm-%{[observer.version]}-sourcemap"
#      when.contains:
#        processor.event: "sourcemap"
#    - index: "apm-%{[observer.version]}-error-%{+yyyy.MM.dd}"
#      when.contains:
#        processor.event: "error"
#    - index: "apm-%{[observer.version]}-transaction-%{+yyyy.MM.dd}"
#      when.contains:
#        processor.event: "transaction"
#    - index: "apm-%{[observer.version]}-span-%{+yyyy.MM.dd}"
#      when.contains:
#        processor.event: "span"
#    - index: "apm-%{[observer.version]}-metric-%{+yyyy.MM.dd}"
#      when.contains:
#        processor.event: "metric"
#    - index: "apm-%{[observer.version]}-onboarding-%{+yyyy.MM.dd}"
#      when.contains:
#        processor.event: "onboarding"

monitoring.enabled: true
monitoring.elasticsearch:
  username: "elastic"
  password: "elasticpassword"
  hosts: ["elasticsearch:9200"]

setup.kibana:
  host: 'kibana:5601'


#logging:
#  to_files: false

 

많은 옵션들이 있지만 필수적으로 apm-server와 output이 들어가야 한다.

 

본인의 Elastic Stack에서는 xpack 보안이 걸려져있기 때문에 id와 pw는 필수로 설정해두어야 한다.

 

 

2. APM-Agent (Python Django)

Python 웹 프레임워크 Django에서 Settings.py 안에 elastic-apm 설정을 해야한다.

pip install elastic-apm

위 라이브러리를 설치.

 

# settings.py

INSTALLED_APPS = [
 	. . .
    'elasticapm.contrib.django',
]


MIDDLEWARE = [
    'elasticapm.contrib.django.middleware.TracingMiddleware',
]


# Elastic
ELASTIC_APM = {
    'SERVICE_NAME': 'ably',
    'SECRET_TOKEN': '',
    'SERVER_URL': 'http://127.0.0.1:8200',
    'ENVIRONMENT': 'production',
    'DEBUG': True
}

 

위와 같이 세팅하고 서버 실행을 시켜야 한다.

 

apm이 잘 연동되었는지 확인하기 위한 명령어도 있다.

python manage.py elasticapm test
python manage.py elasticapm check

두 가지 명령어를 다 입력해보길 권장한다.

 

 

3. KIbana DashBoard - APM

위와 같이 도커를 세팅하고 띄우면, Kibana -> APM으로 들어가서 APM-Server와 APM-Agent 연동을 확인할 수 있다.

위 사진과 같이 APM Server status에서 Check 버튼으로 연동되었는지(서버가 띄어졌는지) 확인할 수 있다.

 

아래의 사진은 Agent 연동 확인하는 버튼이다. 

아래는 웹 어플리케이션(본인은 Python Django)에서 연동 작업을 하였다.

 

 

 

4. APM 시각화

APM으로 들어가면 앞서 django settings.py에서 'SERVICE_NAME'으로 설정한 네임이 등록되게 된다.

 

Transactions를 확인해보면,

파이썬 서버 실행시키고 본인은 여러 API를 호출을 했다. (테스트를 하기 위해서)

 

트랜잭션이 실행된 API를 확인할 수 있는데, 여기서 하나의 API로 들어가서 디테일 부분을 확인해보겠다.

 

아래의 그림과 같이 RDB와 NoSQL 등등 사용한 기술에 대한 쿼리 정보가 담겨져 있다.