Skip to main content
duksoo.dev
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

EKS에 LGTM 스택 구축하기

Observability는 선택이 아니라 필수다. 하지만 SaaS 모니터링 비용이 인프라 비용보다 높아지는 순간이 온다. 그때가 자체 구축을 고민할 타이밍이다.

Datadog을 메인으로 사용하고 있었지만, 모든 환경에 적용하기엔 비용 부담이 있었다. Observability가 아예 없는 환경이 생기는 것보다는, 오픈소스로라도 갖추는 게 낫다고 판단했다. LGTM 스택(Loki, Grafana, Tempo, Mimir)을 EKS에 구축한 과정을 공유한다.

배경

Datadog을 메인으로 사용하고 있지만, 모든 환경에 적용하기엔 비용 부담이 있었다. 특히 작은 규모의 계정들은 Observability가 아예 없는 상태로 운영되고 있었다.

Read full post gdoc_arrow_right_alt

Grafana 대시보드 구축

메트릭 수집은 Observability의 절반에 불과하다. 나머지 절반은 시각화다. 데이터가 쌓여도 볼 수 없으면 의미가 없다.

LGTM 스택을 구축했지만 대시보드가 없었다. 커뮤니티 대시보드를 import 해봤지만 우리 환경과 맞지 않았다. 결국 운영 관점에서 필요한 대시보드를 직접 설계하고 구축했다. GitOps로 대시보드를 관리하는 방식도 함께 정리한다.

어떤 대시보드가 필요한가

운영 관점에서 세 가지가 필요했다.

  1. 인프라 대시보드: 클러스터 전체 상태, 노드 헬스, 리소스 사용량
  2. APM 대시보드: 서비스별 요청량, 에러율, 레이턴시
  3. 파이프라인 대시보드: LGTM 스택 자체의 헬스 체크

Datadog을 쓸 때는 기본 제공되던 것들이다. LGTM 스택에서는 직접 구성해야 한다.

Read full post gdoc_arrow_right_alt

GraalVM Native 이미지로 스케일 아웃 최적화하기

JVM의 Cold Start는 순간 트래픽 상황에서 치명적이다. 스케일 아웃이 되어도 새 Pod가 준비되기까지 시간이 걸리면 이미 늦는다. GraalVM Native Image는 이 문제를 해결한다.

광고 푸시 후 순간 트래픽이 몰리는 서비스에 GraalVM Native 이미지를 적용했다. 개발자가 애플리케이션을 만들고, 나는 CI/CD 파이프라인 구축과 배포, 부하 테스트를 담당했다. 빌드 시간과 이미지 크기를 줄이면서 보안 규격까지 맞춘 과정을 공유한다.

서비스 특성

이 서비스는 광고성 메시지를 대량으로 발송한 직후 트래픽이 급증한다. 사용자들이 링크를 클릭하면 반드시 이 서버를 거쳐야 하는 구조다.

Read full post gdoc_arrow_right_alt

Mimir Alertmanager로 알림 구축

Observability의 최종 목표는 MTTD(Mean Time To Detect)를 줄이는 것이다. 대시보드가 아무리 훌륭해도 24시간 지켜볼 수는 없다. Push 기반 알림이 있어야 문제를 빠르게 인지할 수 있다.

LGTM 스택에서 Mimir Ruler와 Alertmanager를 활용해 알림 시스템을 구축했다. 알림 룰을 GitOps로 관리하고, 알림 폭탄을 방지하기 위한 설계 포인트를 정리한다.

알림 아키텍처

