GitLab CI/CD · 실행 모델 — 순서·조건·전달 · 실습
e2e 하나가 느려서 문서 게시가 8초씩 기다렸다
목표
느린 잡이 섞인 파이프라인을 실제로 돌려 스테이지와 needs 가 잡의 출발 시각을 어떻게 바꾸는지 재고, 산출물 전달·조건부 잡 기다리기·실패 허용 방식을 실행 결과로 확인합니다.
왜 중요한가
스테이지 방식은 이해하기 쉽지만 가장 느린 잡이 모든 뒤 잡의 출발을 붙잡습니다. needs 로 필요한 것만 기다리게 하면 파이프라인이 빨라지는 대신, 무엇을 기다리고 무엇을 받는지를 잡마다 정확히 적어야 합니다. rules 로 빠질 수 있는 잡을 기다리면 파이프라인이 아예 안 만들어지고, 실패를 너무 넓게 허용하면 진짜 사고가 초록색으로 지나갑니다. 이 선택들은 문서를 읽을 때보다 시각과 결과를 볼 때 분명해집니다.
단계
1. /root/glci-dag 을 git 저장소로 만들고 .gitlab-ci.yml 에 stages [build, test, deploy] 와 잡 넷을 두세요: compile(build, sleep 3 뒤 bin/app 파일을 만들고 artifacts 로 bin/ 을 올림), unit(test, test -f bin/app 뒤 echo unit-ok), e2e(test, sleep 8 뒤 echo e2e-ok), publish-docs(deploy, test -f bin/app 뒤 echo docs-published). gitlab-ci-local --shell-isolation --no-artifacts-to-source --timestamps 로 실행해 publish-docs 가 느린 e2e 가 끝난 뒤에야 시작하는 것을 보세요.
2. publish-docs 에 needs: [compile] 을 더하세요. 실행하면 publish-docs 가 e2e 가 끝나기 전에 시작하고, compile 의 산출물(bin/app)은 여전히 받아야 합니다.
3. 잡 lint(stage test, sleep 1 뒤 echo lint-ok)를 needs: [] 로 더하세요. 실행하면 lint 가 compile 이 끝나기 전에 시작해야 합니다.
4. 잡 audit(stage test)를 needs 긴 형태로 job: compile, artifacts: false 로 두고 script 를 test ! -e bin/app && echo no-artifact 로 하세요. 실행하면 audit 는 성공하고(bin/app 이 없음), unit 은 여전히 bin/app 을 받아야 합니다.
5. 잡 integration(stage test)은 $RUN_INTEGRATION == "yes" 일 때만 만들어지게 rules 를 두고 sleep 2 뒤 echo integration-ok 를 실행합니다. 잡 release(stage deploy)는 needs 에 unit 과 job: integration, optional: true 를 두고 echo release 를 실행합니다. 변수 없이 실행하면 integration 없이 release 가 돌고, --variable RUN_INTEGRATION=yes 로 실행하면 integration 이 끝난 뒤 release 가 시작해야 합니다.
6. 잡 셋을 더하세요. flaky(test)는 echo flaky-run 뒤 exit 1 하지만 allow_failure: true 입니다. cleanup(deploy)은 when: always 로 echo cleanup, notify-failure(deploy)는 when: on_failure 로 echo notify 를 실행합니다. 실행하면 flaky 는 경고로 끝나고 파이프라인은 성공하며 cleanup 은 돌고 notify-failure 는 돌지 않아야 합니다. 채점기는 사본에서 flaky 의 allow_failure 를 끈 뒤에도 돌려 봅니다.
7. 잡 check-config 를 stage .pre 에 더하세요(stages 목록에는 적지 않음). sleep 2 뒤 test ! -e STOP 으로 저장소에 STOP 파일이 있으면 실패하고, 없으면 echo config-ok 를 실행합니다. 실행하면 check-config 가 끝난 뒤에 compile 이 시작해야 합니다. 채점기는 사본에 STOP 파일을 넣어, 사전 검사가 실패하면 compile 이 아예 돌지 않는지도 확인합니다.
참고
- 이 VM 에는 GitLab 서버와 러너가 없고, gitlab-ci-local 4.75.1 이 .gitlab-ci.yml 을 GitLab 과 같은 규칙으로 해석해 shell 로 잡을 실행합니다.
image:를 적으면 도커로 돌리려 하므로 쓰지 않습니다. 보호 변수·마스킹·CI_JOB_TOKEN·러너 태그·병합 요청 파이프라인 생성은 서버 기능이라 여기서 재현되지 않습니다. - 실행: 저장소 루트에서
gitlab-ci-local --shell-isolation --no-artifacts-to-source(잡마다 따로 된 작업 디렉터리, 산출물을 저장소에 되쓰지 않음), 잡 목록:gitlab-ci-local --list-csv-all, 해석된 설정:gitlab-ci-local --preview. gitlab-ci-local 은 git 이 추적하는 파일만 잡에 넘기므로 파일을 만들면git add하세요. 채점기는 저장소를 사본으로 떠 모든 파일을 커밋한 뒤 같은 도구로 다시 돌립니다. - gitlab-ci-local 은 needs 로 가리킨 잡이 같은 스테이지나 아직 끝나지 않은 스테이지에 있으면 그 스테이지가 끝날 때까지 기다립니다(실측). GitLab 은 가리킨 잡만 기다리므로 실제 서버에서는 더 빨리 출발합니다. 이 실습의 시각 비교는 두 도구의 결과가 같은 경우만 씁니다.
- gitlab-ci-local 은 rules 로 빠진 잡을 optional 없이 needs 에 적어도 거부하지 않습니다. GitLab 은 그 경우 파이프라인을 만들지 않고 오류를 냅니다.
- gitlab-ci-local 4.75.1 은 retry·timeout·allow_failure:exit_codes·.post 스테이지를 GitLab 과 다르게 처리합니다(실측: 재시도하지 않고, 시간 제한을 넘겨도 계속 돌고, 허용하지 않은 종료 코드로 실패해도 뒤 스테이지를 진행하고, .post 잡은 목록에만 있고 실행하지 않음). 그래서 이 실습에서는 다루지 않습니다.
- [needs](https://docs.gitlab.com/ci/yaml/needs/) · [CI/CD YAML syntax reference(allow_failure·when)](https://docs.gitlab.com/ci/yaml/) · [Job artifacts](https://docs.gitlab.com/ci/jobs/job_artifacts/) · [Pipeline efficiency](https://docs.gitlab.com/ci/pipelines/pipeline_efficiency/)
단계 7개
- 스테이지는 앞 스테이지 전부를 기다린다
- 문서 게시는 컴파일만 기다리면 된다
- needs: [] 는 파이프라인이 시작하자마자 출발한다
- 순서는 기다리되 산출물은 받지 않는다
- 있을 수도 없을 수도 있는 잡을 기다린다
- 실패를 허용할 잡, 실패해도 도는 잡, 실패해야 도는 잡
- 모든 스테이지보다 먼저 도는 사전 검사