이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Spring 백엔드 코드가 실제 운영 서비스가 되기까지 어떤 단계를 거치는가?
  • 각 단계에서 남겨야 하는 산출물과 운영 증거는 무엇인가?
  • 배포 직후 장애가 났을 때 무엇을 먼저 멈추고 무엇을 확인해야 하는가?

개요

개발에서 운영까지의 흐름은 “코드를 서버에 올린다”로 끝나지 않는다.

Spring 애플리케이션은 commit, build, test, artifact, 설정, 배포, 트래픽 연결, 관측, 복구 절차를 통과해야 사용자 요청을 받을 수 있는 운영 서비스가 된다.

이 흐름을 모르면 장애가 났을 때 “방금 배포한 코드가 문제인지”, “운영 설정이 문제인지”, “Nginx나 Load Balancer가 새 인스턴스를 바라보지 않는지”, “DB migration이 먼저 실패했는지”를 분리하지 못한다.

전체 흐름

운영 흐름은 다음처럼 볼 수 있다.

commit
  build and test
    versioned artifact
      runtime config and secret
        deploy to server or container
          health check and traffic routing
            logs, metrics, traces, alerts
              rollback, roll forward, mitigation, restore

각 단계는 다음 단계의 입력이 된다.

Build가 재현되지 않으면 배포할 artifact를 신뢰할 수 없다.

Config가 분리되지 않으면 같은 artifact를 dev, staging, prod에 안전하게 올릴 수 없다.

Health check가 없으면 트래픽을 붙여도 되는 인스턴스인지 판단하기 어렵다.

관측 신호가 없으면 rollback이 필요한지, 조금 더 기다려야 하는지, 특정 기능만 차단해야 하는지 결정할 수 없다.

단계별 산출물

개발 단계의 산출물은 단순 코드가 아니다.

  • merge된 commit hash
  • 변경 요약
  • 관련 이슈나 요구사항
  • DB migration 포함 여부
  • feature flag 필요 여부
  • 배포 후 확인할 API

Build 단계의 산출물은 재현 가능한 artifact다.

  • jar 파일
  • Docker image
  • image tag
  • SBOM이나 dependency 목록
  • 테스트 결과
  • 빌드 로그

Deploy 단계의 산출물은 운영 환경에 반영된 버전과 설정이다.

  • 배포된 artifact 버전
  • Spring profile
  • 환경 변수와 Secret 참조
  • 노출 port
  • Nginx upstream 또는 Load Balancer target
  • DB migration 적용 결과

Observe 단계의 산출물은 판단 가능한 신호다.

  • /actuator/health 상태
  • HTTP 5xx 비율
  • latency p95/p99
  • JVM memory와 GC
  • Hikari pool active/pending
  • 주요 에러 로그
  • trace id 또는 correlation id

Recover 단계의 산출물은 되돌리거나 우회할 수 있는 절차다.

  • 이전 image tag
  • rollback 명령
  • traffic shift 방법
  • feature flag off 방법
  • read-only mode 전환 조건
  • restore 또는 forward fix 판단 기준

Release Note 예시

운영 가능한 배포는 release note가 짧아도 판단에 필요한 정보를 담아야 한다.

service: order-api
environment: prod
version: 2026.06.30-3f21a9c
changed:
  - 주문 목록 cursor pagination 적용
  - orders(member_id, created_at, id) 인덱스 추가 migration 포함
verify:
  - GET /actuator/health
  - GET /api/orders?memberId=10&cursor=...
watch:
  - http.server.requests p95
  - jdbc.connections.pending
  - 5xx rate
rollback:
  - image tag 2026.06.29-a819e00
  - migration은 additive change라 rollback 불필요

이 정도 정보가 있으면 장애 중 최근 변경과 관측 지표를 연결할 수 있다.

Spring 백엔드 개발자의 책임

백엔드 개발자는 서버 전체를 직접 운영하지 않더라도 운영 흐름의 핵심 입력을 만든다.

Spring profile을 잘못 설계하면 prod에서 dev DB를 바라보는 사고가 날 수 있다.

Actuator health endpoint가 DB나 외부 API 상태를 어떻게 반영하는지 정하지 않으면 Load Balancer가 잘못된 인스턴스에 트래픽을 보낼 수 있다.

로그에 request id가 없으면 특정 사용자 오류를 운영 로그에서 찾기 어렵다.

DB migration을 코드 배포와 함께 묶으면 rolling 배포 중 구버전 코드가 새 스키마를 견디는지 확인해야 한다.

배포 직후 확인 순서

배포 직후에는 감각보다 순서를 따른다.

  1. 배포 대상 환경과 버전이 맞는지 확인한다.
  2. 새 인스턴스의 health check가 통과하는지 본다.
  3. smoke test API를 호출한다.
  4. error rate와 latency p95/p99가 기준선을 벗어나는지 본다.
  5. 주요 로그에 새 오류 패턴이 생겼는지 확인한다.
  6. DB migration, batch, cache warm-up이 같이 움직였는지 확인한다.
  7. 문제가 있으면 추가 배포와 자동 배치를 멈춘다.
