AWS 기술 블로그

Amazon EKS에서 관리형 서비스를 활용하여 Spring Boot 애플리케이션 관찰 가능성(Observability) 구성하기

관찰 가능성(Observability, O11y)은 시스템의 건강 상태와 성능을 실시간으로 이해하고, 문제가 발생할 때 그 원인을 신속하게 파악할 수 있게 하는 중요한 개념입니다. 이는 단순히 시스템이 작동 중인지 여부를 확인하는 것을 넘어서, 시스템이 어떻게 작동하고 있는지를 깊이 있게 이해하는 것을 의미합니다. 특히 복잡한 분산 시스템에서 컨테이너 기반 애플리케이션을 운영하는 경우, 다양한 구성 요소 간의 상호 작용이 많아져, 시스템의 전체적인 상태를 파악하기 위해 관찰 가능성이 필수적으로 요구됩니다.

관찰 가능성에서 중요한 세 가지 요소는 로그(Logs), 메트릭(Metrics), 그리고 트레이스(Traces)입니다. 로그는 애플리케이션의 활동을 기록하는 것으로, 이러한 로그 데이터는 파일로 저장되고 수집기를 통해 Amazon CloudWatch Logs 서비스로 전송합니다. 메트릭은 시스템의 성능을 나타내는 지표로, 대부분의 AWS 관리형 리소스에 대한 메트릭은 CloudWatch에서 확인할 수 있습니다. 그러나 애플리케이션 수준의 메트릭은 프로메테우스와 같은 오픈소스 기반의 저장소에 별도로 저장될 수도 있습니다. 트레이스는 애플리케이션 내 요청의 흐름을 추적하는 것으로, 이를 위해 다양한 오픈소스 라이브러리를 활용해 자동 수집 에이전트를 사용하거나, 직접 SDK를 사용하여 계측하는 방식이 있습니다. AWS의 경우, AWS X-RayAWS Distro for OpenTelemetry(ADOT)는 이러한 트레이스를 지원하는 SDK를 제공합니다.

이 블로그 게시물에서는 AWS에서 제공하는 관찰 가능성 도구를 소개하고 이를 사용하여 최소한의 노력으로 최신 스프링부트 애플리케이션과 Amazon EKS 클러스터 리소스 측정을 시작하는 방법을 공유합니다. 특히 Amazon EKS와 애플리케이션의 메트릭 정보를 Amazon Managed Service for Prometheus(AMP)에 수집하고, 로그와 트레이스 정보를 CloudWatch Logs, AWS X-Ray에 전송하고 연동하여 이 3가지 요소를 Amazon Managed Grafana(AMG)에서 시각화하는 방법에 대해서 알아보겠습니다.

AWS 관찰 가능성 도구 소개

관찰 가능성을 구축한다는 것은 도구를 사용하여 데이터를 계측하고, 이 데이터를 수집하여 저장하는 과정을 포함합니다. 최근에는 저장된 데이터를 시각화하는 것까지 관찰 가능성의 중요한 부분으로 인식되고 있습니다.

먼저, 에이전트나 SDK를 활용하여 필요한 데이터를 계측하는 것이 시작점입니다. 계측 대상 데이터는 메트릭(예: 물리적 리소스 사용량, 오류 발생율, 사용 시간), 로그, 트레이스 정보 등입니다. 여기에는 애플리케이션 자체적으로 생성하는 메트릭 데이터, 예를 들어 API 호출 횟수나 비즈니스 분석을 위한 다양한 메트릭 타입(Counter, Gauge, Histogram, Summary 등)도 포함됩니다. 이러한 계측 작업은 AWS에서 제공하는 에이전트를 포함하여 애플리케이션 프레임워크의 Logger나 관련된 라이브러리와 SDK를 통해 수행됩니다.

계측된 데이터는 수집기를 통해 저장소로 전송되어야 합니다. 과거에는 로그, 메트릭, 트레이스 각각에 대해 별도의 수집기(Collector)가 필요했지만, OpenTelemetry 프로젝트의 등장으로 이러한 수집기를 하나로 통합하여 사용하는 것이 가능해졌습니다. AWS에서도 사용자들이 계측된 데이터를 쉽게 수집할 수 있는 계측 도구와 수집기를 제공합니다.

