LabHub
배우기 러닝패스 코스

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

캐시에 넣어 둔 빌드 결과가 배포 잡에서 사라졌다

LabHub 에서 이어서 보기

목표

파이프라인을 여러 번 돌려 캐시가 맞고 빗나가고 무효화되는 것을 로그로 보고, 산출물의 제외·받는 쪽 제한·dotenv 값 전달을 확인한 뒤 산출물 점검 스크립트를 만듭니다.

왜 중요한가

산출물은 없으면 뒤 잡이 실패해야 맞고, 캐시는 없어도 모든 잡이 돌아야 맞습니다. 둘을 섞으면 캐시가 비는 날 배포 잡이 빈 디렉터리를 조용히 내보내거나, 만료 없는 산출물이 저장소 용량을 채웁니다. 캐시는 키를 무엇으로 만드느냐가 전부라서, 키를 고정 문자열로 두면 낡은 의존성을 끌고 다니고 소비자까지 올리게 두면 오염이 번집니다. 산출물은 '무엇이 올라갔나' 를 사람이 매번 확인할 수 없으니 점검을 자동화해 두는 편이 안전합니다.

단계

1. /root/glci-transfer 을 git 저장소로 만들고(.gitignore 에 .gitlab-ci-local/), .gitlab-ci.yml 에 stages [build, test, deploy] 와 잡 둘을 두세요. package(build)는 dist/app.tgzdist/app.js.map 을 만들고 artifacts 로 dist/ 를 올리되 dist/*.map 은 제외하고 expire_in: 1 week 를 둡니다. ship(deploy)은 test -f dist/app.tgz && echo has-tgz, test -e dist/app.js.map && echo has-map || echo no-map, test -d public && echo has-public || echo no-public 를 실행합니다. 실행하면 ship 로그가 has-tgz·no-map·no-public 이어야 합니다.
2. 잡 docs(build)를 더해 public/index.html 을 만들고 artifacts 로 public/(expire_in 2 days)을 올리세요. ship 에는 dependencies: [package] 를 두어 package 의 산출물만 받게 합니다. 실행하면 ship 로그가 여전히 has-tgz·no-map·no-public 이어야 합니다.
3. requirements.txtrequests==2.32.3 한 줄을 두고 커밋 대상에 넣으세요. 잡 deps(build)는 cache 를 key: files: [requirements.txt], paths: [.deps/], policy: pull-push 로 두고, mkdir -p .deps.deps/installed 가 있으면 cache-hit, 없으면 cache-miss 를 출력하고 그 파일을 만듭니다. 두 번 연속 실행하면 miss 다음 hit 이 나와야 합니다. 채점기는 사본에서 requirements.txt 를 바꿔 다시 miss 가 나는지도 봅니다.
4. 잡 둘을 더하세요. unit(test)은 deps 와 같은 키·경로의 cache 를 policy: pull 로 두고 .deps/installed 가 있으면 unit-hit, 없으면 unit-miss 를 출력한 뒤 .deps/junk 를 만듭니다. verify-cache(deploy)도 같은 캐시를 pull 로 받아 .deps/junk 가 있으면 junk-saved, 없으면 junk-not-saved 를 출력합니다. 실행하면 unit-hit 과 junk-not-saved 가 나와야 합니다.
5. deps 의 cache 를 목록 두 개로 바꾸세요. 첫째는 key: files: [requirements.txt]prefix: py 를 더한 .deps/(pull-push), 둘째는 key: tools-$CI_COMMIT_REF_SLUG.tools/ 입니다. deps 스크립트에 .tools/lint 가 있으면 tools-hit, 없으면 tools-miss 를 출력하고 만드는 줄을 더합니다. unit·verify-cache 의 키에도 같은 prefix 를 둡니다. 두 번 실행하면 둘째 실행에서 두 캐시가 모두 hit 이어야 합니다.
6. 잡 version(build)이 VERSION=1.4.2-${CI_COMMIT_SHORT_SHA} 한 줄을 build.env 에 쓰고 artifacts: reports: dotenv: build.env 로 올리게 하세요. 잡 announce(deploy)는 needs: [version] 으로 echo "version=$VERSION" 을 실행합니다. 실행하면 announce 로그가 version=1.4.2-<짧은 커밋 해시> 여야 합니다.
7. /root/glci-transfer/artifact-audit.sh <저장소> 를 만드세요. 저장소를 임시 사본으로 떠 모든 파일을 커밋하고 파이프라인을 돌린 뒤, 올라간 산출물(.gitlab-ci-local/artifacts 아래)에 *.map·*.env·*.pem 이나 1MiB 가 넘는 파일이 있으면 BAD <잡>/<경로> …(공백 구분, 정렬) 한 줄과 3, 없으면 OK 와 0, 파이프라인이 실패하면 ERROR 와 1 로 끝냅니다. 리포트(.gitlab-ci-reports/ 아래)는 점검에서 뺍니다. 원래 저장소에는 아무것도 남기지 않습니다. 채점기는 이 저장소(OK)와 산출물에 새는 파일을 넣은 사본으로 확인합니다.

참고

단계 7개

  1. 산출물은 필요한 것만 올린다
  2. 배포 잡은 쓰지도 않을 문서까지 받지 않는다
  3. 잠금 파일이 바뀌면 캐시도 바뀐다
  4. 소비자는 캐시를 받기만 한다
  5. 수명이 다른 캐시는 키를 나눈다
  6. 앞 잡이 계산한 값을 뒤 잡에 넘긴다
  7. 산출물에 들어가면 안 되는 파일을 잡아낸다