글 작성자: beaniejoy

 

  • Overview
  • What is APM?
  • docker compose file 구성하기
  • 실행하기

 

📌 1. Overview

프로젝트 진행하면서 ngrinder 성능테스트 툴까지 세팅은 다 마친 상황에서 이제 이를 모니터링 할 수 있는 툴을 적용해야 될 시점이 왔습니다. 여러 모니터링 툴들이 많이 있었지만 저는 그 중에 Elastic APM을 적용해봤습니다.

 

📌 2. What is APM?

APM(Application Performance Monitoring or Management)
영어 명칭 그대로 애플리케이션의 성능을 모니터링해주는 시스템을 뜻합니다. 리얼타임에서 서비스 애플리케이션의 성능을 보여주는데 정말 많은 지표들을 제공해줍니다. (Request에 대한 응답 시간, DB 쿼리 성능, 캐쉬 등등)

애플리케이션 백엔드에 있어서 가장 중요한 것은 요청과 응답 과정 속에서 여러 구간들이 존재하는데 이 중 하나라도 문제가 발생하면 애플리케이션 전체에 큰 문제를 초래하게 됩니다. 이러한 문제가 발생했을 때 빠르게 해당 지점을 찾아서 문제 해결을 하는 것이 백엔드 개발자와 엔지니어의 중요한 역할 중 하나입니다.

APM은 이러한 문제들을 빠르게 캐치할 수 있도록 가시화된 자료들을 제공해주는 유용한 도구입니다.

https://www.elastic.co/guide/en/apm/get-started/current/components.html

Elastic APM은 크게 네 가지로 나뉩니다.

  • APM Agent
  • APM Server
  • Elasticsearch
  • Kibana

APM Agent는 애플리케이션에 붙어서 성능을 자동으로 측정해주고 에러를 추적해주는 도구입니다. APM Server는 Agent가 측정한 자료들을 받아서 Elasticsearch에 맞게 변환해서 보내주는 역할을 해줍니다.

Elasticsearch는 분산형 검색, 분석 엔진이면서 Agent에서 보내준 성능관련 데이터들을 저장해놓는 역할을 합니다. Kibana는 Elasticsearch기반으로 UI를 제공해줌으로써 데이터를 가시화해줍니다.

 

📌 3. docker compose file 구성하기

Elastic APM은 직접 다운받아서 각각 실행해서 설정하는 방법이 있지만 저는 docker를 이용해 APM Agent, APM Server, Elasticsearch, Kibana 네 개의 구성요소를 설정하였습니다.

 

🔖 3-1. Elastic Environment 구성

위의 세 개 요소들을 구성합니다.

APM Server elastic github에는 Dockerfile과 docker-compose.yml 설정에 대한 내용들이 많습니다.

# docker-compose.yml
version: '3.8'
services:
  apm-server:
    image: docker.elastic.co/apm/apm-server:7.14.0
    depends_on: 
      - proxy_dep
    container_name: apm-server
    cap_add: ["CHOWN", "DAC_OVERRIDE", "SETGID", "SETUID"]
    cap_drop: ["ALL"]
    # volumes: 
    #   - ./apm-server/apm-server.docker.yml:/usr/share/apm-server/apm-server.yml:ro
    ports:
      - "8200:8200"
    networks: 
      - elastic
      - apm-network
    command: >
      apm-server -e
        -E apm-server.rum.enabled=true
        -E setup.kibana.host=kibana:5601
        -E setup.template.settings.index.number_of_replicas=0
        -E apm-server.kibana.enabled=true
        -E apm-server.kibana.host=kibana:5601
        -E output.elasticsearch.hosts=["elasticsearch:9200"]
    healthcheck:
      interval: 10s
      retries: 12
      test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:8200/

  # This is a proxy used to block beats until all services are healthy.
  # See: https://github.com/docker/compose/issues/4369
  proxy_dep:
    image: busybox
    depends_on:
      elasticsearch: { condition: service_healthy }
      kibana: { condition: service_healthy }

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
    container_name: elasticsearch
    environment:
      - bootstrap.memory_lock=true
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - esdata:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
    networks:
      - elastic
    healthcheck:
      interval: 20s
      retries: 10
      test: curl -s http://localhost:9200/_cluster/health | grep -vq '"status":"red"'

  kibana:
    image: docker.elastic.co/kibana/kibana:7.14.0
    depends_on: 
      elasticsearch: { condition: service_healthy }
    container_name: kibana
    ports:
      - "5601:5601"
    environment:
      ELASTICSEARCH_URL: http://elasticsearch:9200
      ELASTICSEARCH_HOSTS: http://elasticsearch:9200
    networks:
      - elastic
    healthcheck:
      interval: 10s
      retries: 20
      test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:5601/api/status

volumes:
  esdata:
    driver: local

networks:
  elastic:
    driver: bridge
  apm-network:
    external: 
      name: apm_env

