LabHub
学习 学习路径 课程

GitLab CI/CD

打了个 nightly 标签,结果发布了版本

在 LabHub 中继续学习

한국어 원문으로 표시합니다.

목표

브랜치·태그·파일 존재·원격과의 변경에 따라 잡이 목록에 들어가고 빠지는 것을 상황을 바꿔 가며 확인하고, 규칙의 순서와 규칙이 정하는 변수로 배포 정책을 설정에 새깁니다.

왜 중요한가

rules 는 잡이 시작할 때 묻는 조건이 아니라 파이프라인이 만들어질 때 목록을 정하는 규칙입니다. 첫 매치만 적용되므로 항목의 순서가 곧 정책이고, 순서를 잘못 두면 오류 없이 배포가 사라지거나 엉뚱한 태그에 릴리스가 나갑니다. changes 는 무엇과 비교하느냐에 따라 결과가 바뀌고, 조건과 값(배포 대상)을 떨어뜨려 두면 둘이 어긋나는 날이 옵니다. 이런 차이는 설정을 읽는 것만으로는 잘 보이지 않아서 상황을 바꿔 실행해 봐야 합니다.

단계

  1. /root/glci-rules 을 git 저장소로 만들고 .gitignore.gitlab-ci-local/ 를 두세요. .gitlab-ci.yml 에 stages [build, deploy], 조건 없는 잡 unit(build, echo "unit log=$LOG_LEVEL"), 그리고 $CI_COMMIT_BRANCH == "main" 일 때만 만들어지는 deploy-staging(deploy, echo staging)을 두고 main 브랜치에 커밋하세요. 채점기는 사본에서 feature/login 브랜치로 옮겨 deploy-staging 이 목록에서 사라지는지 봅니다.
  2. release-notes(deploy, echo notes)를 $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/ 일 때만 만들어지게 더하고 커밋하세요. gitlab-ci-local 은 git 태그를 읽지 않으므로 --variable CI_COMMIT_TAG=v1.2.0 으로 태그 파이프라인을 흉내 냅니다. v1.2.0 이면 목록에 있고, nightly 나 태그 없음이면 없어야 합니다.
  3. publish(deploy, echo publish)의 rules 를 세 항목으로 두세요: 태그가 있으면 when: on_success, main 브랜치면 when: manualallow_failure: false, 그 밖에는 when: never. 커밋합니다. 목록에서 main 이면 manual(allowFailure false), 태그 변수가 있으면 on_success, feature 브랜치면 없어야 합니다.
  4. docker-build(build, echo docker)를 rules: - exists: [Dockerfile] 로 더하고 커밋하세요. 이 저장소에는 아직 Dockerfile 을 만들지 않습니다. 채점기는 사본에 Dockerfile 을 넣었을 때만 잡이 생기는지 봅니다.
  5. /root/glci-rules-origin.git 에 bare 저장소를 만들어 origin 으로 등록하고 main 을 push 한 뒤 git remote set-head origin main 을 실행하세요. 그다음 잡 docs-build(build, echo docs)를 rules: - changes: ["docs/**/*"] 로 더해 커밋하고 다시 push 합니다. 채점기는 사본에서 docs 아래를 고친 브랜치와 다른 파일만 고친 브랜치를 만들어, 앞의 경우에만 docs-build 가 생기는지 봅니다.
  6. deploy(deploy, echo "target=$DEPLOY_TARGET")를 더하세요. rules 는 태그면 variables: {DEPLOY_TARGET: production}, main 이면 variables: {DEPLOY_TARGET: staging} 입니다. 커밋하고 push 합니다. main 에서 실행하면 target=staging, 태그 변수를 주면 target=production 이 찍혀야 합니다.
  7. .gitlab-ci.yml 맨 위에 workflow: rules: 를 두세요. main 이면 variables: {LOG_LEVEL: warn}, 그 밖에는(when: always) variables: {LOG_LEVEL: debug} 입니다. 커밋하고 push 합니다. main 에서 unit 로그는 unit log=warn, feature 브랜치에서는 unit log=debug 여야 합니다.

참고

main 에서만 스테이징 배포를 만든다

/root/glci-rules 을 git 저장소로 만들고 .gitignore.gitlab-ci-local/ 를 두세요. .gitlab-ci.yml 에 stages [build, deploy], 조건 없는 잡 unit(build, echo "unit log=$LOG_LEVEL"), 그리고 $CI_COMMIT_BRANCH == "main" 일 때만 만들어지는 deploy-staging(deploy, echo staging)을 두고 main 브랜치에 커밋하세요. 채점기는 사본에서 feature/login 브랜치로 옮겨 deploy-staging 이 목록에서 사라지는지 봅니다.