AWS Distro for OpenTelemetry 수집기

AWS는 Amazon EKS 환경에서 관찰 가능성 데이터를 쉽게 수집할 수 있도록 OpenTelemetry 기반의 ADOT 수집기를 제공합니다. ADOT 수집기는 다양한 receiver와 exporter를 설정할 수 있습니다. 지원이 가능한 목록은 aws-otel-collector 프로젝트 GitHub 저장소의 README 문서에서 확인이 가능합니다. 고객은 관찰 가능성을 위한 계측 데이터를 별도의 수집기가 아닌 하나의 ADOT 수집기를 통해서 수집이 가능합니다.

Amazon Managed Service for Prometheus 수집기

AWS는 최근 Amazon EKS에서 실행되는 워크로드의 Prometheus 지표를 수집하기 위한 완전 관리형 에이전트 없는 수집기인 Amazon Managed Service for Prometheus 수집기(AWS managed collectors)를 발표했습니다. 고객들은 별도의 에이전트 관리 없이 Amazon EKS 애플리케이션 및 인프라에서 프로메테우스 지표를 효율적으로 검색하고 수집할 수 있습니다. 이 수집기는 데이터가 안전한 VPC를 벗어나는 일 없이 프로메테우스 지표를 수집할 수 있는 신뢰할 수 있고 가용성이 뛰어난 다중 AZ의 완전관리형 서비스를 제공합니다.

솔루션 개요

Amazon EKS 에서 스프링부트 애플리케이션을 Pod로 운영하는 가정 하에서 관찰 가능성을 위한 솔루션은 다음과 같습니다.

  • 1 단계: Amazon EKS 클러스터 생성 후 ADOT 애드온 설치
  • 2 단계: 로그 수집을 위한 ADOT 수집기 설정하기
  • 3 단계: 트레이스 수집을 위한 ADOT 수집기 설정하기
  • 4 단계: AMP 서비스 AWS managed collectors 설정하기
  • 5 단계: 스프링부트 애플리케이션 배포하기
  • 6 단계: AMG 대시보드 생성하기

솔루션에 사용되는 스프링부트 샘플 애플리케이션은 스프링부트 액추에이터(Actuator)와 마이크로미터 라이브러리를 활용하여 애플리케이션 메트릭 정보를 노출하도록 구성했습니다. 추가로 샘플 애플리케이션은 OpenTelemetry Agent for Java 기반의 aws-otel-java-instrumentation 에이전트를 활용하여 트레이스 데이터를 자동 계측하도록 실행합니다.

그림1. 솔루션 전체 아키텍처

1단계: Amazon EKS 클러스터 생성 후 ADOT 애드온 설치

먼저 Kubernetes 1.28 버전의 Amazon EKS 클러스터를 생성합니다. 클러스터 생성이 완료되면 아래 그림과 같이 Amazon EKS 콘솔의 클러스터 메뉴의 Add-on 메뉴에서 ADOT 애드온을 설치할 수 있습니다.

그림2. Amazon EKS Add-on 메뉴에서 확인할 수 있는 다양한 관리형 애드온 목록

AWS Distro for OpenTelemetry를 선택하고, 애드온 설정은 기본값 설정 그대로 유지하여 설치를 진행합니다.

그림3. AWS Distro for OpenTelemetry 애드온 설치를 위한 설정 화면

설치가 완료되면 콘솔의 Add-ons 메뉴에서 애드온 상태를 확인할 수 있습니다. Active 상태가 되면 EKS 클러스터에는 OpenTelemetry의 오퍼레이터가 배포된 것을 확인할 수 있습니다. 오퍼레이터가 배포된 이후에는 ADOT 수집기를 위한 사용자 정의 리소스(Custom Resource Definition, CRD)를 정의하여 ADOT 수집기를 배포할 수 있습니다.

그림4. k9s 도구로 ADOT 오퍼레이터 확인

