[IT-방법] docker compose yml 모니터링 구축하기 – 안정적인 컨테이너 운영을 위한 관측 체계 구성법

docker-compose.yml 기본 문법를 설명하는 모니터링 구성 대표 이미지

왜 장애를 미리 알지 못하고 잠에서 깨야 할까요

새벽 3시, 갑작스러운 알림 소리에 눈을 뜹니다. 슬랙(Slack)에는 서버가 응답하지 않는다는 긴급 메시지가 올라와 있어요. 로그를 확인하니 특정 컨테이너가 메모리 부족으로 무한 재시작을 반복하고 있네요. 이런 상황은 운영자라면 누구나 한 번쯤 겪어봤을 법한 피곤한 일상이에요.

단순히 컨테이너가 ‘실행 중(Running)’이라고 해서 서비스가 정상이라고 믿는 것은 위험해요. 프로세스는 살아있지만, 내부 애플리케이션이 데드락에 걸려 실제 요청을 처리하지 못하는 상태가 얼마든지 발생할 수 있기 때문이죠. 진정한 의미의 관측은 서비스의 상태를 정의하고, 그 상태가 변했을 때 즉각 반응하는 것에서 시작해요.

결국 docker compose yml 모니터링의 목적은 문제가 터진 뒤에 수습하는 것이 아니라, 문제가 터지기 직전의 징후를 포착하여 운영자의 개입을 최소화하는 데 있어요. 오늘 이 글을 통해 야간 호출을 줄이고 안정적인 서비스를 유지하는 구체적인 방법들을 알아볼게요.

💡 알아두기
모니터링은 단순한 감시가 아니에요. 지표를 수집하고, 기준을 세우고, 알림을 보내는 일련의 체계를 만드는 과정이에요.
이 글에서는 다음과 같은 내용을 다뤄요.

  • 컨테이너의 건강 상태를 정의하는 Healthcheck 설정법
  • CPU와 메모리 같은 핵심 리소스 지표를 수집하는 구성
  • 장애 원인 파악을 위한 효율적인 로그 관리 전략
  • 불필요한 알림을 줄이는 똑똑한 알림 규칙 설계

관측 체계를 구축하기 전 갖춰야 할 기본 요소

무작정 모니터링 도구를 설치한다고 해서 모든 문제가 해결되지는 않아요. 무엇을, 어떤 주기로, 어떤 기준으로 볼 것인지에 대한 설계가 먼저 선행되어야 해요. 설계 없이 시작하면 나중에 너무 많은 알림 때문에 정작 중요한 신호를 놓치는 ‘알림 피로(Alert Fatigue)’에 빠지기 쉽거든요.

가장 먼저 결정해야 할 것은 관측 대상의 계층이에요. 인프라 수준의 리소스(CPU, RAM), 애플리케이션 수준의 상태(HTTP 응답), 그리고 이벤트 수준의 로그를 모두 고려해야 해요. 이 세 가지는 서로 보완 관계에 있어서 어느 하나만으로는 완벽한 진단이 불가능해요.

모니터링 방식별 특징 비교

구분 상태 점검 (Healthcheck) 지표 수집 (Metrics) 로그 수집 (Logs)
주요 목적 서비스 생존 여부 확인 자원 사용 추이 분석 상세 에러 원인 파악
확인 시점 즉각적인 상태 변화 지속적인 변화 흐름 문제 발생 직후 상세 분석
장점 설정이 간편하고 빠름 예측 가능한 장애 대응 가능 가장 구체적인 정보 제공
한계 성능 저하 현상은 알기 어려움 정확한 원인 파악은 어려움 데이터 양이 방대하여 비용 발생

운영 환경의 규모에 따라 선택 기준은 달라져요. 소규모 프로젝트라면 Docker Compose의 자체 기능을 최대한 활용하는 것이 경제적이지만, 컨테이너 개수가 수십 개를 넘어가기 시작하면 Prometheus(프로메테우스)나 Grafana(그라파나) 같은 전문적인 스택을 도입하는 것이 훨씬 유리해요.

⚠️ 주의
모든 지표를 다 수집하려는 욕심은 금물이에요. 데이터 저장 비용과 시스템 부하가 급격히 늘어날 수 있으니, 핵심 지표부터 단계적으로 확장하세요.