curl -fsS https://api.example.com/actuator/health
curl -fsS https://api.example.com/actuator/prometheus | grep 'http_server_requests'
docker image ls | grep order-api

명령 출력은 실행 시각, 대상 환경, 기대값과 함께 남겨야 장애 회고에서 재사용할 수 있다.

장애 신호

  • 배포 직후 특정 endpoint의 5xx가 증가한다.
  • health check는 통과하지만 smoke test가 실패한다.
  • 새 버전 로그에 같은 exception이 반복된다.
  • latency p95는 증가했는데 CPU는 낮고 connection pool pending이 오른다.
  • Nginx access log에는 502가 보이지만 Spring 로그에는 요청이 없다.
  • 배포된 버전과 release note에 적힌 버전이 다르다.
  • migration은 성공했다고 보이지만 구버전 애플리케이션이 컬럼 오류를 낸다.

이 신호들은 모두 “코드 문제” 하나로 묶으면 안 된다.

배포 경로, 설정, 프록시, DB, 관측 누락을 나누어 봐야 한다.

안전한 완화 조치

장애 중 첫 목표는 원인 맞히기가 아니라 피해 확산 방지다.

  • 신규 배포와 자동 배치를 멈춘다.
  • 문제가 되는 feature flag를 끈다.
  • 영향 endpoint에 rate limit을 건다.
  • 트래픽을 이전 버전이나 정상 인스턴스로 돌린다.
  • 읽기 기능만 열 수 있으면 read-only mode를 검토한다.
  • DB 변경이 포함되어 있으면 rollback보다 forward fix가 안전한지 먼저 판단한다.

하지 말아야 할 대응도 분명하다.

  • 로그를 보지 않고 timeout만 늘리지 않는다.
  • pool size를 즉시 키워 DB 병목을 더 키우지 않는다.
  • 설정을 여러 개 동시에 바꾸지 않는다.
  • 복구 가능성을 확인하지 않고 destructive migration을 실행하지 않는다.
  • 장애 중 원인 추정만 공유하고 사용자 영향과 완화 상태를 빼먹지 않는다.

인프라 담당자와 공유할 자료

인프라 담당자에게는 추상적인 설명보다 시간과 증거를 준다.

14:05에 order-api 2026.06.30-3f21a9c를 prod에 배포했습니다.
14:08부터 POST /api/orders 5xx가 0.1%에서 4.8%로 증가했습니다.
새 버전의 Spring profile은 prod이며 DB migration V42가 포함되어 있습니다.
Nginx access log에는 502와 504가 섞여 있고, Spring 로그에는 Hikari connection timeout이 보입니다.
현재 신규 배포와 coupon-backfill batch는 중지했습니다.
확인 요청: 해당 시간대 LB target health와 DB connection saturation을 같이 봐주세요.

이 정보는 인프라가 Load Balancer, 서버 자원, DB 연결, 네트워크 경로를 빠르게 좁히게 만든다.

실전 팁

  • 배포 문서는 성공 명령보다 실패 시 확인 순서를 먼저 적는다.
  • release note에는 변경 내용보다 관찰할 지표와 rollback 조건을 반드시 넣는다.
  • smoke test는 로그인, 핵심 조회, 핵심 쓰기처럼 사용자 흐름과 가까워야 한다.
  • Spring profile, Secret, DB URL은 artifact 안에 고정하지 않고 환경에서 주입한다.
  • 장애 회고에는 “어느 단계에서 증거가 부족했는가”를 남긴다.

위험 신호!

  • prod에 올라간 artifact의 commit hash를 모른다.
  • 배포 후 health check만 보고 사용자 API를 확인하지 않는다.
  • 운영 설정이 콘솔 수동 변경과 repo 파일에 나뉘어 있다.
  • rollback 방법이 문서가 아니라 담당자 기억에만 있다.
  • 로그, metric, trace가 release version과 연결되지 않는다.

확인 질문

확인 질문

  • 개발에서 운영까지 흐름을 단계로 나누는 이유는 무엇인가?
    • artifact, 설정, 배포 경로, 관측, 복구 중 어느 단계가 실패했는지 나눠야 대응이 달라지기 때문이다.
  • 배포 직후 장애에서 가장 먼저 멈춰야 할 것은 무엇인가?
    • 추가 배포, 자동 배치, 재시도 폭주처럼 장애를 키울 수 있는 변경과 유입을 먼저 멈춰야 한다.
  • release note에 rollback 정보를 적어야 하는 이유는 무엇인가?
    • 장애 중 이전 버전, DB 변경 호환성, traffic 전환 방법을 즉시 판단하기 위해서다.

참고 문서