ADOT 수집기는 설정 파일을 통해 receiver와 exporter를 정의함으로써 데이터 수집 및 전송에 필요한 구성을 할 수 있습니다. 이를 통해 하나의 수집기로 로그, 메트릭, 트레이스 정보를 모두 수집하는 것이 가능합니다. 그러나 실제 운영 환경에서는 각 수집 대상에 따라 별도의 수집기를 구성하는 것이 바람직합니다. 이는 각 수집기에 특정 작업을 전담시킴으로써 부하 분산과 장애 격리를 달성하기 위함입니다. 또한, 수집기를 분리함으로써 시스템의 유연성과 확장성을 높일 수 있으며, 수집기별로 필요한 권한 설정을 다르게 하여 보안을 강화할 수 있습니다. 다음 단계에서는 로그와 트레이스를 위한 수집기를 순차적으로 설정하는 방법에 대해 살펴보겠습니다.

2 단계: 로그 수집을 위한 ADOT Collector 설정하기

로그 수집을 위한 ADOT 수집기를 설정하기 전에 IAM Roles for Service Accounts 설정을 통해 수집기의 권한을 생성해야 합니다. 아래 eksctl 명령어를 통해서 쉽게 설정이 가능합니다. 생성된 IAM 역할의 ARN 값은 따로 기록하여 아래 과정에서 사용합니다.

eksctl create iamserviceaccount \
  --name adot-col-container-logs \
  --namespace opentelemetry-operator-system \
  --cluster my-eksctl-cluster \
  --attach-policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy \
  --approve \
  --role-only

앞에서 설치한 EKS add-on은 배포할 ADOT 수집기를 구성할 수 있는 설정 기능을 제공합니다. Add-ons 메뉴에서 ADOT add-on을 선택하면 수집기 설정을 수정할 수 있습니다. Edit 버튼을 눌러서 편집화면으로 진입하여 Optional configuration settings 드롭다운 메뉴를 펼칩니다. Configuration values에 아래의 YAML 파일 설정 내용을 입력하여 저장합니다.

collector:
  containerLogs:
    serviceAccount:
      annotations:
        eks.amazonaws.com/role-arn: <iam_role_arn_for_log>
    pipelines: 
      logs: 
        cloudwatchLogs: 
          enabled: true 
    exporters: 
      awscloudwatchlogs: 
        log_group_name: /aws/eks/my-eks-cluster/containers/application

어노테이션의 eks.amazonaws.com/role-arn 에는 위에서 생성한 IAM 역할의 ARN 값을 입력합니다. 추가로 특정 S3 버킷에 로그를 전송하고 싶다면 exporters 설정에서 log_group_namelog_stream_name을 설정할 수 있습니다. 만약, 트레이스 정보와 로그 정보를 X-Ray 콘솔에서 연동하여 확인하고자 할 때 log_group_name이 일치해야 하기 때문에 이런 경우 설정이 필요합니다. 기타 추가 설정은 공식 문서를 참고합니다.

설정을 저장하면 add-on 업데이트가 진행되고, 로그 수집을 위한 수집기가 DaemonSet 형태로 배포됩니다.

그림5. k9s 도구로 로그 수집을 위한 ADOT Collector 배포 확인

3 단계: 트레이스 수집을 위한 ADOT Collector 설정하기

마찬가지로 트레이스 데이터 수집을 위한 ADOT 수집기를 설정하기 전에 IAM Roles for Service Accounts 설정을 통해 수집기의 권한을 생성해야 합니다. 아래 eksctl 명령어를 통해서 쉽게 설정이 가능합니다. 생성된 IAM 역할의 ARN 값은 따로 기록하여 아래 과정에서 사용합니다.

eksctl create iamserviceaccount \
  --name adot-col-otlp-ingest \
  --namespace opentelemetry-operator-system \
  --cluster my-eks-cluster \
  --attach-policy-arn arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess \
  --approve \
  --role-only

마찬가지로 ADOT add-on의 수집기 설정 기능을 활용하여 기존 설정을 아래처럼 업데이트합니다.

collector:
  containerLogs:
    serviceAccount:
      annotations:
        eks.amazonaws.com/role-arn: <iam_role_arn_for_log>
    pipelines:
      logs:
        cloudwatchLogs:
          enabled: true
    exporters:
      awscloudwatchlogs:
        log_group_name: /aws/eks/my-eks-cluster/containers/application
  otlpIngest:
    serviceAccount:
      annotations:
        eks.amazonaws.com/role-arn: <iam_role_arn_for_trace>
    pipelines:
      traces:
        xray:
          enabled: true

