LabHub

GitLab CI/CD · 실행 모델 — 순서·조건·전달 · 이론

rules 는 실행이 아니라 생성을 정한다

LabHub 에서 이어서 보기

한 줄 요약

rules 는 잡이 시작할 때 "돌까 말까"를 묻는 장치가 아니라, 파이프라인이 만들어지는 순간 "이 잡을 목록에 넣을까"를 결정하는 장치다.

왜 이게 필요했나

파이프라인 하나로 여러 상황을 감당해야 한다는 것이 문제의 출발점이다. 기능 브랜치에서는 테스트만 돌리고 싶고, 병합 요청에서는 거기에 보안 스캔을 더하고 싶고, 기본 브랜치에서는 스테이징까지 나가야 하고, 태그가 붙으면 운영 배포를 준비하되 사람이 버튼을 누르게 하고 싶다. 이 네 가지를 파일 네 개로 나누면 공통 부분이 네 벌로 갈라지고 곧 서로 달라진다.

예전 문법인 only/except 는 이 요구를 어중간하게 받아냈다. 조건을 나열할 수는 있었지만 조건마다 다른 동작(자동 실행, 수동 승인, 실패 허용)을 붙일 수 없었고, 두 키를 한 잡에 함께 쓸 수도 없었다. rules 는 조건과 동작을 한 항목에 묶어 이 한계를 걷어낸 문법이고, 지금은 새 설정에서 only/except 를 쓸 이유가 없다. 둘을 한 잡에 섞어 쓰면 GitLab 이 설정을 거부한다.

어떻게 동작하나

rules 는 항목의 목록이고, 위에서부터 읽다가 조건에 처음 걸리는 항목 하나만 적용한 뒤 멈춘다. 이 "첫 매치만"이라는 성질이 전부다. 그래서 조건 없는 항목은 항상 걸리고, 그 아래에 무엇을 적든 영영 읽히지 않는다. 조건 없는 when: never 를 목록 가운데 두면 그 뒤의 규칙이 통째로 죽는데, 이 사고는 아무 오류도 내지 않기 때문에 배포가 안 나가는 이유를 한참 못 찾게 만든다.

항목이 가질 수 있는 조건은 세 가지다. if 는 변수 표현식이고 $CI_COMMIT_BRANCH == "main" 처럼 쓴다. changes 는 이번 변경에 특정 경로가 포함됐는지를 본다. exists 는 저장소에 특정 파일이 있는지를 본다.

걸렸을 때의 동작은 when 이 정한다. on_success 는 앞이 다 성공했으면 자동으로, manual 은 잡을 만들되 사람이 눌러야 시작, always 는 앞이 실패해도, never 는 잡을 아예 만들지 않음이다. manual 과 함께 쓰는 allow_failure 는 의미가 헷갈리기 쉬운데, 이것이 false 여야 그 수동 잡이 진짜 승인 게이트가 된다. true 면 누르지 않아도 파이프라인이 성공으로 끝나 버린다.

여기서 다시 확인할 것은 평가 시점이다. rules 는 파이프라인을 만들 때 한 번 평가되고, 잡이 시작할 때 다시 보지 않는다. 그래서 앞 잡이 실행 중에 만든 값으로 뒤 잡의 실행 여부를 정할 수는 없다. 그런 조건 분기는 rules 가 아니라 잡 안의 script 에서 처리해야 한다.

현장에서 만나는 모습

가장 흔한 증상은 커밋 하나에 파이프라인이 두 개 생기는 것이다. 브랜치 파이프라인과 병합 요청 파이프라인이 같은 조건에 둘 다 걸려서인데, 러너 자원을 두 배로 먹고 상태 표시도 두 개가 된다. 해결은 잡마다 조건을 덧붙이는 것이 아니라 workflow:rules 로 파이프라인 자체를 하나만 만들게 막는 것이다.

두 번째로 흔한 것은 운영 배포 잡을 when: manual 로 걸어 두고 allow_failure 를 기본값에 맡기는 것이다. 승인 게이트라고 믿고 있었는데 아무도 누르지 않은 파이프라인이 초록색으로 끝나 있는 장면을 언젠가 보게 된다.

이어서 볼 것

잡과 잡 사이로 파일을 건네는 artifacts, 그리고 실행과 실행 사이로 시간을 아끼는 cache 를 본다. 이름이 비슷해 자주 섞이지만 완전히 다른 물건이다.