rules 는 파이프라인을 만들 때 평가됩니다. 조건이 하나도 맞지 않으면 그 잡은 'never' 로 목록에서 빠집니다. 브랜치를 바꿔 gitlab-ci-local --list-csv-all 로 when 칸을 비교해 보세요.

태그 이름의 모양까지 보고 릴리스 노트를 만든다

release-notes(deploy, echo notes)를 $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/ 일 때만 만들어지게 더하고 커밋하세요. gitlab-ci-local 은 git 태그를 읽지 않으므로 --variable CI_COMMIT_TAG=v1.2.0 으로 태그 파이프라인을 흉내 냅니다. v1.2.0 이면 목록에 있고, nightly 나 태그 없음이면 없어야 합니다.

=~ 는 정규식 비교입니다. 태그 변수는 태그 파이프라인에서만 채워지므로 그 존재만 보면 nightly 같은 임시 태그에도 릴리스가 나갑니다. 정규식은 슬래시로 감쌉니다.

첫 매치만 적용된다 — 순서가 곧 정책이다

publish(deploy, echo publish)의 rules 를 세 항목으로 두세요: 태그가 있으면 when: on_success, main 브랜치면 when: manualallow_failure: false, 그 밖에는 when: never. 커밋합니다. 목록에서 main 이면 manual(allowFailure false), 태그 변수가 있으면 on_success, feature 브랜치면 없어야 합니다.

위에서부터 읽다가 처음 맞는 항목 하나만 씁니다. 조건 없는 when: never 를 가운데에 두면 그 아래 항목은 영영 읽히지 않고, 아무 오류도 나지 않습니다. manual 잡을 진짜 승인 게이트로 쓰려면 allow_failure: false 를 함께 둡니다.

Dockerfile 이 있는 저장소에서만 이미지를 굽는다

docker-build(build, echo docker)를 rules: - exists: [Dockerfile] 로 더하고 커밋하세요. 이 저장소에는 아직 Dockerfile 을 만들지 않습니다. 채점기는 사본에 Dockerfile 을 넣었을 때만 잡이 생기는지 봅니다.

exists 는 저장소에 그 경로의 파일이 있는지를 봅니다. 여러 저장소가 같은 템플릿을 include 할 때, 저장소마다 설정을 고치지 않고 해당하는 잡만 켜는 데 씁니다.

문서가 바뀐 브랜치에서만 문서를 빌드한다

/root/glci-rules-origin.git 에 bare 저장소를 만들어 origin 으로 등록하고 main 을 push 한 뒤 git remote set-head origin main 을 실행하세요. 그다음 잡 docs-build(build, echo docs)를 rules: - changes: ["docs/**/*"] 로 더해 커밋하고 다시 push 합니다. 채점기는 사본에서 docs 아래를 고친 브랜치와 다른 파일만 고친 브랜치를 만들어, 앞의 경우에만 docs-build 가 생기는지 봅니다.

changes 는 '무엇과 비교한 변경인가' 가 핵심입니다. gitlab-ci-local 은 원격 기본 브랜치(origin/main)와 비교하므로 원격이 있어야 합니다. GitLab 의 브랜치 파이프라인은 직전 push 와, 병합 요청 파이프라인은 대상 브랜치와 비교합니다.

어느 규칙에 걸렸는지가 배포 대상을 정한다

deploy(deploy, echo "target=$DEPLOY_TARGET")를 더하세요. rules 는 태그면 variables: {DEPLOY_TARGET: production}, main 이면 variables: {DEPLOY_TARGET: staging} 입니다. 커밋하고 push 합니다. main 에서 실행하면 target=staging, 태그 변수를 주면 target=production 이 찍혀야 합니다.

rules 항목의 variables 는 그 항목에 걸렸을 때만 잡에 들어갑니다. 조건과 값을 한곳에 두면 '태그인데 staging 으로 나갔다' 같은 불일치가 구조적으로 사라집니다.

파이프라인 전체의 값은 workflow 에서 정한다

.gitlab-ci.yml 맨 위에 workflow: rules: 를 두세요. main 이면 variables: {LOG_LEVEL: warn}, 그 밖에는(when: always) variables: {LOG_LEVEL: debug} 입니다. 커밋하고 push 합니다. main 에서 unit 로그는 unit log=warn, feature 브랜치에서는 unit log=debug 여야 합니다.

workflow:rules 는 파이프라인을 만들지 말지와 파이프라인 전체에 들어갈 변수를 정합니다. 잡마다 같은 조건을 반복하지 않아도 됩니다. 병합 요청과 브랜치 파이프라인이 겹치는 것을 막는 곳도 여기지만, 그 동작은 GitLab 서버에서만 확인할 수 있습니다.