왜 스테이지 순차 실행이 문제인가

GitLab CI의 기본 모델은 스테이지 단위로 파이프라인을 진행한다. build → test → deploy 순서라면, build 스테이지의 모든 잡이 끝나야 test 스테이지가 시작된다. 이 규칙은 직관적이지만, 서로 무관한 잡까지 같은 스테이지의 낙오자(straggler)를 기다리게 만든다.

예를 들어 프런트엔드 빌드가 2분, 백엔드 빌드가 8분 걸린다면, 프런트엔드 테스트는 이미 준비됐는데도 백엔드 빌드가 끝날 때까지 6분을 낭비한다. 스테이지가 많아질수록 이 대기 시간은 누적되어 전체 파이프라인이 각 스테이지의 최장 잡의 합으로 결정된다.

DAG와 needs의 동작 방식

GitLab CI의 needs 키워드는 스테이지 순서 대신 잡 간 의존 관계를 직접 정의한다. 이렇게 하면 파이프라인이 방향성 비순환 그래프(DAG)로 재구성되고, 각 잡은 자신이 의존하는 잡만 끝나면 즉시 실행된다. 앞선 예에서 프런트엔드 테스트는 프런트엔드 빌드만 끝나면 바로 시작한다.

핵심은 스테이지 개념을 버리는 게 아니라, 잡의 실행 시점을 스테이지 경계가 아닌 실제 의존성이 결정하도록 바꾸는 것이다.

기본 예시: needs로 의존성 재구성

stages:
  - build
  - test
  - deploy

build-frontend:
  stage: build
  script: ./build-frontend.sh

build-backend:
  stage: build
  script: ./build-backend.sh

test-frontend:
  stage: test
  needs: ["build-frontend"]   # 백엔드 빌드를 기다리지 않음
  script: ./test-frontend.sh

test-backend:
  stage: test
  needs: ["build-backend"]
  script: ./test-backend.sh

deploy:
  stage: deploy
  needs: ["test-frontend", "test-backend"]
  script: ./deploy.sh

test-frontend는 build-frontend만 needs로 지정했으므로, build-backend가 아직 돌고 있어도 시작된다. deploy는 두 테스트가 모두 끝나야 실행되므로 안전성은 유지된다.

순차 vs DAG 실행 시간 비교

구성임계 경로전체 소요
순차 스테이지max(build) + max(test) + deploy8 + 5 + 1 = 14분
DAG (needs)느린 쪽 체인의 합8 + 3 + 1 = 12분

(가정: FE 빌드 2분/테스트 5분, BE 빌드 8분/테스트 3분, deploy 1분) 잡 시간 편차가 클수록 DAG의 이득은 커진다. 임계 경로가 곧 파이프라인 시간이 된다.

아티팩트 전달 최적화

needs는 기본적으로 지정한 잡의 아티팩트를 내려받는다. 큰 아티팩트를 불필요하게 전달하면 병렬화로 아낀 시간을 다운로드가 잡아먹는다. 특정 잡의 아티팩트만 받거나 아예 받지 않으려면 artifacts: false를 명시한다.

test-backend:
  stage: test
  needs:
    - job: build-backend
      artifacts: true
    - job: lint          # 순서 의존만 필요, 산출물은 불필요
      artifacts: false
  script: ./test-backend.sh

아티팩트를 받는 잡은 artifacts: 설정으로 필요한 경로만 paths에 담아 크기를 줄이는 것이 좋다.

실무에서 주의할 점

  • needs 누락은 조용한 버그다. 의존성을 빠뜨리면 잡이 필요한 아티팩트 없이 먼저 실행되어 간헐적으로 실패한다. 스테이지가 지켜주던 순서를 이제 직접 관리해야 한다.
  • needs 상한. 한 잡의 needs 개수에는 제한(플랜별로 다르며 기본 50개)이 있으므로, 팬인(fan-in)이 과도하면 중간 집계 잡을 둔다.
  • 모든 잡을 DAG로 바꿀 필요는 없다. 의존성 편차가 작으면 이득이 미미하고 설정 복잡도만 늘어난다. 임계 경로에 있는 병목부터 적용한다.
  • graph 뷰로 검증하라. 파이프라인의 Needs 탭에서 실제 그래프가 의도대로 그려졌는지 확인하면 순환/누락을 조기에 잡을 수 있다.

정리

DAG 최적화의 목표는 "잡이 실제로 필요한 것만 기다리게" 만드는 것이다. 스테이지 경계로 인한 인위적 대기를 제거하면 파이프라인 시간은 임계 경로로 수렴한다. 먼저 가장 오래 걸리는 체인을 찾고, 그 위의 불필요한 의존만 걷어내는 순서로 접근하면 설정 복잡도를 최소화하면서 효과를 극대화할 수 있다.