打了个 nightly 标签,结果发布了版本
한국어 원문으로 표시합니다.
목표
브랜치·태그·파일 존재·원격과의 변경에 따라 잡이 목록에 들어가고 빠지는 것을 상황을 바꿔 가며 확인하고, 규칙의 순서와 규칙이 정하는 변수로 배포 정책을 설정에 새깁니다.
왜 중요한가
rules 는 잡이 시작할 때 묻는 조건이 아니라 파이프라인이 만들어질 때 목록을 정하는 규칙입니다. 첫 매치만 적용되므로 항목의 순서가 곧 정책이고, 순서를 잘못 두면 오류 없이 배포가 사라지거나 엉뚱한 태그에 릴리스가 나갑니다. changes 는 무엇과 비교하느냐에 따라 결과가 바뀌고, 조건과 값(배포 대상)을 떨어뜨려 두면 둘이 어긋나는 날이 옵니다. 이런 차이는 설정을 읽는 것만으로는 잘 보이지 않아서 상황을 바꿔 실행해 봐야 합니다.
단계
/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 이 목록에서 사라지는지 봅니다.- 잡
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나 태그 없음이면 없어야 합니다. - 잡
publish(deploy,echo publish)의 rules 를 세 항목으로 두세요: 태그가 있으면when: on_success, main 브랜치면when: manual과allow_failure: false, 그 밖에는when: never. 커밋합니다. 목록에서 main 이면 manual(allowFailure false), 태그 변수가 있으면 on_success, feature 브랜치면 없어야 합니다. - 잡
docker-build(build,echo docker)를rules: - exists: [Dockerfile]로 더하고 커밋하세요. 이 저장소에는 아직 Dockerfile 을 만들지 않습니다. 채점기는 사본에 Dockerfile 을 넣었을 때만 잡이 생기는지 봅니다. /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 가 생기는지 봅니다.- 잡
deploy(deploy,echo "target=$DEPLOY_TARGET")를 더하세요. rules 는 태그면variables: {DEPLOY_TARGET: production}, main 이면variables: {DEPLOY_TARGET: staging}입니다. 커밋하고 push 합니다. main 에서 실행하면target=staging, 태그 변수를 주면target=production이 찍혀야 합니다. .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여야 합니다.
참고
- 이 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 의 차이(실측): git 태그를 CI_COMMIT_TAG 로 읽지 않아
--variable CI_COMMIT_TAG=...로 흉내 냅니다. rules:changes 는 origin 의 기본 브랜치와 비교하고 compare_to 는 무시합니다. workflow:rules 로 파이프라인을 만들지 않는 동작과 manual 잡이 뒤 스테이지를 막는 동작은 재현하지 않습니다. - 브랜치를 바꿔 볼 때는 사본이나 새 브랜치에서 하고, 채점 전에는 main 으로 돌아와 커밋해 두세요.
- Specify when jobs run with rules · workflow · Predefined CI/CD variables · CI/CD YAML syntax reference
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: manual 과 allow_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 서버에서만 확인할 수 있습니다.