설정을 업데이트하면 X-Ray 수집을 위한 수집기가 Deployment 형태로 배포됩니다.

그림5. k9s 도구로 X-Ray 트레이스 수집을 위한 ADOT Collector 배포 확인

X-Ray 트레이스 수집을 위해 배포된 수집기는 기본으로 4317 TCP 포트를 개방하고 있습니다. 따라서 수집기에 해당하는 서비스의 FQDN 주소를 향후 애플리케이션 설정에 X-Ray 데이터를 전송하도록 엔드포인트로 설정해야 합니다.

4 단계: 메트릭 수집을 위해 AMP 서비스 AWS managed collectors 설정하기

로그와 트레이스 데이터와 마찬가지로 메트릭 데이터도 ADOT 수집기를 이용하여 수집이 가능합니다. 설정하는 방법은 위 단계와 크게 다르지 않으며 공식 문서를 참고하면 쉽게 설정 가능합니다. 하지만 만약 여러분이 AMP 서비스를 사용하여 프로메테우스 데이터를 저장한다면, AMP에서 제공하는 AWS managed collectors도 사용할 수 있습니다. 이 수집기의 장점은 여러분의 Amazon EKS 클러스터의 리소스를 사용하지 않고, EKS 클러스터의 지표 수집을 위한 수집기를 설정할 수 있다는 것입니다. 따라서 메트릭 수집기를 별도로 운영하는 상황에서 AMP 서비스에서 제공하는 AWS managed collectors는 좋은 옵션입니다.

먼저 스크래퍼(Scraper)를 생성해야 합니다. 스크래퍼는 Amazon EKS 클러스터를 생성하는 과정에서 구성할 수 있지만, 이미 클러스터가 생성된 상태에서는 아래와 같은 AWS CLI를 통해서 생성할 수 있습니다. (약 20분 내외 소요)

aws amp create-scraper \
  --scrape-configuration configurationBlob=$SCRAPER_CONFIG_BASE64_ENCODE_BLOB
  --destination ampConfiguration={workspaceArn=$AMP_WORKSPACE_ARN}
  --source eksConfiguration="{clusterArn=arn:aws:eks:ap-northeast-2:$ACCOUNT_NUMBER:cluster/$CLUSTER_NAME, securityGroupIds=[sg-xxxx], subnetIds=[subnet-xxxx1,subnet-xxxx2,subnet-xxxx3]}"

만약 파라미터를 직접 입력하기 복잡하다면, json 파일로 정리해서 아래처럼 사용할 수 있습니다.

aws amp create-scraper --cli-input-json file://amp-create-scraper-cli-input.json

여기서 amp-create-scraper-cli-input.json 는 스크래퍼 생성 시에 입력할 수 있는 파라미터를 json 파일로 구성한 것으로 --cli-input-json 파라미터와 함께 사용합니다. amp-create-scraper-cli-input.json 은 아래처럼 구성합니다.

{
    "alias": "my-eks-cluster-scraper",
    "scrapeConfiguration": {
      "configurationBlob": "$SCRAPER_CONFIG_BASE64_ENCODE_BLOB"
    },
    "source": {
      "eksConfiguration": {
        "clusterArn": "arn:aws:eks:ap-northeast-2:$ACCOUNT_ID:cluster/my-eks-cluster",
        "securityGroupIds": [
          "sg-xxxx"
        ],
        "subnetIds": [
          "subnet-xxxx1",
          "subnet-xxxx2",
          "subnet-xxxx3"
        ]
      }
    },
    "destination": {
      "ampConfiguration": {
        "workspaceArn": "$AMP_WORKSPACE_ARN"
      }
    }
}

여기서 실제 스크래퍼가 수집할 대상에 대한 설정은 $SCRAPER_CONFIG_BASE64_ENCODE_BLOB입니다. 이 값은 아래와 같은 설정값의 base64 인코딩 값입니다. base64 인코딩이 가능한 도구를 활용해서 아래 설정 내용을 인코딩하여 입력합니다. 설정시 주의할 점은 현재 AWS managed collectors 설정의 수집주기(scrape_interval)는 30초 이하를 지원하고 있지 않습니다.