flowchart LR
    subgraph GitOps[GitOps 관리]
        Git[Git Repository]
        CM[ConfigMap]
    end

    subgraph Mimir[Mimir]
        Ruler[Ruler<br/>PromQL 평가]
        Storage[(Metrics<br/>Storage)]
        AM[Alertmanager<br/>라우팅/그룹핑]
    end

    subgraph Grafana[Grafana]
        AlertUI[Alerting UI<br/>알림 현황 조회]
    end

    subgraph Slack[Slack]
        Ch1[#alerts-service]
        Ch2[#alerts-infra]
    end

    Git -->|Helm Deploy| CM
    CM -->|Alert Rules| Ruler
    Storage -->|메트릭 쿼리| Ruler
    Ruler -->|알림 발생| AM
    AM -->|namespace: app| Ch1
    AM -->|namespace: observability| Ch2
    AM -->|알림 상태| AlertUI

Ruler가 주기적으로 메트릭을 쿼리하고, 조건이 충족되면 Alertmanager로 알림을 보낸다. Alertmanager는 알림을 그룹핑하고, 라우팅 규칙에 따라 적절한 Slack 채널로 전송한다. Grafana에서는 현재 발생 중인 알림을 조회하고 히스토리를 확인할 수 있다.

Read full post gdoc_arrow_right_alt

JVM Pod 재시작 시 초기 요청 실패, StartupProbe로 해결하기

Kubernetes에서 JVM 애플리케이션은 시작이 느리다. Pod가 뜨고 컨테이너가 Running 상태가 되어도, JVM이 준비되기까지는 시간이 더 걸린다. 이 간극을 무시하면 초기 요청이 실패한다.

Karpenter 노드 정리로 Pod가 재스케줄링될 때마다 초기 API 요청이 타임아웃으로 실패하는 문제가 있었다. ReadinessProbe만으로는 부족했다. StartupProbe와 전용 엔드포인트를 도입해서 해결한 과정을 공유한다.

문제 상황

새벽에 Karpenter가 비용 최적화를 위해 유휴 노드를 정리하면서 Pod가 다른 노드로 이동했다. Pod 재시작 자체는 정상이었지만, 재시작 직후 들어온 요청들이 실패했다.

Read full post gdoc_arrow_right_alt

Liveness Probe가 서비스를 죽인 날

Liveness Probe는 죽은 Pod를 살리기 위한 것이다. 그런데 잘못 설정하면 멀쩡한 Pod를 죽이는 도구가 된다.

이론적으로는 알고 있었다. Kubernetes Probe 3종류에서도 “LivenessProbe는 단순하게"라고 정리했다. 그런데 실제로 겪고 나니 체감이 다르다. Karpenter 노드 교체와 무거운 Liveness Probe가 만나면서 연쇄 재시작이 발생했다. Datadog 메트릭으로 타임라인을 복원하고 원인을 분석한 과정을 공유한다.

증상

아침에 5xx 알람이 터졌다. Spring Boot API 서버에서 약 15분간 간헐적 에러가 발생했다.

Read full post gdoc_arrow_right_alt

EKS 1.32 → 1.33 업그레이드 실전 가이드

EKS 1.33이 릴리스됐다. 보통 마이너 버전 업그레이드는 “Control Plane 올리고, Addon 올리고, Node 올리면 끝"이라고 생각하기 쉽다. 나도 그렇게 생각했다.

dev 환경에서 먼저 작업하면서 예상치 못한 문제들을 만났다. VPC CNI 설정 불일치로 Pod IP 할당이 안 되고, Karpenter CRD 버전 문제로 노드 프로비저닝이 막히고, Datadog DD_HOSTNAME 누락으로 모니터링이 깨졌다.

dev에서 삽질한 덕분에 prod는 40분 만에 깔끔하게 끝냈다. 그 과정을 공유한다.

환경 구성

환경 노드 구성 특이사항
dev MNG + Karpenter Self-managed Addons
prod MNG + Karpenter Self-managed Addons

두 환경 모두 Self-managed Addon 방식이다. EKS managed addon이 아니라 직접 이미지 버전을 관리한다. 이게 업그레이드 시 추가 작업이 필요한 이유다.

Read full post gdoc_arrow_right_alt

플랫폼 ECS → EKS 마이그레이션, 가중치 전환으로 무중단 완료하기

컨테이너 오케스트레이션 플랫폼을 바꾸는 건, 비행 중에 엔진을 교체하는 것과 같다. 핵심은 “어떻게 전환할 것인가"다. 한 번에 스위칭하면 빠르지만 위험하고, 너무 느리면 두 환경을 동시에 운영하는 비용이 커진다.

플랫폼 서버를 ECS에서 EKS로 마이그레이션했다. Big Bang 전환 대신 가중치 기반 점진적 트래픽 전환 전략을 택했다. 99:1에서 시작해 0:100까지, 각 단계마다 모니터링하고 이상이 없을 때만 다음 단계로 넘어가는 방식이다. 결과적으로 에러 없이 무중단으로 전환을 완료했다. 그 과정을 공유한다.

전환 전략 설계

왜 가중치 전환인가

마이그레이션 전환 방식은 크게 세 가지가 있다.

Read full post gdoc_arrow_right_alt

IRSA 완전 정복: EKS Pod가 AWS 서비스에 접근하는 원리

EKS에서 Pod가 S3에 파일을 올리거나 SQS에 메시지를 보내려면 AWS 자격 증명이 필요하다. 예전에는 AWS Access Key를 환경변수나 ConfigMap에 넣어서 해결했다. 동작은 하지만, 키가 유출되면 누구나 해당 권한을 사용할 수 있고, 키 로테이션도 수동이다.

IRSA(IAM Roles for Service Accounts)는 이 문제를 근본적으로 해결한다. Kubernetes의 ServiceAccount와 AWS IAM Role을 OIDC 프로토콜로 연결해서, Pod에 임시 자격 증명을 자동으로 주입한다. 키를 코드에 넣을 필요가 없고, 토큰은 자동 갱신되며, 네임스페이스 단위로 권한을 분리할 수 있다.

Read full post gdoc_arrow_right_alt

External Secrets Operator: K8s에서 시크릿을 관리하는 두 가지 접근

K8s 환경에서 앱이 DB 비밀번호나 API 키 같은 시크릿을 사용하려면, 어딘가에서 가져와야 한다. 이 “어딘가"와 “가져오는 방식"에 따라 아키텍처가 달라진다.

크게 두 가지 접근이 있다. 앱이 AWS API를 직접 호출해서 읽는 방식과, K8s Operator가 대신 읽어서 환경변수로 넣어주는 방식이다. 전자는 Parameter Store 직접 읽기, 후자는 External Secrets Operator다. 각각의 동작 원리와 트레이드오프를 정리한다.

방식 1: 앱이 직접 읽기 (Parameter Store)

Spring Boot 기준으로, Spring Cloud AWS가 제공하는 Parameter Store 통합 기능을 사용하는 방식이다.

Read full post gdoc_arrow_right_alt