준비 과정에서 가장 중요한 것은 우선순위 설정이에요. 서비스가 죽었을 때 알림을 받는 것이 1순위라면, 메모리가 80%를 넘었을 때 알림을 받는 것은 2순위가 되어야 해요. 이 우선순위가 정해져야 나중에 알림 규칙을 설계할 때 혼란을 피할 수 있어요.

실무에 바로 적용하는 단계별 모니터링 구성법

이제 본격적으로 docker compose yml 모니터링을 위한 설정을 하나씩 적용해 볼게요. 이론적인 설명보다는 실제 YAML 파일에 어떻게 적어야 하는지, 그리고 그 설정이 어떤 의미를 갖는지 중심으로 설명할게요.

STEP 1. Healthcheck를 통한 서비스 생존 확인

가장 기본이 되는 것은 서비스가 단순히 떠 있는지를 넘어, 실제로 일을 할 수 있는 상태인지를 확인하는 거예요. Docker Compose 파일 내에 `healthcheck` 항목을 추가하여 이를 구현할 수 있어요.

단순히 프로세스가 떠 있는지만 보는 것이 아니라, 실제 HTTP 엔드포인트로 요청을 보내 응답을 확인하는 방식이 가장 권장돼요.

💡 알아두기
Healthcheck는 컨테이너가 ‘Unhealthy’ 상태가 되면, 오케스트레이션 도구(예: Docker Swarm)가 자동으로 컨테이너를 재시작하도록 유도할 수 있어요.

예를 들어, 웹 서버 서비스를 위한 설정은 다음과 같아요.


services:
  web-app:
    image: my-web-service:latest
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

여기서 `interval`은 점검 주기, `timeout`은 응답을 기다리는 최대 시간, `retries`는 연속으로 몇 번 실패해야 최종적으로 비정상(Unhealthy) 판정을 내릴지를 결정해요. 특히 start_period는 아주 중요해요. 애플리케이션이 부팅되는 동안에는 당연히 응답을 못 할 수 있으니, 초기 부팅 시간을 충분히 확보해 주어야 불필요한 재시작 루프를 방지할 수 있어요.

STEP 2. cAdvisor를 활용한 리소스 지표 수집

서비스가 느려지는 원인이 메모리 누수인지, CPU 과부하인지 알려면 리소스 사용량을 수집해야 해요. 이를 위해 가장 많이 쓰이는 도구가 바로 cAdvisor예요. cAdvisor는 실행 중인 모든 컨테이너의 CPU, 메모리, 네트워크 사용량을 실시간으로 수집해서 보여주는 에이전트 역할을 해요.

Docker Compose 파일에 cAdvisor를 서비스로 추가하면 별도의 설치 없이 바로 지표를 뽑아낼 수 있어요.


services:
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    container_name: cadvisor
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro

이렇게 구성하면 cAdvisor가 호스트 시스템의 도커 엔진에 접근하여 각 컨테이너의 상세 지표를 긁어 모아요. 이 데이터는 나중에 Prometheus 같은 시계열 데이터베이스에 저장되어 Grafana 대시보드에서 예쁜 그래프로 그려지게 되죠. 이때 주의할 점은 볼륨 마운트 설정이에요. cAdvisor가 시스템 정보를 읽을 수 있도록 호스트의 주요 경로들을 읽기 전용(ro)으로 잘 연결해 주어야 해요.

STEP 3. 중앙 집중형 로그 수집 체계 구축

지표가 ‘무엇이 일어났는가’를 말해준다면, 로그는 ‘왜 일어났는가’를 말해줘요. 컨테이너 환경에서는 컨테이너가 삭제되면 그 안의 로그도 같이 사라지기 때문에, 반드시 외부로 로그를 빼내는 작업이 필요해요.

가장 가벼운 방법은 Docker의 `json-file` 로그 드라이버를 사용하는 것이지만, 운영 규모가 커지면 Loki(로키)나 ELK 스택을 사용하는 것이 좋아요. 특히 Loki는 Grafana와 궁합이 매우 좋아서 설정이 간편하다는 장점이 있어요.