global:
   scrape_interval: 30s
scrape_configs:
  - job_name: pod_exporter
    kubernetes_sd_configs:
      - role: pod
  - job_name: cadvisor
    scheme: https
    authorization:
      credentials_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    kubernetes_sd_configs:
      - role: node
    relabel_configs:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+)
      - replacement: kubernetes.default.svc:443
        target_label: __address__
      - source_labels: [__meta_kubernetes_node_name]
        regex: (.+)
        target_label: __metrics_path__
        replacement: /api/v1/nodes/$1/proxy/metrics/cadvisor
  # apiserver metrics
  - scheme: https
    authorization:
      credentials_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    job_name: kubernetes-apiservers
    kubernetes_sd_configs:
    - role: endpoints
    relabel_configs:
    - action: keep
      regex: default;kubernetes;https
      source_labels:
      - __meta_kubernetes_namespace
      - __meta_kubernetes_service_name
      - __meta_kubernetes_endpoint_port_name
  # kube proxy metrics
  - job_name: kube-proxy
    honor_labels: true
    kubernetes_sd_configs:
    - role: pod
    relabel_configs:
    - action: keep
      source_labels:
      - __meta_kubernetes_namespace
      - __meta_kubernetes_pod_name
      separator: '/'
      regex: 'kube-system/kube-proxy.+'
    - source_labels:
      - __address__
      action: replace
      target_label: __address__
      regex: (.+?)(\\:\\d+)?
      replacement: $1:10249
  # SpringBoot Actuator
  - job_name: springboot-actuator
    metrics_path: '/actuator/prometheus'
    kubernetes_sd_configs:
    - role: pod
      selectors:
      - role: 'pod'
        label: 'app.kubernetes.io/name=my-o11y-app'

위 설정에서 스크랩퍼의 Job을 기준으로 어떤 메트릭을 수집하는지 간단하게 살펴보겠습니다.

  • pod_exporter: Pod Exporter는 특정 Pod의 성능 메트릭을 수집합니다. 이는 Pod의 CPU 사용량, 메모리 사용량, 네트워크 트래픽 등을 포함할 수 있습니다. 이 정보는 포드의 성능 문제를 진단하고 용량 계획을 수립하는 데 필수적입니다.
  • cadvisor: cAdvisor(Container Advisor)는 컨테이너의 리소스 사용량과 성능 특성을 수집하는 도구입니다. 이는 각 컨테이너의 CPU, 메모리, 스토리지 및 네트워크 사용 데이터를 제공합니다. 이 정보는 컨테이너의 성능을 이해하고, 리소스 할당을 최적화하는 데 중요합니다.
  • kubernetes-apiservers: API 서버는 쿠버네티스 클러스터의 중앙 관리 시스템으로, 모든 관리 명령과 상태 정보의 중심점입니다. API 서버의 메트릭을 모니터링하면 클러스터의 관리 부하, 응답 시간, 에러율 등을 파악할 수 있어, 클러스터의 전반적인 건강 상태를 이해하는 데 도움이 됩니다.
  • kube-proxy: Kube-proxy는 쿠버네티스 네트워크 서비스를 관리하는 구성요소로, 포드 간 및 외부 네트워크와의 통신을 담당합니다. Kube-proxy의 메트릭을 통해 네트워크 트래픽, 연결 오류 등을 모니터링할 수 있으며, 이는 네트워크 성능과 관련된 문제를 진단하는 데 유용합니다.
  • springboot-actuator: SpringBoot는 Actuator 모듈을 이용해 다양한 지표 수집이 가능합니다. Actuator는 프로메테우스를 활용한 HTTP 트래픽 지표, JVM 지표, 시스템 지표, 데이터베이스 및 캐시 관련 지표를 포함해 사용자의 사용자 지정 메트릭 등을 수집 가능합니다. 위 설정에서는 수집 경로가 /actuator/prometheus으로, 기본 값으로 설정되어 있지만 해당 경로와 포트는 별도로 설정이 가능합니다. (일반적인 설정은 보안을 강화하기 위해서 경로를 변경하고, 포트를 API 포트와 분리합니다.) 프로메테우스의 scrape_config 문서를 참고하세요.