docker-compose.yml 구성에 있어서 중요한 것이 networks 설정입니다. APM Server는 APM Agent(프로젝트에서는 Spring Boot Application)와 연결을 해야하기 때문에 docker 환경 상 같은 네트워크에 속해 있어야 합니다. (안그러면 Connection Refused 같은 에러 발생합니다.)

$ docker network create apm_env

docker file 내부 네트워크 말고 외부 네트워크를 설정해서 Server, Agent 연결을 해야하기 때문에 따로 docker 환경에 임의의 network를 만들어줍니다.

 

🔖 3-2. Agent(Application단) docker 설정

여기서는 Spring Boot Application에 적용할 Agent를 설정해야 하기 때문에 APM Java Agent를 사용하였습니다.

# docker-compose.yml
version: "3.8"
services:
  # load balancer
  nginx:
    image: nginx
    container_name: nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx/:/etc/nginx/conf.d/
    depends_on:
      - boot_app_1
      - boot_app_2
  boot_app_1:
    build:
      dockerfile: Dockerfile
      context: .
    # 임의의 network를 지정하면 default에 대한 자동설정이 없어짐, 따로 지정해야함
    networks:
      - default
      - apm-network
  boot_app_2:
    build:
      dockerfile: Dockerfile
      context: .
    networks:
      - default
      - apm-network

networks:
  apm-network:
    # 해당 docker-compose 파일 기준으로 생성된 네트워크에서 외부로 연결
    # apm-server와 같은 네트워크로 묶기 위한 설정
    external:
      name: apm_env

임시 Boot Application을 만들어서 여기에 Agent를 설정해보겠습니다. 기본적으로 nginx를 통한 load balancing을 적용하고 있고 2개 application을 통해 scale-out 환경에서 진행해보겠습니다.

여기서도 중요한 것이 위에 APM Server의 network로 외부 apm_env라는 네트워크를 지정했습니다. Spring Boot 2개의 서버도 여기에 연결해줘야 Agent와 Server를 연결할 수 있습니다.

# Dockerfile
FROM adoptopenjdk/openjdk11:alpine

VOLUME /vol

ARG app_file=build/libs/*.jar
ARG apm_agent=apm-agent/*.jar

COPY ${app_file} app.jar
COPY ${apm_agent} apm-agent.jar

ENTRYPOINT ["java", \
"-javaagent:/apm-agent.jar", \
"-Delastic.apm.server_urls=http://apm-server:8200", \
"-Delastic.apm.service_name=boot-apm-agent", \
"-Delastic.apm.application_packages=com.example", \
"-Delastic.apm.environment=dev", \
"-Dspring.profiles.active=dev", \
"-jar", \
"/app.jar"]
  • -javaagent: elastic apm-agent-[version].jar 파일을 매칭시켜놓습니다.
  • server_urls: 연결하고자 하는 apm-server를 지정합니다. 여기서 도메인 이름은 같은 네트워크로 설정했던 apm-server의 container name으로 지정할 수 있습니다.(http://apm-server:8200)
  • service_name: 해당 애플리케이션 이름을 지정합니다. 나중에 kibana UI에 적용됩니다.
  • application_packages: 해당 애플리케이션 상위 패키지 명을 지정합니다.

 

📌 4. 실행하기

 

🔖 4-1. Elastic Environment 실행

위의 설정을 마치면 이제 한번 실행해볼 차례입니다.

$ cd elastic-apm-env/
$ docker-compose up

APM Server, Elasticsearch, Kibana가 도커를 통해 한꺼번에 올라갑니다.

$ curl localhost:8200

도커를 통해 apm 환경을 띄우고 나서 위와 같이 APM Server를 한번 호출해봅니다.

{
  "build_date": "2021-07-29T19:55:24Z",
  "build_sha": "...",
  "version": "7.14.0"
}

이런 식으로 JSON 형태 데이터를 응답해야 제대로 서버가 올라간 것입니다.

localhost:5601 를 브라우저 주소 입력란에 입력하고 들어갑니다.

해당 포트는 kibana를 가리키는데 도커로 올린 후 위와 같은 Kibana UI가 나와야 제대로 올라간 것입니다.

 

🔖 4-2. Application 실행하기

$ cd boot-apm-agent
$ ./gradlew clean build
$ docker-compose up

Spring Boot Application을 gradle을 통해 build를 한 후 docker를 띄웁니다.

두 개의 Spring Boot가 나오고 나서 Kibana를 확인해줍니다.

Kibana에서 왼쪽 탭에 APM > Services 탭을 클릭하면 위와 같이 해당 애플리케이션이 나와야 정상적으로 연결이 된 것입니다.

여기까지가 docker를 이용한 Spring Boot Application에 Elastic APM 적용하는 내용이었고 다음에는 성능테스트를 통해 어떻게 출력이 되고 어떤 것들을 봐야하는지에 대해 공부하고 정리해보겠습니다. 감사합니다.

 

Github

 

틀린 내용이 있을 수 있습니다. 이에 대한 코멘트 언제나 환영입니다!

'Monitoring' 카테고리의 다른 글

docker를 이용한 Ngrinder 성능 테스트 환경 세팅  (0) 2021.07.25