로그 수집을 할 때는 다음 세 가지를 반드시 고려하세요.

  • 로그 로테이션(Rotation): 로그 파일이 디스크를 가득 채우지 않도록 주기적으로 관리해야 해요.
  • 로그 레벨(Level): DEBUG, INFO, WARN, ERROR를 명확히 구분하여 수집해야 나중에 검색이 빨라요.
  • 컨텍스트(Context): 어떤 컨테이너의 어떤 서비스에서 발생한 로그인지 메타데이터를 반드시 포함해야 해요.

STEP 4. 장애 대응을 위한 알림 규칙(Alerting) 설계

모든 준비가 끝났다면 이제 알림을 설정할 차례예요. 하지만 단순히 “CPU가 높으면 알려줘”라고 설정하면 안 돼요. 1분 동안 잠깐 튀는 CPU 사용량 때문에 알림이 울린다면 운영자는 금방 피로해질 거예요.

효과적인 알림 규칙을 위한 시나리오 예시를 들어볼게요.

시나리오 A: 메모리 부족 예방
“컨테이너의 메모리 사용량이 80% 이상인 상태가 5분 동안 지속될 경우, Slack으로 경고 알림을 보낸다.”
이렇게 지속 시간(Duration) 조건을 넣는 것이 핵심이에요. 일시적인 스파이크는 무시하고, 진짜 문제가 있는 상황에만 반응하도록 만드는 것이죠.

시나리오 B: 서비스 중단 대응
“Healthcheck 결과가 Unhealthy로 변한 컨테이너가 발견되면, 즉시 담당자에게 긴급 전화를 보낸다.”
이것은 즉각적인 조치가 필요한 ‘Critical’ 등급의 알림이에요.

이렇게 알림의 등급을 나누고, 각 등급에 맞는 채널(Slack, 이메일, 전화)을 지정하는 것이 실무적인 관측 체계의 완성이에요.

💡 알아두기
알림은 ‘무엇을 해야 할지’를 함께 적어두는 것이 좋아요. 예를 들어, ‘메모리 부족 알림’과 함께 ‘컨테이너 로그 확인 및 메모리 제한 설정값 검토’라는 가이드를 같이 보내면 대응 속도가 훨씬 빨라져요.

자주 하는 실수와 해결법

실무에서 모니터링을 구축하다 보면 의도치 않은 문제에 직면하곤 해요. 가장 빈번하게 발생하는 사례들을 정리했으니, 여러분의 설정과 비교해 보세요.

실수: Healthcheck 주기를 너무 짧게 설정함
왜 발생하는가: 장애를 빨리 감지하고 싶은 마음에 `interval`을 1초나 2초로 설정해요. 이 경우 컨테이너 내부에서 체크를 위한 프로세스가 너무 자주 실행되어 오히려 CPU 사용량이 치솟는 배보다 배꼽이 더 큰 상황이 생겨요.
해결법: 서비스의 특성에 따라 다르지만, 보통 30초에서 1분 사이가 적당해요. 서비스의 중요도가 매우 높다면 10초 정도로 타협할 수 있어요.

실수: 로그 로테이션 설정을 누락함
왜 발생하는가: 처음에는 로그 용량이 작아서 눈에 띄지 않지만, 서비스가 커지면 순식간에 디스크를 점유해요. 결국 디스크 풀(Disk Full)로 인해 시스템 전체가 멈추게 되죠.
해결법: Docker Compose의 `logging` 옵션을 사용하여 `max-size`와 `max-file`을 반드시 지정하세요.

실수: 알림 조건에 ‘지속 시간’을 넣지 않음
왜 발생하는가: 순간적인 네트워크 지연이나 일시적인 부하로 인해 발생하는 스파이크(Spike)에 모두 반응하게 돼요. 이로 인해 운영자는 알림을 무시하게 됩니다.
해결법: 알림 규칙에 `for: 5m` 처럼 일정 시간 동안 조건이 유지될 때만 알림이 가도록 설정하세요.

실수: 리소스 제한(Limits)을 설정하지 않음
왜 발생하는가: 모니터링은 상태를 보는 것이지, 상태를 제어하는 것이 아니에요. 특정 컨테이너가 자원을 다 써버리면 모니터링 도구조차 작동하지 않을 수 있어요.
해결법: `deploy.resources.limits` 설정을 통해 각 컨테이너가 사용할 수 있는 최대 자원을 엄격히 제한하세요.