스크랩퍼 생성이 완료되면 아래와 같은 출력 결과를 확인할 수 있습니다. 여기서 스크랩퍼의 scraperId를 확인합니다.

{
    "scraperId": "s-c6f170d9-6b8e-4be1-b600-9768d7cffee1",
    "arn": "arn:aws:aps:ap-northeast-2:021788526072:scraper/s-c6f170d9-6b8e-4be1-b600-9768d7cffee1",
    "status": {
        "statusCode": "CREATING"
    },
    "tags": {}
}

이어서 아래 AWS CLI 명령어를 통해서 생성된 스크랩퍼의 Unique ID를 확인합니다. 결과 출력에 보이는 roleArn 값의 가장 끝에는 스크랩퍼의 Unique ID가 붙어있습니다. (예: arn:aws:iam::{account-number}:role/aws-service-role/scraper.aps.amazonaws.com/AWSServiceRoleForAmazonPrometheusScraper_{unique-id})

aws amp describe-scraper --scraper-id {scraper-id}

그림6. AWS CLI 명령어로 스크랩퍼 Unique ID 알아내기

이 값을 이용해서 아래와 같은 스크랩퍼 ARN 주소를 얻을 수 있습니다. (예: 600f8c3e-0a0e-4)

arn:aws:iam::${ACCOUNT_NUMBER}:role/AWSServiceRoleForAmazonPrometheusScraper_{unique-id}

다음으로 스크랩퍼가 클러스터의 내용을 수집하기 위해서 필요한 ClusterRole을 EKS 클러스터에 적용하여 Role 바인딩을 하겠습니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: aps-collector-role
rules:
  - apiGroups: [""]
    resources: ["nodes", "nodes/proxy", "nodes/metrics", "services", "endpoints", "pods", "ingresses", "configmaps"]
    verbs: ["describe", "get", "list", "watch"]
  - apiGroups: ["extensions", "networking.k8s.io"]
    resources: ["ingresses/status", "ingresses"]
    verbs: ["describe", "get", "list", "watch"]
  - nonResourceURLs: ["/metrics"]
    verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: aps-collector-user-role-binding
subjects:
- kind: User
  name: aps-collector-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: aps-collector-role
  apiGroup: rbac.authorization.k8s.io

이제 eksctl 명령어를 이용해서 위에서 만든 ClusterRole 바인딩을 스크랩퍼 IAM 역할과 연결하겠습니다.

eksctl create iamidentitymapping \
  --cluster {cluster-name} \
  --region {region} \
  --arn arn:aws:iam::{account-number}:role/AWSServiceRoleForAmazonPrometheusScraper_600f8c3e-0a0e-4 \
  --username aps-collector-user

이제 스크랩퍼 설정이 완료됐습니다. 스크랩퍼는 EKS 콘솔의 Observability 메뉴에서 확인이 가능합니다.

그림7. EKS 콘솔의 Observability 메뉴에서 확인이 가능한 스크랩퍼

스크랩퍼가 정상적으로 프로메테우스 메트릭 정보를 수집하고 있는지 확인하기 위해서 Amazon Managed Service for Grafana 콘솔에 접속합니다. Apps 메뉴의 AWS Data Sources로 AMP를 선택하고, 알맞은 리전을 선택하여 AMP 워크스페이스를 데이터 소스로 추가합니다.

그림8. Grafana의 Apps의 AWS Data Sources에서 쉽게 데이터 소스 지정이 가능

Grafana의 Explore 콘솔에서 데이터 소스를 알맞은 AMP로 지정하면 수집된 메트릭의 종류를 확인할 수 있습니다. 이 중에서 up 메트릭을 조회해보면 현재 프로메테우스에서 스크랩중인 Job 목록을 확인할 수 있습니다. result가 1인 Job은 정상적으로 스크랩을 하고 있다는 의미입니다.

그림9. 프로메테우스에서 확인이 가능한 메트릭 목록

그림10. up 메트릭으로 Job 목록 확인

5 단계: 스프링부트 애플리케이션 배포하기

자, 수집기 설정이 모두 끝났습니다. 본격적으로 스프링부트 애플리케이션을 위한 Dockerfile을 설정하겠습니다. (스프링부트의 Actuator 설정에 대한 설명을 생략합니다.)

