"이 커밋 왜 여기 있어요?" — 로그가 지저분해지는 순간 팀은 신뢰를 잃는다 필자가 일 평균 주문 8만 건을 처리하는 커머스 프로젝트에서 결제 모듈을 담당하던 시절, 어느 배포 이후 특정 할인 쿠폰 조합에서만 최종 결제 금액이 미세하게 틀어지는 회귀 버그가 접수된 적이 있습니다.
카테고리
DevOps
총 15편의 글
CI/CD, Kubernetes, GitOps, 관측성, 컨테이너 보안처럼 배포 이후의 안정성을 만드는 운영 기술을 다룹니다.
- 적용 대상
- 배포 파이프라인과 운영 플랫폼을 관리하는 DevOps·플랫폼 개발자
- 주요 초점
- 배포 안정성관측성운영 자동화
인프라가 "코드"라면, 그 코드의 상태를 누가 책임지는가 Terraform을 처음 도입한 팀이 가장 빨리 맞닥뜨리는 위기는 terraform apply 를 두 사람이 동시에 실행하는 순간입니다. 우리 팀의 플랫폼 팀에서 정확히 이 상황이 벌어졌습니다. SRE 한 명이 EKS 노드 그룹 스케일아웃을 적용하는 동안, 다른 팀원이 보안 그룹 규칙을 추가했습니다.
커널 수준에서 패킷을 들여다보는 것이 왜 중요한가 쿠버네티스 클러스터를 운영하다 보면 "이 파드 간 통신이 왜 실패하는가"라는 질문 앞에서 막막함을 느낄 때가 있습니다. kubectl logs 에는 아무런 에러가 없고, kubectl describe pod 를 봐도 이상이 없습니다. 그런데 A 서비스가 B 서비스를 호출하면 간헐적으로 연결이 끊깁니다.
클러스터가 10개로 늘어나는 순간, 수동 배포는 채무가 된다 운영 팀이 단일 Kubernetes 클러스터에 하나의 ArgoCD로 운영하던 시절, 배포는 어렵지 않았습니다. dev , staging , prod 네임스페이스를 나누고 ArgoCD Application을 손으로 만들면 됐습니다.
Kubernetes에 배포할 때 YAML 파일을 그대로 복사해 환경마다 고치고 있다면, 이미 문제가 시작됐다 내부 팀이 처음 Helm을 도입한 프로젝트는 결제 플랫폼 마이크로서비스 12개를 Kubernetes 위에서 운영하는 환경이었습니다. 초기에는 각 서비스마다 deployment.yaml , service.yaml , configmap.
장애는 끝난 뒤부터 팀의 실력이 드러난다 서비스 장애가 발생하면 팀은 복구에 집중합니다. 알림이 울리고, 대시보드를 열고, 로그를 뒤지고, 임시 조치를 적용합니다. 하지만 진짜 중요한 일은 장애가 끝난 뒤 시작됩니다.
로그는 문자열이 아니라 사건 기록이다 장애가 나면 가장 먼저 로그를 봅니다. 하지만 많은 서비스의 로그는 정작 장애 순간에 도움이 되지 않습니다. "error occurred" 같은 메시지만 남아 있고, 어떤 사용자 요청인지, 어떤 주문인지, 어떤 외부 API 호출과 연결되는지 알 수 없습니다. 반대로 너무 많은 로그가 쌓여 중요한 신호가 묻히기도 합니다.
컨테이너는 작을수록 안전하다 Dockerfile이 동작한다고 해서 운영에 안전한 이미지는 아닙니다. 빌드 도구, 패키지 매니저, shell, curl, 테스트 파일, 캐시, 심지어 빌드 시 사용한 token이 runtime image에 남는 경우가 많습니다.
시크릿은 환경변수에 넣는 순간 끝난 것이 아니다 데이터베이스 비밀번호, API token, OAuth client secret, webhook signing key, cloud access key는 모두 서비스의 혈관입니다. 그런데 많은 팀에서 시크릿 관리는 배포 설정의 부속품처럼 다뤄집니다. .
오토스케일링은 자동이지만 자동으로 안전해지지는 않는다 Kubernetes를 쓰면 트래픽이 늘어날 때 Pod가 자동으로 늘어나고, 노드가 부족하면 클러스터도 알아서 커질 것처럼 느껴집니다.
장애는 로그 한 줄로 설명되지 않는다 운영 장애를 처음 겪는 팀은 대부분 로그부터 찾습니다. 에러 로그가 있으면 원인이 보일 것이라고 기대합니다. 하지만 실제 장애는 그렇게 친절하지 않습니다. 결제 API의 p95 지연 시간이 300ms에서 3초로 튀었는데 애플리케이션 로그에는 에러가 없습니다.
Redis는 너무 무거웠다 — stick-table을 다시 본 계기 2024년 말, 필자의 경험으로는 B2B SaaS 플랫폼의 API 레이어 앞단을 대대적으로 정비했습니다. 당시 Rate Limiting 구현체는 Redis를 중앙 카운터 저장소로 쓰는 전형적인 구조였습니다.
브라우저가 naver.com에 요청을 보낼 때, 실제로 TCP 연결을 받고 응답을 돌려주는 서버가 naver.com 오리진 서버가 아닐 수 있습니다. 수십 개의 오리진 서버 앞에 조용히 앉아 있는 리버스 프록시가 요청을 받고, SSL을 해제하고, 헤더를 덧붙이고, 가장 한가한 백엔드로 넘겨줍니다. 클라이언트는 이 중간 행위자의 존재를 전혀 알지 못합니다.
1부에서 리버스 프록시가 어떤 원리로 클라이언트와 오리진 사이에 끼어드는지, TCP 커넥션 재사용과 헤더 재작성이 왜 중요한지를 살펴봤다면(리버스 프록시 원리 가이드(1부)), 2부인 이 글에서는 실제 트래픽을 받는 서버를 손으로 세웁니다. 이론을 알고 있어도 설정 파일 한 줄 차이로 서비스가 무너지는 경험은 누구나 합니다. 우리 팀도 그랬습니다.
GitHub Actions: 개발 워크플로우를 바꾼 자동화 환경 소프트웨어 개발 프로세스에서 "빌드하고 배포하는 일" 은 개발의 본질이면서도, 동시에 가장 개발자를 지치게 만드는 노동이었습니다.