Kubernetes 에서 Datadog Java (Spring Boot) APM 적용하기
Tags: kubernetes, java, datadog
Published: 2022-02-21 08:49:44

## 들어가며
현재 진행중인 프로젝트는 Kubernetes (AWS EKS) 에서 Istio 를 사용하면서 Java, Go, Python 등으로 개발 된 서비스를 개발/운영 중이다. 로깅, 모니터링, APM 을 위해서는 Datadog을 사용중이고, 여기서는 Datadog의 Java (Spring Boot) APM 적용을 정리하려고 한다. 

## Kubernetes 에서 Datadog 설치
Kubernetes 에서 Datadog Agent 를 설치하고 설정하는 내용은 [Kubernetes/Istio 를 위한 Datadog 설정](https://dev.to/airoasis/kubernetesistio-reul-wihan-datadog-seoljeong-471k) 에 설명하였다. 해당 Post의 내용대로 Datadog 을 설치하면 Kubernetes/Istio 모니터링, 모든 Pod (컨테이너)의 로그 수집, APM 을 받을 수 있는 상태로 Datadog Agent 및 Datadog Cluster Agent가 설정 완료된다. 만약 Istio를 사용하지 않는다면 "Istio 설정 변경" 부분만 적용하지 않으면 된다. 

여기에서 중요한건 `DD_DOGSTATSD_NON_LOCAL_TRAFFIC` 를 설정해야 JVM Metrics 까지 모니터링 할 수 있다. 

## Spring Boot 서비스를 위한 Kubernetes deployment 리소스 생성
아래와 같이 deployment를 생성하면 Datadog 에서 해당 서비스의 APM 및 JVM Metrics, Profiling Metrics, Kubernetes Metrics 등 모니터링이 가능하다. Datadog java agent는 Spring Boot 서비스에 Java Agent 로 올라가고 일반 Tracing 데이터는 Spring Boot 이 올라간 Pod가 속한 Node에 DaemonSet으로 deploy된 Datadog Agent의 tracing-agent서비스 (Port: 8126)로 수집한 데이터를 보내고 JVM Metrics 정보는 agent 서비스 (Post: 8125)로 보내게 된다. 

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: main-server
  labels:
    app: main-server
spec:
  selector:
    matchLabels:
      app: main-server
  template:
    metadata:
      labels:
        app: main-server
    spec:
      volumes: 
      - name: datadog-apm-agent 
        emptyDir: {}
      containers:
      - name: main-server
        image: mwp/main-server:latest
        volumeMounts: 
        - name: datadog-apm-agent 
          mountPath: /datadog/apm/agent 
        env:
          - name: DD_AGENT_HOST
            valueFrom:
              fieldRef:
                fieldPath: status.hostIP
          - name: DD_SERVICE
            valueFrom:
              fieldRef:
                fieldPath: metadata.labels['app']
          - name: DD_ENV
            value: "develop"
          - name: DD_VERSION
            value: "1.0"
          - name: DD_TRACE_ENABLED
            value: "true"
          - name: DD_TRACE_SAMPLE_RATE
            value: "1"
          - name: DD_PROFILING_ENABLED
            value: "true"
          - name: DD_LOGS_INJECTION
            value: "true"
          - name: DD_JMXFETCH_ENABLED
            value: "true"
        ports:
          - containerPort: 8080
      initContainers:
      - name: datadog-apm-agent
        image: busybox
        command:
        - wget
        - -O
        - /datadog/apm/agent/dd-java-agent.jar
        - https://dtdg.co/latest-java-tracer
        volumeMounts:
        - name: datadog-apm-agent
          mountPath: /datadog/apm/agent
```

Datadog 문서에는 java agent를 다운받아서 사용하라고 되어있고, 직접 소스코드에서 다운 받아서 사용할 수도 있다. 하지만 좀 더 Kubernets스럽게? 하는 방법은 위에서와 같이 Pod 에서 사용할 volume을 만들고 `initContainers`를 사용하여 Pod가 올라가기 전에 `wget`으로 java agent를 다운 받아서 mount한 volume 에 저장하고, 실제 Spring Boot 이 올라가는 container 에서 해당 volume 에 저장된 java agent 를 사용하는 방법이다. 

* `DD_AGENT_HOST`: Pod가 속한 Node에 DeamonSet으로 deploy된 Datadog Agent로 APM 데이터를 보내기 위해 `status.hostIP` 를 사용하여 node의 IP를 설정한다. 
* `DD_SERVICE`: Datadog APM 에서 보여지는 서비스명으로 metadata의 app 이름으로 설정하였다. 
* `DD_TRACE_ENABLED`: 다양한 환경, 예를 들어 dev/stg/prd 와 같이 다양한 환경에서 APM 의 사용 여부를 정할 때 유용하게 사용 가능
* `DD_TRACE_SAMPLE_RATE`: 수집하는 데이터의 sampling rate을 설정한다. 1은 100%를 의미한다. 
* `DD_PROFILING_ENABLED`: Datadog Continuous Profiler 를 활성화 하는 것으로 매우 매우 낮은 overhead로 code issue나 performance regression을 확인할 수 있다. 
* `DD_JMXFETCH_ENABLED`: JVM Metrics를 활성화 하기 위해 필요하다. 문서에는 default 값이 true라고 되어 있지만 명시적으로 이렇게 하지 않으면 JVM Metrics 가 나오지 않는다... (버그인거 같다)

> 🤚 위에 있는 Deployment 는 Datadog의 Java agent를 설명하기 위한 최소한의 설정이다. 실제 운영환경에서 필요한 Spring Boot, Kubernetes 관련 개발/설정은 [Kubernetes 에서 Spring Boot 서비스 개발하기 시리즈](https://dev.to/airoasis/series/16894)에 정리하였다.

## 마치며
이번에 상용을 앞둔 서비스를 LoadRunner를 통해 테스팅을 하였다. Kubernetes의 HPA, CA를 사용하면서 문제점을 확인하고 troubleshooting을 하는데 Datadog의 monitoring 과 APM 은 정말 정말 정말 유용하게 사용되었다. 이와 관련된 글은 다른 Post 에 정리할 예정이다. 

## References
* https://docs.datadoghq.com/tracing/setup_overview/setup/java/?tab=springboot
* https://docs.datadoghq.com/tracing/runtime_metrics/java/
* https://docs.datadoghq.com/developers/dogstatsd/?tab=kubernetes#setup