애플리케이션 로그 설정을 먼저 진행하겠습니다. 일반적으로 컨테이너 애플리케이션은 표준 출력/에러(stdout/stderr)를 통해 로그를 출력하는 것이 관례입니다. 컨테이너 엔진은 로깅 드라이버를 사용하여 로그를 노드의 지정된 경로(Linux의 경우 /var/log/pods)에 파일로 저장합니다. 그러므로 애플리케이션 로그는 콘솔, 즉 표준 출력 형식으로 설정하는 것이 적절합니다. 하지만, 트레이스 정보와 로그를 연계하려는 경우, 로그 포맷에 X-Ray의 트레이스 ID를 포함시켜야 합니다. 다음은 Logback 설정에서 %clr(%X{AWS-XRAY-TRACE-ID}){yellow}를 로그 포맷에 추가한 예시입니다.

<included>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %clr(%X{AWS-XRAY-TRACE-ID}){yellow} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
</included>

다음으로 X-Ray 트레이스 데이터의 자동계측을 위해서 최신 버전의 aws-opentelemetry-agent.jar를 사용합니다. 이 때, 환경변수를 이용해서 몇 가지 설정을 해야합니다. 첫 번째로 해당 에이전트가 실제 트레이스 데이터를 수집하는 수집기로 데이터를 전송할 수 있도록 OTEL_EXPORTER_OTLP_ENDPOINT 환경변수로 엔드포인트 주소를 설정합니다. 엔드포인트 주소는 트레이스 수집기에 해당하는 쿠버네티스 서비스의 FQDN을 입력하고, 4317 포트를 사용합니다. 두 번째는 X-Ray 트레이스 데이터에 CloudWatch 로그 그룹 이름을 추가하기 위해 OTEL_RESOURCE_ATTRIBUTES 환경변수에 CloudWatch 로그 그룹 이름을 설정합니다.

완성된 Dockerfile의 예시는 아래와 같습니다.

# Base image
FROM amazoncorretto:17-alpine-jdk

# Working directory
WORKDIR /app

# Copy the jar file to the container
COPY ./build/libs/spring-boog-kotlin-otlp-0.0.1-SNAPSHOT.jar my-o11y-app.jar
COPY ./libs/aws-opentelemetry-agent.jar libs/aws-opentelemetry-agent.jar

# Expose the port number
EXPOSE 8080 8080

ENV OTEL_RESOURCE_ATTRIBUTES aws.log.group.names=/aws/eks/my-eks-cluster/containers/application
ENV OTEL_EXPORTER_OTLP_ENDPOINT http://adot-col-otlp-ingest-collector.opentelemetry-operator-system.svc.cluster.local:4317
ENV OTEL_METRICS_EXPORTER none

# Command to run the application
CMD ["java", "-javaagent:libs/aws-opentelemetry-agent.jar", "-Dspring.profiles.active=dev,console-logging", "-jar", "my-o11y-app.jar"]

다음으로 스프링부트 애플리케이션을 Maven이나 Gradle을 사용하여 빌드한 후, Docker를 활용해 컨테이너 이미지를 생성합니다. 생성된 이미지는 Docker Hub나 Amazon ECR과 같은 이미지 레지스트리로 업로드합니다. 마지막으로, Kubernetes 매니페스트 파일을 통해 Amazon EKS 클러스터에 애플리케이션을 배포합니다. 참고로 Ingress 혹은 Service 등의 로드밸런서를 활용하고자 하는 경우 로드밸런서의 Healthcheck 경로를 Actuator에서 설정한 경로로 설정해야 합니다.

6 단계: AMG 대시보드 설정하기

Amazon EKS 클러스터의 스프링부트 애플리케이션 배포와 관찰 가능성을 위한 수집기 설정이 완료됐습니다. 이제 시각화를 위해 AMG의 대시보드를 만들어보겠습니다.

먼저 스크랩퍼로 수집한 프로메테우스 정보를 활용하여 EKS 클러스터와 스프링부트 애플리케이션의 메트릭 대시보드를 만들어보겠습니다. 대시보드는 Grafana Dashboards에서 제공하는 템플릿을 활용했습니다.

