LabHub

GitLab CI/CD · 현장에서의 파이프라인 · 이론

러너가 실제로 하는 일

LabHub 에서 이어서 보기

한 줄 요약

GitLab 은 설정을 읽어 잡 목록을 만들 뿐이고, 그 잡을 실제로 실행하는 것은 별도의 프로세스인 러너다. 그래서 러너가 없으면 파이프라인은 오류 없이 영원히 대기 상태로 남는다.

왜 이게 필요했나

파이프라인을 처음 다루는 사람이 가장 자주 겪는 막힘은 문법 오류가 아니라 "잡이 만들어졌는데 시작하지 않는" 상황이다. 화면에는 빨간 오류가 없고, 잡은 pending 이라고만 적혀 있다. 이 상태는 설정이 잘못된 것이 아니라 그 잡을 가져갈 러너가 없다는 뜻인데, 서버와 실행자가 분리된 구조를 모르면 설정 파일만 계속 들여다보게 된다.

분리 자체는 의도된 설계다. 빌드는 무겁고 위험하다. 임의의 코드를 실행하고, 디스크를 채우고, 네트워크로 나간다. 그런 일을 서버와 같은 프로세스에서 하면 서버가 함께 죽는다. 실행을 밖으로 빼면 러너를 필요한 만큼 늘릴 수 있고, 팀마다 다른 환경을 줄 수 있고, 러너 하나가 망가져도 GitLab 은 멀쩡하다.

어떻게 동작하나

러너는 GitLab 에 등록된 뒤 주기적으로 "내가 가져갈 잡이 있느냐"고 물어본다. 서버가 밀어 주는 것이 아니라 러너가 당겨 가는 구조라서, 러너가 방화벽 안에 있어도 인바운드 포트를 열 필요가 없다.

무엇을 가져갈지는 태그가 정한다. 잡에 tags 를 적으면 그 태그를 가진 러너만 그 잡을 집어 간다. 태그가 필요한 잡에 태그를 안 적거나, 그 태그를 가진 러너가 하나도 없으면 잡은 계속 대기한다. 이것이 앞서 말한 pending 의 대표적인 원인이다.

집어 간 뒤의 실행 방식은 executor 가 정한다. shell 은 러너가 깔린 기계에서 그대로 실행하고, docker 는 잡마다 컨테이너를 새로 띄우고, kubernetes 는 잡마다 파드를 만든다. 뒤의 둘은 매번 깨끗한 환경을 주기 때문에 재현성이 좋지만, 그만큼 잡 사이에 아무것도 남지 않는다. 앞에서 배운 artifactscache 가 필요한 이유가 바로 이것이다 — 격리를 유지하면서도 필요한 것만 골라 건네려는 장치다.

실행 중에는 GitLab 이 CI_ 로 시작하는 변수를 잔뜩 넣어 준다. CI_COMMIT_BRANCH, CI_COMMIT_SHA, CI_PIPELINE_ID, CI_JOB_ID 같은 것들이다. rules 의 조건도 이 변수로 쓰고, 아티팩트 이름이나 이미지 태그도 이 변수로 만든다. 커밋 SHA 를 이미지 태그에 넣는 습관이 여기서 나온다.

현장에서 만나는 모습

러너 운영에서 가장 자주 다투는 숫자는 동시 실행 수다. 너무 낮으면 잡이 줄을 서고, 너무 높으면 기계가 스왑을 시작해 모든 잡이 함께 느려진다. 그리고 느려진 파이프라인은 재시도를 부르고, 재시도는 다시 부하를 만든다.

또 하나는 공유 러너와 전용 러너의 경계다. 아무나 쓰는 공유 러너에서 배포 잡을 돌리면, 그 러너를 쓰는 다른 프로젝트가 배포 자격 증명이 지나간 자리를 볼 가능성이 생긴다. 그래서 배포 잡은 보호 브랜치 전용 러너로 분리하는 것이 기본이다.

덧붙여, 이 실습 환경에는 러너가 없다. 그래서 이 코스는 잡이 도는 장면 대신 잡이 어떻게 만들어지고 어떤 순서로 줄 서는지를 다룬다. 러너가 생겼을 때 달라지는 것은 실행뿐이고, 지금 배우는 모델은 그대로 쓰인다.

이어서 볼 것

파이프라인이 사고를 내는 자리를 본다. 비밀 값이 새는 경로, 남의 설정을 끌어다 쓸 때의 위험, 그리고 배포를 되돌릴 수 있게 만드는 최소 장치를 다룬다.