실수: 모니터링 도구 자체의 가용성을 고려하지 않음
왜 발생하는가: 모니터링 서버가 돌아가는 서버가 죽으면, 장애가 발생해도 알림을 받을 수 없어요.
해결법: 가능하면 모니터링 스택은 애플리케이션 서버와 분리된 별도의 노드에 구축하는 것이 안전해요.

자주 묻는 질문

Q. docker compose 명령어로도 모니터링이 가능한가요?

docker compose ps 명령어를 통해 현재 컨테이너의 상태와 Healthcheck 결과는 확인할 수 있어요. 하지만 이는 일시적인 확인용일 뿐, 추세를 보거나 과거의 장애 기록을 추적하는 용도로는 한계가 명확해요.

Q. Healthcheck를 설정하면 성능이 많이 떨어지나요?

애플리케이션 내부에서 `curl`이나 `wget`을 실행하는 방식은 아주 미세한 자원을 소모해요. 하지만 적절한 `interval`과 `timeout`을 설정한다면 서비스 운영에 지장을 줄 정도의 부하는 거의 발생하지 않으니 안심하고 사용하셔도 돼요.

Q. 로그 용량이 너무 큰데, 모든 로그를 다 저장해야 할까요?
모든 로그를 저장하는 것은 비용 측면에서 매우 비효율적이에요. ERROR 레벨의 로그는 최대한 오래 보관하고, INFO나 DEBUG 레벨은 짧은 기간(예: 3일)만 보관하도록 보관 정책(Retention Policy)을 세우는 것이 실무적인 방법이에요.

Q. 리소스 제한을 걸면 서비스가 갑자기 죽지 않을까요?
메모리 제한에 도달하면 리눅스 커널의 OOM(Out Of Memory) Killer가 해당 컨테이너를 강제로 종료할 수 있어요. 그래서 모니터링을 통해 메모리 사용량이 제한치에 근접할 때 미리 알림을 받고, 리소스 설정을 조정하는 과정이 꼭 필요해요.

Q. 알림 채널은 무엇이 가장 좋나요?
긴급한 장애는 전화나 문자, 일반적인 경고는 Slack이나 Teams 같은 협업 도구로 분류하는 것이 좋아요. 모든 것을 문자로 받으면 결국 중요한 알림을 놓치게 됩니다.

안정적인 운영을 위한 지속적인 실천

모니터링 체계를 구축하는 것은 끝이 아니라 시작이에요. 시스템은 계속 변하고, 새로운 장애 유형은 언제든 나타날 수 있으니까요. 오늘 배운 내용들을 바탕으로 작은 것부터 하나씩 적용해 보시길 권장해요.

✅ 핵심 요약

  • Healthcheck로 서비스의 실질적인 생존 여부를 정의하세요.
  • cAdvisor 같은 도구를 사용하여 리소스 사용량 지표를 확보하세요.
  • 로그는 반드시 외부로 추출하고 로테이션 설정을 잊지 마세요.
  • 알림에는 반드시 ‘지속 시간’ 조건을 넣어 알림 피로를 방지하세요.
  • 컨테이너 리소스 제한을 설정하여 상호 간섭을 막으세요.

지금 당장 모든 것을 완벽하게 만들려고 할 필요는 없어요. 다음과 같은 단계로 천천히 나아가 보세요.

  • 오늘 할 일: 현재 운영 중인 주요 서비스의 `docker-compose.yml`에 기본 Healthcheck를 추가해 보세요.
  • 이번 주 할 일: 핵심 지표 3가지(CPU, RAM, Disk)를 정하고, 이를 감시할 수 있는 알림 규칙을 하나만 만들어 보세요.
  • 실행 직전 할 일: 알림이 왔을 때 담당자가 즉시 확인하고 조치할 수 있는 매뉴얼이 준비되어 있는지 체크해 보세요.

핵심 지표 3가지만 먼저 정하고 알림을 걸어 보세요. 그것만으로도 여러분의 야간 수면 질이 달라질 거예요. 안정적인 운영은 화려한 도구가 아니라, 꼼꼼한 관찰과 적절한 대응에서 나옵니다.

더 깊이 있는 도커 운영 지식이 궁금하다면 도커 컴포즈 기본 개념 완벽 정리 — 개념부터 실무 활용까지 한눈에 보는 가이드를 참고해 보세요.

댓글 남기기