그림11. 애플리케이션 메트릭 대시보드 구성 화면
그림12. 쿠버네티스 메트릭 대시보드 구성 화면

다음으로 CloudWatch의 로그와 X-Ray 트레이스 정보를 위한 대시보드를 설정합니다. 마찬가지로 Apps 메뉴의 AWS Data Source 메뉴를 사용하여 데이터소스를 추가하면 됩니다. 특히 CloudWatch 데이터 소스를 설정할 때, 로그와 트레이스 연동을 위해 X-ray trace link 설정을 추가합니다.

그림13. CloudWatch 설정에서 X-ray trace link 활성화
그림14. X-Ray 트레이스가 존재하는 로그를 출력하도록 패널 구성

X-Ray를 위한 대시보드를 생성합니다. Exploror를 통해서 X-Ray를 검색해보면 수집된 서비스맵을 쉽게 확인할 수 있고, 이를 바로 대시보드에 추가하는 방식으로 설정합니다.

그림15. X-Ray 트레이스 목록을 출력하도록 패널 구성

생성한 대시보드에는 서비스맵 외에도 같은 시간대에 발생한 Traces와 X-Ray 트레이스 ID가 삽입된 CloudWatch 로그를 필터링해서 보여주는 패널을 함께 구성할 수 있습니다. 예를 들어, CloudWatch 로그의 경우 아래처럼 CloudWatch Logs Insights 쿼리 구문을 이용해서 필터링합니다.

fields @timestamp, @message
| parse '* : *@*' as pre, trace_id
| filter ispresent(trace_id)
| sort @timestamp desc
| limit 100

아래는 기본적인 내용으로 구성한 X-Ray 대시보드 예시입니다. 이처럼 여러분은 더욱 다양하고 유용한 정보를 패널로 추가하여 X-Ray 대시보드를 구성할 수 있습니다.

그림16. 완성된 X-Ray 대시보드

리소스 정리하기

이번 블로그에서는 Amazon EKS에서 스프링부트 애플리케이션의 관찰 가능성을 구축하기 위한 AWS의 관리형 도구 사용 방법을 다루었습니다. 이러한 도구들은 관리가 용이하다는 장점이 있으며, 따라서 리소스의 삭제 및 정리 과정도 매우 간단합니다.

우선, ADOT 수집기는 EKS 콘솔의 Add-ons 메뉴에서 쉽게 관리할 수 있습니다. 여기서 ADOT 애드온의 설정을 변경하거나 애드온 자체를 삭제하면, 관련 리소스가 자동으로 업데이트 혹은 제거됩니다.

AMP 스크랩퍼의 경우, 현재 EKS 콘솔의 Observability 메뉴에서 상태 확인만 가능합니다. 따라서 블로그 작성 시점 기준으로 스크랩퍼의 삭제는 AWS CLI를 통해서만 실행할 수 있으며, 아래의 명령어를 사용하여 스크랩퍼를 제거할 수 있습니다.

aws amp delete-scraper --scraper-id <scraper-id>

결론

AWS의 관리형 도구를 활용하는 것은 관찰 가능성을 구축하는데 있어 효율적인 방법 중 하나입니다. 이러한 도구들은 설치와 유지 관리의 난이도를 낮춰주며, 운영의 편의성을 제공합니다. 물론, 메트릭 시각화를 위해 CloudWatch의 Container Insights를 사용하거나, 오픈 소스 도구를 활용하거나, 심지어 타사 솔루션을 사용하는 등 다양한 대안도 존재합니다. 그러나 각 방법은 특유의 장단점과 운영상의 고려사항을 가지고 있으므로, 사용자는 이러한 점들을 고려하여 최적의 선택을 해야 합니다. AWS가 제공하는 관리형 도구는 이러한 선택지 중 하나로, 관찰 가능성 구축에 있어 매우 유용한 옵션이 될 수 있습니다.

Jungseob Shin

Jungseob Shin

신정섭 Solutions Architect는 다양한 분야의 Backend 서버 개발 경험을 바탕으로 Startup 고객이 비즈니스 목표를 달성하도록 AWS 서비스의 효율적인 사용을 위한 아키텍처 설계 가이드와 기술을 지원하는 역할을 수행하고 있습니다. 컨테이너와 서버리스 기술에 관심이 많습니다.